1. 介绍
CSS的绘画阶段负责根据盒子的大小(由布局阶段生成)和计算样式绘制盒子的背景、内容和高亮部分。
本规范描述了一个API,允许开发人员通过额外的<image>函数 来响应大小/计算样式的变化以绘制盒子的部分内容。
注意:在未来的规范版本中,可能会增加支持定义盒子部分(例如背景层)的裁剪、全局透明度和滤镜功能。
2. 绘画 Worklet
仅在一个现有引擎中可用。
Opera52+Edge79+
Edge (旧版)无IE无
Firefox for Android无iOS Safari无Chrome for Android65+Android WebView65+Samsung Internet9.0+Opera Mobile47+
paintWorklet
属性允许访问负责所有与绘画相关类的Worklet
。
paintWorklet
的Worklet全局作用域类型是PaintWorkletGlobalScope
。
paintWorklet
的Worklet目标类型是"paintworklet"
。
partial namespace CSS { [SameObject ]readonly attribute Worklet ; };
paintWorklet
PaintWorkletGlobalScope
是paintWorklet
的全局执行上下文。
仅在一个现有引擎中可用。
Opera?Edge79+
Edge (旧版)无IE无
Firefox for Android无iOS Safari无Chrome for Android65+Android WebView65+Samsung Internet9.0+Opera Mobile?
PaintWorkletGlobalScope
有一个与 Window.devicePixelRatio
属性相同的devicePixelRatio
属性。
仅在一个现有引擎中可用。
Opera?Edge79+
Edge (旧版)无IE无
Firefox for Android无iOS Safari无Chrome for Android65+Android WebView65+Samsung Internet9.0+Opera Mobile?
[Global =(Worklet ,PaintWorklet ),Exposed =PaintWorklet ]interface :
PaintWorkletGlobalScope WorkletGlobalScope {undefined registerPaint (DOMString ,
name VoidFunction );
paintCtor readonly attribute unrestricted double ; };
devicePixelRatio
PaintRenderingContext2DSettings
包含与绘画画布相关的渲染上下文的设置。PaintRenderingContext2DSettings
提供了画布渲染上下文2D设置的支持子集。将来,它可能会扩展以支持绘画画布中的颜色管理。
dictionary {
PaintRenderingContext2DSettings boolean =
alpha true ; };
class MyPaint{ static get inputProperties() { return [ '--foo' ]; } static get inputArguments() { return [ '<color>' ]; } static get contextOptions() { return { alpha: true }; } paint( ctx, size, styleMap) { // 在此编写绘画代码。 } }
3. 概念
绘画定义是一个
结构体,用于描述
PaintWorkletGlobalScope
所需的有关作者定义的<image>的
信息(可以通过<paint()>函数引用)。它包括以下内容:
文档绘画定义是一个 结构体,用于描述 文档所需的有关作者定义的<image>函数的信息(可以通过绘画函数引用)。它包括以下内容:
4. 注册自定义绘画
文档包含一个文档绘画定义的映射。最初
该映射为空;当调用registerPaint(name, paintCtor)
时会填充该映射。
PaintWorkletGlobalScope
包含一个绘画定义的映射。最初该映射为空;当调用registerPaint(name, paintCtor)
时会填充该映射。
PaintWorkletGlobalScope
包含一个绘画类实例的映射。最初该映射为空;当用户代理调用绘制绘画图像时会填充该映射。
用户代理可以随时处置并从映射中删除绘画类实例映射中的实例。当某个<paint()>函数不再被使用时, 或者用户代理需要回收内存时,可以执行此操作。
仅在一个现有引擎中可用。
Opera?Edge79+
Edge (旧版)无IE无
Firefox for Android无iOS Safari无Chrome for Android65+Android WebView65+Samsung Internet9.0+Opera Mobile?
registerPaint(name, paintCtor)
方法时,用户代理必须运行以下步骤:
-
令paintDefinitionMap为
PaintWorkletGlobalScope
的 绘画定义映射。 -
如果paintDefinitionMap[name] 存在,抛出一个"
InvalidModificationError
"DOMException
并中止所有这些步骤。 -
令inputProperties为空的
sequence<DOMString>
。 -
令inputPropertiesIterable为paintCtor的Get(paintCtor, "inputProperties")的结果。
-
如果inputPropertiesIterable不是undefined,则将inputProperties设置为将 inputPropertiesIterable转换为
sequence<DOMString>
的结果。 如果抛出异常,重新抛出异常并中止所有这些步骤。
注意:输入属性getter提供的CSS属性列表可以是自定义属性或原生CSS属性。
注意:CSS属性列表可能包含简写形式。
注意:为了使绘画图像类具有向前兼容性,CSS属性列表还可以包含当前对用户代理无效的属性。例如
margin-bikeshed-property
。
-
令inputArguments为空的
sequence<DOMString>
。 -
令inputArgumentsIterable为paintCtor的Get(paintCtor, "inputArguments")的结果。
-
如果inputArgumentsIterable不是undefined,则将inputArguments设置为 将inputArgumentsIterable转换为
sequence<DOMString>
的结果。 如果抛出异常,重新抛出异常并中止所有这些步骤。 -
对于inputArguments中的每个item,执行以下子步骤:
-
令contextOptionsValue为paintCtor的Get("contextOptions")的结果。
-
将contextOptionsValue转换为
PaintRenderingContext2DSettings
的结果。 如果抛出异常,重新抛出异常并中止所有这些步骤。注意:将
paintRenderingContext2DSettings.alpha
设置为false
允许用户代理 除了进行"可见性"优化外,还可以对文本进行抗锯齿处理,例如,当绘画图像不透明时,不会在绘画图像后面绘制图像。 -
如果IsConstructor(paintCtor)的结果为false,抛出TypeError并中止 所有这些步骤。
-
令prototype为paintCtor的Get("prototype")的结果。
-
令paintValue为prototype的Get("paint")的结果。
-
令definition为一个新的绘画定义,包括以下内容:
-
类构造函数为 paintCtor。
-
绘画函数为 paint。
-
构造函数有效标志 为true。
-
输入属性为 inputProperties。
-
PaintRenderingContext2DSettings 对象为paintRenderingContext2DSettings。
-
-
将paintDefinitionMap[name]设置为 definition。
-
排队任务以运行以下步骤:
-
令documentDefinition为一个新的文档 绘画定义,包括以下内容:
-
输入属性 为inputProperties。
-
输入参数语法 为inputArgumentSyntaxes。
-
PaintRenderingContext2DSettings 对象为paintRenderingContext2DSettings。
-
-
如果documentPaintDefinitionMap[name] 存在,执行以下步骤:
-
令existingDocumentDefinition为 documentPaintDefinitionMap[name]的get结果。
-
如果existingDocumentDefinition为
"invalid"
,中止所有这些步骤。 -
如果existingDocumentDefinition和documentDefinition不相等 (即输入属性、 输入参数语法和 PaintRenderingContext2DSettings 对象不同),则:
将 documentPaintDefinitionMap[name]设置为
"invalid"
。向调试控制台记录错误,指出相同类已使用不同的
inputProperties
、inputArguments
或paintRenderingContext2DSettings
注册。
-
-
否则,将documentPaintDefinitionMap[name] 设置为documentDefinition。
注意:输入属性列表应该只查找一次,类没有机会动态更改其输入属性。
注意:在未来的规范版本中,作者可以有机会接收不同类型的RenderingContext。
特别是作者可能希望使用WebGL渲染上下文来渲染3D效果。
设置WebGL渲染上下文以将PaintSize
和StylePropertyMap
作为输入是很复杂的。
5. 绘画符号
仅在一个现有引擎中可用。
Opera52+Edge79+
Edge (旧版)无IE无
Firefox for Android无iOS Safari无Chrome for Android65+Android WebView65+Samsung Internet9.2+Opera Mobile47+
paint() = paint( <ident>, <declaration-value>? )
<paint()>函数是对<image>类型的额外支持符号。
< style > . logo { background-image : paint ( company -logo ); } . chat-bubble { background-image : paint ( chat -bubble , blue ); } </ style >
对于光标属性,<paint()>函数应被视为无效图像,并回退到下一个支持的<image>。
在计算值时间,<paint()>函数
不需要匹配由registerPaint()
注册的语法。
相反,当在绘制绘画图像时进行解析时,这将导致一个无效图像。
6. 2D 渲染上下文
[Exposed =PaintWorklet ]interface { };
PaintRenderingContext2D PaintRenderingContext2D includes CanvasState ;PaintRenderingContext2D includes CanvasTransform ;PaintRenderingContext2D includes CanvasCompositing ;PaintRenderingContext2D includes CanvasImageSmoothing ;PaintRenderingContext2D includes CanvasFillStrokeStyles ;PaintRenderingContext2D includes CanvasShadowStyles ;PaintRenderingContext2D includes CanvasRect ;PaintRenderingContext2D includes CanvasDrawPath ;PaintRenderingContext2D includes CanvasDrawImage ;PaintRenderingContext2D includes CanvasPathDrawingStyles ;PaintRenderingContext2D includes CanvasPath ;
注意:PaintRenderingContext2D
实现了 CanvasRenderingContext2D
API 的一个子集。
它特别没有实现 CanvasImageData
、
CanvasUserInterface
、
CanvasText
,
或者CanvasTextDrawingStyles
API。
PaintRenderingContext2D
对象有一个输出位图。
它在对象创建时被初始化。
输出位图的大小是它所渲染对象的具体对象大小。
PaintRenderingContext2D
对象还具有一个alpha标志,
该标志可以设置为 true 或 false。
在创建上下文时,最初必须将其 alpha 标志设置为 true。
当 PaintRenderingContext2D
对象的 alpha 标志设置为 false 时,
它的 alpha 通道必须对所有像素固定为 1.0(完全不透明),并且尝试更改任何像素的 alpha 分量的操作必须被静默忽略。
输出位图的大小不一定代表用户代理在内部或渲染过程中使用的实际位图大小。 例如,如果视觉视口被缩放,用户代理可能会在内部使用与坐标空间中的设备像素数量相对应的位图,以便生成高质量的渲染。
此外,用户代理可能会记录已应用于 输出位图的绘制操作顺序, 以便用户代理随后可以在设备位图上以正确的分辨率进行绘制。 这也允许用户代理在视觉视口缩放时重复使用相同的 输出位图。
在"currentColor"
用作PaintRenderingContext2D
API 中的颜色时,它被视为不透明的黑色。
registerPaint( 'currentcolor' , class { paint( ctx, size) { ctx. fillStyle= 'currentColor' ; ctx. fillRect( 0 , 0 , size. width, size. height); } });
-
创建一个新的
PaintRenderingContext2D
。 -
将
PaintRenderingContext2D
的 alpha 标志设置为 paintRenderingContext2DSettings 的alpha
。 -
返回新的
PaintRenderingContext2D
。
注意: 渲染上下文的初始状态在 设置位图尺寸算法中设置, 因为它调用了 重置渲染上下文为默认状态,并清除了 输出位图。
6.1. 绘制 CSSImageValue
CanvasImageSource
typedef 被扩展以包括 CSSImageValue
类型,用作图像源。
对于使用 CanvasDrawImage
混入的接口:
-
当
CanvasImageSource
对象表示一个CSSImageValue
, 应该将调用该值的底层图像算法的结果用作drawImage
的源图像。
注意: 这部分内容应最终移动到 HTML 规范的 canvas 部分。 请参阅 问题 819。
7. 绘制图像
如果 <paint()> 函数生成的图像处于视觉视口内,用户代理必须显示由调用绘制绘画图像算法生成的图像输出。
注意: 用户代理不必每帧都为处于视觉视口内的 <paint()> 函数运行 绘制绘画图像。它可以缓存结果(可能使用额外的失效步骤)来显示正确的图像输出。
注意: 用户代理可以选择延迟绘制视觉视口外的图像。
requestAnimationFrame
内更新了样式,例如:
requestAnimationFrame( function () { element. styleMap. set( '--custom-prop-invalidates-paint' , 42 ); });
如果 element
处于视觉视口内,用户代理必须绘制绘画图像并显示当前帧的结果。
绘制绘画图像函数由用户代理在对象尺寸协商算法期间调用,该算法负责渲染<image>,snappedConcreteObjectSize 定义如下。令 concreteObjectSize 为具体对象大小。snappedConcreteObjectSize 通常与 concreteObjectSize 相同。但是,用户代理可以调整大小以便在像素边界上绘制。如果调整,用户代理应通过比例变化调整 snappedConcreteObjectSize,以便 <paint()> 函数可以相应地调整绘图。
注意: 在未来的规范版本中,作者可以指定绘画图像的自然尺寸。这可能作为回调来暴露,允许作者定义静态自然尺寸,或者根据计算样式和大小变化动态更新自然尺寸。
PaintSize
对象表示作者应该绘制的图像的大小。这个大小是用户代理给出的 snappedConcreteObjectSize。
注意: 请参阅CSS Images 3 § 4.4 CSS 对象大小的示例,了解如何计算具体对象大小。
绘制绘画图像函数可以在任何时候由用户代理推测调用,使用任何snappedConcreteObjectSize。生成的图像不会显示。
注意: 用户代理可以使用任何启发式方法来推测 snappedConcreteObjectSize 的可能未来值,例如推测大小保持不变。
注意: 虽然图像不会显示,但它仍然可以被缓存,后续的<paint()>的调用可以使用缓存的图像。
[Exposed =PaintWorklet ]interface {
PaintSize readonly attribute double ;
width readonly attribute double ; };
height
-
让 paintFunction 成为用户代理想要绘制的 box 上的 <paint()> 函数。
-
让 name 成为 paintFunction 的第一个参数。
-
让 documentPaintDefinitionMap 成为相关文档的 文档绘制定义 映射。
-
如果 documentPaintDefinitionMap[name] 不存在,则图像输出为 无效图像,并中止所有步骤。
-
让 documentDefinition 成为从 documentPaintDefinitionMap[name] 获取的结果。
-
如果 documentDefinition 是
"invalid"
,则图像输出为 无效图像,并中止所有步骤。 -
让 inputArgumentSyntaxes 成为 documentDefinition 的输入参数语法。
-
让 inputArguments 成为 paintFunction 的所有参数的列表,排除“绘制名称”参数。
-
如果 inputArguments 不符合 inputArgumentSyntaxes 提供的已注册语法,则图像输出为 无效图像,并中止所有步骤。
该步骤可能在以下情况下失败:// paint.js registerPaint( 'failing-argument-syntax' , class { static get inputArguments() { return [ '<length>' ]; } paint( ctx, size, styleMap, args) { /* paint code here. */ } }); < style > . example-1 { background-image : paint ( failing -argument-syntax , red ); } . example-2 { background-image : paint ( failing -argument-syntax , 1 px , 2 px ); } </ style > < div class = example-1 ></ div > < div class = example-2 ></ div > < script > CSS. paintWorklet. addModule( 'paint.js' ); </ script > example-1
会产生一个 无效图像,因为"red"
不符合注册的语法。example-2
会产生一个 无效图像,因为函数参数太多。 -
让 workletGlobalScope 成为来自绘画
Worklet
的PaintWorkletGlobalScope
,遵循 § 7.1 全局范围选择中的规则。用户代理可以在此时根据需要 创建一个工作全局范围。
-
运行 调用绘画回调 给定 name、inputArguments、snappedConcreteObjectSize、workletGlobalScope,可选地并行运行。
-
让 paintDefinitionMap 成为 workletGlobalScope 的 绘画定义 映射。
-
如果 paintDefinitionMap[name] 不存在,运行以下步骤:
-
队列任务运行以下步骤:
-
让 documentPaintDefinitionMap 成为相关文档的 文档绘画定义 映射。
-
设置 documentPaintDefinitionMap[name] 为
"invalid"
。 -
用户代理应该在调试控制台中记录一个错误,指出在所有
PaintWorkletGlobalScope
中没有注册类。
-
-
让图像输出成为 无效图像,并中止所有这些步骤。
注意: 这处理了可能有一个绘画工作全局范围没有收到
registerPaint(name, paintCtor)
的情况(然而另一个全局范围收到了)。在另一个全局范围上调用的绘画回调可能成功,但当调用 绘制一个绘画图像 时,在后续帧上不会成功。 -
-
让 definition 成为获取 paintDefinitionMap[name] 的结果。
-
让 paintClassInstanceMap 成为 workletGlobalScope 的 绘画类实例 映射。
-
让 paintInstance 成为获取 paintClassInstanceMap[name] 的结果。如果 paintInstance 为 null,运行以下步骤:
-
让 inputProperties 成为 definition 的 输入属性。
-
让 styleMap 成为一个新的
StylePropertyMapReadOnly
,只填充 inputProperties 中列出的属性的计算值。 -
让 renderingContext 成为通过 创建 PaintRenderingContext2D 对象 给定:
-
“width” - 由 snappedConcreteObjectSize 给定的宽度。
-
“height” - 由 snappedConcreteObjectSize 给定的高度。
-
“paintRenderingContext2DSettings” - 由 definition 给定的 PaintRenderingContext2DSettings 对象。
注意: 在调用绘画函数之间不应重用 renderingContext。这意味着在 renderingContext 上没有存储数据或状态。
注意: 这也意味着在绘画方法完成后,renderingContext 实际上被“隔离”。
-
-
让 paintSize 成为一个新的
PaintSize
,初始化为 snappedConcreteObjectSize 定义的宽度和高度。 -
在此阶段,用户代理可以重用先前调用的图像(如果 paintSize、styleMap 和 inputArguments 与先前调用的内容相同)。如果是这样,则让图像输出为该缓存图像并中止所有这些步骤。
在下面的示例中,div-1
和div-2
都具有相同的 JavaScript 参数的绘制函数。用户代理可以缓存一次调用的结果,并将其用于两个元素。// paint.js registerPaint( 'simple' , class { paint( ctx, size) { ctx. fillStyle= 'green' ; ctx. fillRect( 0 , 0 , size. width, size. height); } }); < style > . div-1 { width : 50 px ; height : 50 px ; background-image : paint ( simple ); } . div-2 { width : 100 px ; height : 100 px ; background-size : 50 % 50 % ; background-image : paint ( simple ); } </ style > < div class = div-1 ></ div > < div class = div-2 ></ div > < script > CSS. paintWorklet. addModule( 'paint.js' ); </ script > -
让 paintFunctionCallback 成为 definition 的 paint function。
-
调用 paintFunctionCallback,参数包括 «renderingContext, paintSize, styleMap, inputArguments»,并使用 paintInstance 作为 回调的 this 值。
如果 paintFunctionCallback 在可接受的时间内(由用户代理决定,即 "长时间运行的脚本")未完成,用户代理可以终止脚本,将图像输出设为 无效图像,并中止所有这些步骤。
注意:用户代理可以在其调试工具中为开发者提供工具,显示绘制类的开销。用户代理在适当情况下也可以显示 "无响应的脚本" 对话框。
-
图像输出应从传递给方法的 renderingContext 中生成。
注意:生成的图像内容并非设计为可访问。作者可以通过标准的可访问性 API 传递任何有用的信息。
7.1. 全局作用域选择
当用户代理需要从 paint PaintWorkletGlobalScope
的 Worklet
的
全局作用域 列表中选择一个 时,它必须:
-
至少从两个
PaintWorkletGlobalScope
中选择,除非用户代理面临内存限制。 -
不可连续 1000 次重复使用同一个
PaintWorkletGlobalScope
。注意: 1000 次限制是一个较高的上限,随着时间的推移,这一限制可能会(向下)优化。
注意: 这些规则确保作者不会依赖于在全局对象或类上存储状态,参见 关于工作线程规范中关于代码幂等性的讨论。
8. 示例
8.1. 示例 1:彩色圆形
下面的示例利用了 <paint()> 函数可以被动画化的特性。 例如,当下面的文本框获得焦点时,--circle-color
属性将从 deepskyblue
过渡到 purple
。
这种功能不仅限于过渡,还适用于 CSS 动画和 Web Animations API。
<!DOCTYPE html> < style > # example { --circle-color : deepskyblue ; background-image : paint ( circle ); font-family : sans-serif ; font-size : 36 px ; transition : -- circle - color 1 s ; } # example : focus { --circle-color : purple ; } </ style > < textarea id = "example" > CSS is awesome.</ textarea > < script > CSS. registerProperty({ name: '--circle-color' , syntax: '<color>' , initialValue: 'black' , inherits: false }); CSS. paintWorklet. addModule( 'circle.js' ); </ script >
// circle.js registerPaint( 'circle' , class { static get inputProperties() { return [ '--circle-color' ]; } paint( ctx, geom, properties) { // 改变填充颜色。 const color= properties. get( '--circle-color' ); ctx. fillStyle= color. cssText; // 确定中心点和半径。 const x= geom. width/ 2 ; const y= geom. height/ 2 ; const radius= Math. min( x, y); // 绘制圆形 \o/ ctx. beginPath(); ctx. arc( x, y, radius, 0 , 2 * Math. PI, false ); ctx. fill(); } });
8.2. 示例 2:图片占位符
作者可以使用 paint 在图片加载时绘制一个占位符图片。
<!DOCTYPE html> < style > # example { --image : url( '#someUrlWhichIsLoading' ); background-image : paint ( image -with-placeholder ); } </ style > < div id = "example" ></ div > < script > CSS. registerProperty({ name: '--image' , syntax: '<image> | none' , initialValue: 'none' , }); CSS. paintWorklet. addModule( 'image-placeholder.js' ); </ script >
// image-placeholder.js registerPaint( 'image-with-placeholder' , class { static get inputProperties() { return [ '--image' ]; } paint( ctx, geom, properties) { const img= properties. get( '--image' ); switch ( img. state) { case 'ready' : // The image is loaded! Draw the image. ctx. drawImage( img, 0 , 0 , geom. width, geom. height); break ; case 'pending' : // The image is loading, draw some mountains. drawMountains( ctx); break ; case 'invalid' : default : // The image is invalid (e.g. it didn’t load), draw a sad face. drawSadFace( ctx); break ; } } });
8.3. 示例 3:弧形
<!DOCTYPE html> < style > # example { width : 200 px ; height : 200 px ; background-image : paint ( arc , purple , 0.4 turn , 0.8 turn , 40 px , 15 px ), paint ( arc , blue , -20deg , 170 deg , 30 px , 20 px ), paint ( arc , red , 45 deg , 220 deg , 50 px , 10 px ); } </ style > < div id = "example" ></ div > < script > CSS. paintWorklet. addModule( 'arc.js' ); </ script >
// arc.js registerPaint( 'arc' , class { static get inputArguments() { return [ '<color>' , '<angle>' , // startAngle '<angle>' , // endAngle '<length>' , // radius '<length>' , // lineWidth ]; } paint( ctx, geom, _, args) { ctx. strokeStyle= args[ 0 ]. cssText; // 确定中心点。 const x= geom. width/ 2 ; const y= geom. height/ 2 ; // 将起始角度和结束角度转换为弧度。 const startAngle= this . convertAngle( args[ 1 ]) - Math. PI/ 2 ; const endAngle= this . convertAngle( args[ 2 ]) - Math. PI/ 2 ; // 将半径和线宽转换为像素。 const radius= this . convertLength( args[ 3 ]); const lineWidth= this . convertLength( args[ 4 ]); ctx. lineWidth= lineWidth; ctx. beginPath(); ctx. arc( x, y, radius, startAngle, endAngle, false ); ctx. stroke(); } convertAngle( angle) { switch ( angle. unit) { case 'deg' : return angle. value* Math. PI/ 180 ; case 'rad' : return angle. value; case 'grad' : return angle. value* Math. PI/ 200 ; case 'turn' : return angle. value* Math. PI/ 0.5 ; default : throw Error( `Unknown angle unit: ${ angle. unit} ` ); } } convertLength( length) { switch ( length. type) { case 'px' : return length. value; default : throw Error( `Unkown length type: ${ length. type} ` ); } } });
8.4. 示例 4:不同的颜色(基于大小)
< h1 > Heading 1</ h1 > < h1 > Another heading</ h1 > < style > h1 { background-image : paint ( heading -color ); } </ style > < script > CSS. paintWorklet. addModule( 'heading-color.js' ); </ script >
// heading-color.js registerPaint( 'heading-color' , class { static get inputProperties() { return []; } paint( ctx, geom, properties) { // 根据图像的宽度和高度选择颜色。 const width= geom. width; const height= geom. height; const color= colorArray[( width* height) % colorArray. length]; // 仅绘制一个实心图像。 ctx. fillStyle= color; ctx. fillRect( 0 , 0 , width, height); } });
8.5. 示例 5:在元素区域外绘制
可以通过使用 border-image 属性在元素的区域外进行绘制。
< style > # overdraw { --border-width : 10 ; border-style : solid ; border-width : calc( var ( --border-width ) * 1 px ); border-image-source : paint ( overdraw ); border-image-slice : 0 fill ; border-image-outset : calc( var ( --border-width ) * 1 px ); width : 200 px ; height : 200 px ; } </ style > < div id = "overdraw" ></ div > < script > CSS. paintWorklet. addModule( 'overdraw.js' ); </ script >
// overdraw.js registerPaint( 'overdraw' , class { static get inputProperties() { return [ '--border-width' ]; } paint( ctx, geom, properties) { const borderWidth= parseInt( properties. get( '--border-width' )); ctx. shadowColor= 'rgba(0,0,0,0.25)' ; ctx. shadowBlur= borderWidth; ctx. fillStyle= 'rgba(255, 255, 255, 1)' ; ctx. fillRect( borderWidth, borderWidth, geom. width- 2 * borderWidth, geom. height- 2 * borderWidth); } });
9. 安全性考虑
这些功能没有引入已知的安全问题。
10. 隐私考虑
-
绘制回调的时机可以被用作高带宽通道,用于检测链接的 "已访问" 状态。 (详情) 这并不是一个全新的隐私泄漏问题, 因为许多交互都会泄漏已访问状态, 但如果没有进一步的缓解措施, 这将是该信息的一个特别高带宽通道。
目前没有计划采取官方的缓解措施, 因为这个隐私泄漏问题需要更直接的解决方案 来修复所有此类通道。
11. 更改记录
自 2018 年 8 月 9 日 CR 版本发布以来的更改:
-
将传递给绘制工作器的输入属性列表筛选为仅包含已知或自定义属性。
-
为
PaintRenderingContext2D
添加了 alpha 标志, 以控制渲染表面是强制不透明还是允许透明度。 -
修正了输出位图大小的定义:
输出位图的大小是 它所渲染对象的具体对象大小
它所渲染片段的大小。