英文页面是权威参考。本译文可能已经过期,可能落后英文版若干个版本;翻译之后有改动的条目会显示英文原文,并带有译文已过期标记。
Kimi Design API 参考
TypeScript 包与 C++ 渲染器的公开 API,由提交 e036c066cb 的源码生成。标有原生的条目会链接到该 TypeScript 方法经由 Wasm 调用的 C 函数;C 函数则用由 TS 调用反向链接回来,并链接到实现它的 C++ 代码。
@taco-slides/model:633 项中已记录 556 项 · @taco-slides/editor:474 项中已记录 308 项 · @taco-slides/render-core:270 项中已记录 196 项 · @taco-design/electron:58 项中已记录 57 项 · C++ 渲染器:310 项中已记录 157 项
@taco-slides/model TypeScript
633 个导出中已记录 556 个 · 大纲
model 包是 Kimi Design 文档与框架无关的唯一可信来源。它定义文档类型,负责加载、保存和校验文档,并把每次编辑记录为一组带撤销历史的操作。它不包含任何编辑器、渲染器或网络代码。
文档被规范化为按 ID 索引的扁平映射:pageOrder、pages、nodes 和 assets,外加一个 theme。每个页面指向一个从不裁剪的根画框或编组,因此页面是一块无边界的画布。容器持有有序的 children 列表。节点不存储父级指针,因此层级结构只有一个可信来源。assertDocument 会拒绝缺失的节点、环、被共享的子节点、不可达的节点、失效的引用以及格式错误的几何数据。
本包返回的值都是深度冻结的。要修改文档,请把 DocumentOperation 传给 applyOperations,或者分派给 DocumentStore;后者还会保存用于撤销、重做和分支的提交历史。
当前版本
本包当前写入的版本号,在构建本页时从源码读取。
| 文档 schema | 0.27.0 | CURRENT_DOCUMENT_SCHEMA_VERSION;参见schema 历史 |
|---|---|---|
| 存储的历史记录 | 1 | CURRENT_STORE_SCHEMA_VERSION |
文档与页面
DesignDocument 保存所有页面、节点、资源和主题资源。页面按 pageOrder 排序,每个页面指明自己的根节点。
源码type DesignDocument = DesignDocumentV1一个 Kimi Design 文档。此包返回的值都是深度冻结的;要修改,请使用
applyOperations或通过DocumentStore。
源码interface DesignDocumentV1CURRENT_DOCUMENT_SCHEMA_VERSION版本下文档的存储结构。代码中请使用DesignDocument别名。数据被规范化为以 ID 为键的扁平映射。
assertDocument会检查:每个页面根节点都存在,每个节点恰好能从一个页面到达且最多有一个父节点,不存在环,并且样式、变量、连接线、媒体节点和字体的引用都能解析。(ImagePaint.assetId不会对照资源映射检查。)readonly schemaVersion: typeof CURRENT_DOCUMENT_SCHEMA_VERSION源码readonly id: DocumentId源码readonly title: string源码readonly pageOrder: readonly PageId[]源码每个页面 ID 恰好出现一次,按显示顺序排列。
readonly pages: Readonly<Record<string, Page>>源码readonly nodes: Readonly<Record<string, SceneNode>>源码所有页面上的所有节点,以
NodeId为键。readonly assets: Readonly<Record<string, Asset>>源码图片、视频和字体,以
AssetId为键。readonly theme: DocumentTheme源码readonly components?: Readonly<Record<string, ComponentDefinition>>自 0.23.0源码Reusable layer trees, keyed by
ComponentId. Omitted when empty. Each component’s layers live innodesunder itsrootId, on no page.readonly metadata?: Readonly<Record<string, JsonValue>>源码随文档保存的自由格式 JSON 数据。模型不会读取它。
源码interface Page文档中的一个页面。页面是无边界的画布:其根容器从不裁剪,因此顶层节点可以位于任何位置,根节点的 frame 只记录可见范围(见
pageRootFrame)。readonly id: PageId源码与该页面在
DesignDocument.pages中的键一致。readonly name: string源码不能为空。
readonly rootId: NodeId源码页面的根节点:没有父节点的画框或编组。
readonly guides?: readonly Guide[]自 0.11.0源码页面画布上的标尺参考线,使用页面坐标。为空时省略。
readonly variableModes?: VariableModes自 0.26.0源码The page’s mode per variable collection. Layers set to Auto inherit it; a collection left out uses the collection’s
activeModeId.readonly metadata?: Readonly<Record<string, JsonValue>>源码
自 0.11.0源码interface Guide标尺参考线:仅在编辑器中使用的直线,用于定位对象。渲染器从不绘制它,因此它永远不会出现在导出结果中。
readonly axis: "x" | "y"源码“x” 表示位于 x = offset 处的竖直线;“y” 表示位于 y = offset 处的水平线。
readonly offset: number源码沿坐标轴的位置,以文档单位表示,相对于承载该参考线的对象:页面参考线相对于页面原点,画框参考线相对于画框的左上角。
源码type DocumentSchemaVersion = number | SemanticVersion文档 schema 版本。当前文档使用
SemanticVersion;数字形式只在读取0.0.0版本之前保存的旧文件时使用。
源码type SemanticVersion = `${number}.${number}.${number}`major.minor.patch形式的版本字符串,例如"0.14.0"。
源码const CURRENT_DOCUMENT_SCHEMA_VERSION: "0.27.0"此包读写的 schema 版本。
deserializeDocument会把较旧的文档迁移到此版本,assertDocument会拒绝任何其他版本。
源码function pageRootFrame( document: DesignDocument, pageId: PageId ): Rect | undefined页面根节点的 frame 即页面的可见范围:编辑器将其适配到屏幕上的区域,渲染器也据此确定场景尺寸。页面根节点从不裁剪,因此顶层节点可以位于其外部。
场景节点
SceneNode 是一个按 type 区分的联合类型:frame、group、text、code、shape、image、video 和 connector。形状再按 shape 进一步区分。每个节点都具有 NodeBase 的字段;除路径外,每个节点还通过一个框和旋转来定位(FramedNodeBase)。
源码type SceneNode = | FrameNode | GroupNode | TextNode | CodeNode | ShapeNode | ImageNode | VideoNode | ConnectorNode | InstanceNode页面树中的任意节点,通过其
type字段区分。节点存放在扁平的DesignDocument.nodes映射中;容器按 ID 列出其子节点,父节点不被存储。
源码interface NodeBase每个
SceneNode都具有的字段。readonly id: NodeId源码与该节点在
DesignDocument.nodes中的键一致。readonly name: string源码图层名称。不能为空。
readonly visible: boolean源码readonly locked: boolean源码防止该节点在编辑器画布上被编辑。
readonly opacity: number源码取值从 0(透明)到 1(不透明)。
readonly blendMode?: BlendMode自 0.8.0源码该节点如何与其后方的内容合成;省略时为 normal。
readonly mask?: boolean自 0.8.0源码蒙版会在其自身绘制的 alpha 之外隐藏其后续同级节点,而自身不绘制任何内容。隐藏的蒙版不遮罩任何内容。
readonly aspectRatioLocked?: boolean自 0.1.1源码调整节点大小时保持宽高成比例。
readonly variableBindings?: VariableBindings源码其值来自主题变量的属性。
readonly exportSettings?: readonly ExportSetting[]自 0.14.0源码该节点导出区域中的各行,按顺序排列。为空时省略。
readonly expressions?: NodeExpressions自 0.24.0源码Computed fields: expression source text keyed by field, for nodes under a component root only (see
ComputableFieldandcomputableFieldsOf). The plain field keeps the base value, which the expression reads asstoredand which is shown when the expression does not check. A field holds a variable binding or an expression, never both. Omitted when empty.readonly condition?: string自 0.24.0源码A boolean expression; when it is false the layer and its sublayers are left out of every instance. Only on layers under a component root, never on the root itself. An expression that does not check counts as no condition.
readonly constraints?: ResizeConstraints自 0.25.0源码How the layer follows its frame when the frame is resized (see
ResizeConstraints). Omitted means Left and Top: the layer keeps its position and size. Used for children of frames without auto layout and for absolute children of auto layout frames; ignored elsewhere. Never on a group: constraints set on a group are set on its layers, as in Figma.readonly layoutPositioning?: "absolute"自 0.25.0源码"absolute"takes a child of an auto layout frame out of the flow, like Figma’s “Ignore auto layout”: the layout neither moves it nor counts it when hugging, and it follows the frame’s size changes by itsconstraints. Ignored when the parent has no auto layout.readonly variableModes?: VariableModes自 0.26.0源码The mode this layer and its sublayers use for each variable collection (see
VariableModes). A collection left out is Auto: the layer inherits the mode from its parent. On an instance, the modes apply to the component’s layers, so two instances of one component can show two modes.readonly metadata?: Readonly<Record<string, JsonValue>>源码与节点一起保存的自由格式 JSON 数据。模型不会读取它。
源码interface FramedNodeBase extends NodeBase所有由矩形定位的节点共有的字段:适用于除
PathNode以外的所有类型,后者改用变换矩阵定位。readonly frame: Rect源码位置和未旋转时的尺寸,位于父节点的坐标系中(相对于父节点画框的左上角)。
readonly rotation: number源码角度,单位为度,在屏幕上顺时针,绕画框中心旋转。
readonly flipX?: boolean源码以局部水平中心为轴镜像渲染后的节点。
readonly flipY?: boolean源码以局部垂直中心为轴镜像渲染后的节点。
frame、rotation和翻转共同把局部点 (原点位于画框左上角)放到父节点中的其中 是以弧度表示的
rotation, 在每个已设置翻转的轴上取 。先翻转,再旋转。readonly resizing?: NodeResizing自 0.15.0源码填充尺寸和尺寸限制。为空时省略。
源码type ContainerNode = FrameNode | GroupNode拥有
children的节点。用isContainerNode判断。
源码const isContainerNode: (node: SceneNode) => node is ContainerNode对画框和编组为 true,即拥有
children的节点。
源码interface FrameNode extends FramedNodeBase拥有自身尺寸、填充、描边和效果的容器,可选择使用自动布局。每个页面的根节点是一个画框或编组;页面根节点从不裁切内容。
readonly type: "frame"源码readonly children: readonly NodeId[]源码按绘制顺序排列的子节点 ID:第一个子节点位于最底层。
readonly layout: Layout源码子节点的定位方式:自由定位,或由堆叠或网格自动布局定位。
readonly style?: VisualStyle源码readonly clipContent?: boolean源码隐藏子节点中超出画框的部分。
readonly guides?: readonly Guide[]自 0.11.0源码属于此画框并随其移动的标尺参考线。编辑器只在既未旋转也未翻转的顶层画框上显示它们。为空时省略。
源码interface GroupNode extends FramedNodeBase自身没有尺寸的容器:它的 frame 始终适配为其子节点边界的并集(见
fitGroupToChildren)。当applyOperations移除了编组的最后一个子节点时,该编组也会被移除。readonly type: "group"源码readonly variableBindings?: GroupVariableBindings源码Properties whose values come from theme variables. A group’s size is computed from its layers, so it cannot bind
widthorheight.readonly children: readonly NodeId[]源码按绘制顺序排列的子节点 ID:第一个子节点位于最底层。
readonly clipContent?: boolean源码
源码interface TextNode extends FramedNodeBase由带样式的段落组成的文本框。
readonly type: "text"源码readonly paragraphs: readonly TextParagraph[]源码readonly verticalAlign: "top" | "middle" | "bottom"源码当 frame 比文本高时,文本在 frame 中的垂直位置。
readonly overflow: "clip" | "visible"源码超出 frame 的文本是被裁掉还是仍然绘制。
readonly autoResize: "none" | "height" | "width-and-height"源码none保持 frame 的两个尺寸固定,height保持宽度并让高度随文本变化,width-and-height让两者都随文本变化。readonly wrap: "none" | "word" | "character"源码长行可以在何处换行:从不换行、在单词之间换行,或在任意字符之间换行。
源码type TextualNode = TextNode包含可编辑富文本的节点。目前只有
TextNode。
源码const isTextualNode: (node: SceneNode) => node is TextualNode对包含富文本的节点(
TextNode)为 true。
源码interface CodeNode extends FramedNodeBase一段源代码。语法高亮在渲染时计算,只存储原始源代码。
readonly type: "code"源码readonly source: string源码readonly language: string源码用于高亮的语言标识符。不能为空。
readonly fontFamily: string源码统一应用于整段源代码,而不是单个文本片段。
readonly fontSize: number源码统一应用于整段源代码,而不是单个文本片段。为正数。
readonly codeStyleId?: CodeStyleId源码主题中的代码样式;省略时使用主题的
defaultCodeStyleId。readonly codeStyleOverrides?: Partial< Pick< CodeStyle, "lineHeight" | "letterSpacing" | "background" | "foreground" | "syntax" > >源码仅对此节点替换代码样式中对应值的取值。
readonly lineNumbers: boolean | number源码false 隐藏行号,
true从 1 开始编号,数字则设置首行的行号。readonly autoResize: "none" | "height" | "width-and-height"自 0.1.3源码含义与
TextNode.autoResize相同。readonly wordWrap: boolean源码按画框宽度对过长的源代码行自动换行。
readonly stroke?: Stroke自 0.1.4源码绘制在代码块四周的描边。
readonly decorations: readonly CodeDecoration[]源码
源码interface CodeDecorationCodeNode源代码中被标记的一段范围。
源码type ShapeNode = | RectangleNode | EllipseNode | PolygonNode | StarNode | LineNode | PathNode所有
type: "shape"的节点,通过其shape字段区分。
源码interface RectangleNode extends FramedNodeBase填满其 frame 的矩形;
VisualStyle.cornerRadius为其设置圆角。readonly type: "shape"源码readonly shape: "rectangle"源码readonly style: VisualStyle源码
源码interface EllipseNode extends FramedNodeBase填满其画框的椭圆,或椭圆的圆弧、扇形或圆环。
readonly type: "shape"源码readonly shape: "ellipse"源码readonly style: VisualStyle源码readonly arc?: EllipseArc自 0.12.0源码省略时绘制完整的椭圆。
自 0.12.0源码interface EllipseArc把椭圆变成圆弧、扇形或圆环,与 Figma 的弧形数据相同。角度以度为单位,在椭圆的参数角上从 x 轴正方向顺时针测量。扫描范围从起始角度到结束角度,任一方向上最多一整圈。
readonly startingAngle: number源码readonly endingAngle: number源码readonly innerRadius: number源码内半径,以外半径的比例表示,取值从 0(扇形)到小于 1(圆环)。
自 0.12.0源码interface PolygonNode extends FramedNodeBase正多边形,其顶点经缩放以填满 frame,第一个顶点位于顶部中央,与 Figma 的绘制方式一致。
readonly type: "shape"源码readonly shape: "polygon"源码readonly pointCount: number源码角的数量,为 3 到 60 之间的整数。
readonly style: VisualStyle源码
自 0.12.0源码interface StarNode extends FramedNodeBase星形,其外顶点和内顶点经缩放以填满 frame。
readonly type: "shape"源码readonly shape: "star"源码readonly pointCount: number源码外顶点的数量,为 3 到 60 之间的整数。
readonly innerRadius: number源码内顶点的距离,以外半径的比例表示,范围为 0 到 1。
readonly style: VisualStyle源码
自 0.12.0源码interface LineNode extends FramedNodeBase单条直线描边。与 Figma 一样,其 frame 高度为零:直线从 frame 局部坐标 (0, 0) 延伸到 (width, 0),旋转使其绕 frame 中心转动。箭头就是带有箭头端点的直线。
readonly type: "shape"源码readonly shape: "line"源码readonly style: VisualStyle源码readonly startCap: StrokeCap源码readonly endCap: StrokeCap源码
源码interface PathNode extends NodeBase可编辑的矢量形状。与其他形状不同,它没有 frame 或旋转:
transform将矢量网络放置到父节点中,其边界由变换后的网络推导得出(见getNodeBounds)。readonly type: "shape"源码readonly shape: "path"源码readonly vectorNetwork: VectorNetwork自 0.2.0源码路径的几何形状。
readonly transform: TransformMatrix源码将网络坐标映射到父节点的坐标系。
readonly style: VisualStyle源码readonly startCap?: StrokeCap自 0.22.0源码The end points of an open path whose segments form one chain, each in order from the end of the one before (see
openPathChainEnds): the start cap sits on the first segment’s start and the end cap on the last segment’s end, the same styles a line has. Omitted is round, which every path drew before 0.22.0. Closed paths and paths with branches or several chains ignore them, and so does a path with an inside or outside stroke.readonly endCap?: StrokeCap自 0.22.0源码
源码interface ImageNode extends FramedNodeBase放置的图片。像素数据存放在
ImageAsset中。readonly type: "image"源码readonly assetId: AssetId源码必须指向一个类型为
image的资源。readonly fit: MediaFit源码readonly crop?: Rect源码要显示的源图片部分,以源像素表示。
readonly alt: string源码用于无障碍访问的替代文本;可以为空。
源码interface VideoNode extends FramedNodeBase放置的视频。文件存放在
VideoAsset中。readonly type: "video"源码readonly assetId: AssetId源码必须指向一个类型为
video的资源。readonly fit: MediaFit源码readonly crop?: Rect源码要显示的视频画面部分,以源像素表示。
readonly alt: string源码用于无障碍访问的替代文本;可以为空。
源码type MediaFit = "contain" | "cover" | "fill"图片或视频如何填满其 frame,与 CSS
object-fit相同。
源码interface ConnectorNode extends FramedNodeBase两点之间带描边的直线或箭头,每个端点都可以选择连接到某个节点。
readonly type: "connector"源码readonly start: ConnectorEndpoint源码readonly end: ConnectorEndpoint源码readonly routing: "straight" | "elbow" | "curve"源码readonly stroke: Stroke源码readonly startCap: StrokeCap自 0.20.0源码The end styles, the same set a line has (
STROKE_CAPS). Before 0.20.0 a connector had only"none","arrow"and"dot"; loading an older document turns"arrow"into"triangle-arrow"and"dot"into"circle-arrow".readonly endCap: StrokeCap源码readonly cornerRadius?: number自 0.21.0源码How far, in pixels, each bend of an elbow connector is rounded, as Figma’s
ConnectorNode.cornerRadius. A bend never rounds past half of either part of the line it joins, so a short part keeps a smaller curve. The ends and end styles are not rounded. Straight and curved connectors have no bends and ignore it. Missing means 0: sharp bends. Not negative.readonly cornerSmoothing?: number自 0.21.0源码How far each rounded bend of an elbow connector eases into the line, from 0 (a circular arc) to 1 (a continuous curve), the same fraction as a rectangle’s
NodeVisualStyle.cornerSmoothingand drawn the same way. A smoothed bend takes up to(1 + cornerSmoothing) * cornerRadiusof each part of the line it joins, capped at half of the shorter part, which also caps the smoothing. It has no effect without a corner radius, or on straight and curved connectors. Figma’sConnectorNodehas no smoothing; this extends it. Missing means 0.
源码interface ConnectorEndpoint译文已过期
One end of a
ConnectorNode.An end with
nodeIdattaches to that layer, and the page compiler places it from the layer’s frame each time, so it follows the layer when the layer moves or resizes. Where on the layer it goes is set by at most one of:side: the middle of that side, and an elbow connector leaves the layer at a right angle to it. Figma calls this a magnet (TOP,RIGHT,BOTTOMorLEFTin the plugin API’sConnectorEndpointConnectedWithMagnet). On an ellipse, polygon or star the end is where the shape’s outline meets the line from its centre toward that side, so it sits on the drawn shape.anchor: a corner or edge middle of a polygon, star or ellipse arc (ConnectorAnchor); the end leaves along the outline’s outward direction there.point: a fixed point on the layer, as FigJam places an end dropped with Command or Ctrl held (ConnectorEndpointConnectedWithPosition). Figma stores it in the layer’s pixels; here it is a fraction of the layer’s width and height, so the point keeps its place when the layer resizes.
With none of them (Figma’s
AUTOmagnet), the end goes where the layer’s outline faces the other end.xandyare the end’s position in the connector’s frame; for an attached end they record where it was last placed and are replaced when the connector is drawn.readonly nodeId?: NodeId源码此端连接的节点。它必须与连接线位于同一页面。
readonly x: number源码readonly y: number源码readonly side?: ConnectorSide自 0.20.0源码The side of the attached layer this end is pinned to. Needs
nodeId, and cannot be set together withpointoranchor.readonly anchor?: ConnectorAnchor自 0.20.0源码The key point on the attached shape’s outline this end is pinned to. Needs
nodeId, and cannot be set together withsideorpoint.readonly point?: { readonly x: number; readonly y: number }自 0.20.0源码The point on the attached layer this end is fixed to, as fractions of the layer’s width (
x) and height (y) from its top-left corner:{ x: 1, y: 0.5 }is the middle of the right side. Each fraction is between 0 and 1. NeedsnodeId, and cannot be set together withsideoranchor.
自 0.20.0源码type ConnectorSide = "top" | "right" | "bottom" | "left"A side of a layer that an attached connector end is pinned to.
自 0.20.0源码interface ConnectorAnchorA key point on a shape’s outline that an attached connector end is pinned to, found from the shape’s geometry each time the connector is drawn, so the end follows the shape when it moves, resizes or changes its points.
vertex: cornerindexof the outline, counted aspolygonPointsandstarPointslist them (clockwise from the top point; a star’s outer tips are the even indices). On an ellipse arc, vertex 0 is where the arc starts and vertex 1 where it ends, on the outer rim.edge: the middle of the outline’s edge from vertexindexto the next.
An index the shape does not have (for example after a polygon loses points), or an anchor on a layer without such points, leaves the end automatic, as if it had no anchor.
readonly kind: "vertex" | "edge"源码readonly index: number源码A whole number from 0.
源码type BlendMode = (typeof BLEND_MODES)[number]
自 0.8.0源码const BLEND_MODES: readonly [ "normal", "darken", "multiply", "color-burn", "lighten", "screen", "color-dodge", "overlay", "soft-light", "hard-light", "difference", "exclusion", "hue", "saturation", "color", "luminosity" ]可分离与不可分离的合成模式,采用 CSS
mix-blend-mode的术语。
画框可以用自动布局来定位子节点,而不必手动摆放。堆叠把子节点排成一行或一列,并可换到多行;网格把子节点放进等宽的列中。画框在每个轴上选择固定(Fixed)或包裹内容(Hug),而每个子节点在 NodeResizing 中选择是否填充父节点给出的空间,以及适用的尺寸限制。这些都遵循 Figma 的自动布局,包括它的规则:当某个堆叠子节点在某个轴上填充时,画框在该轴上停止包裹内容。
源码type Layout = AbsoluteLayout | AutoLayout
源码interface AbsoluteLayoutreadonly kind: "absolute"源码
源码type AutoLayout = StackAutoLayout | GridAutoLayout
源码interface StackAutoLayout extends AutoLayoutConstraints横排(
"horizontal")或竖排("vertical")的自动布局。主轴沿堆叠方向,交叉轴与之垂直。readonly kind: "vertical" | "horizontal"源码readonly gap: number源码子节点在主轴上的间距。
readonly padding: LayoutPadding源码readonly align: "start" | "center" | "end"源码子节点在所在行内的交叉轴位置。子节点要横跨整行,需在
FramedNodeBase.resizing中设置交叉轴填充。schema 0.15.0 移除了作用于整个画框的"stretch"。readonly justify: | "start" | "center" | "end" | "space-between" | "space-around" | "space-evenly"源码子节点在每一行内沿主轴如何分布。
space-*取值用一个永不为负的自动间距代替gap:space-between把所有剩余空间放在子节点之间(只有一个子节点时它位于起点),space-around在第一个子节点之前和最后一个之后各放半个间距,space-evenly则各放一整个间距(两者都把单个子节点居中)。子节点溢出时,三者都从起点依次排列。schema 0.15.0 新增了"space-around"和"space-evenly"。readonly wrap?: boolean自 0.15.0源码把放不下的子节点移到新的一行:横向堆叠换到新行,竖向堆叠换到新列。省略表示只有一行。
readonly wrapGap?: number自 0.15.0源码换行后各行之间的间距。省略表示与
gap相同。wrap关闭时保留但不使用。readonly alignContent?: "auto" | "space-between"自 0.15.0源码换行后的各行如何分配交叉轴。
"auto"(默认)按align排列各行,或在每个子节点都在交叉轴上填充时,把剩余空间平均分给各行;"space-between"用永不为负的自动间距把各行分开。wrap关闭时保留但不使用。
源码interface GridAutoLayout extends AutoLayoutConstraintsreadonly kind: "grid"源码readonly columns: number源码readonly columnGap: number源码readonly rowGap: number源码readonly padding: LayoutPadding源码
源码interface AutoLayoutConstraints画框自身的尺寸设置。尺寸限制已在 0.15.0 中移到
FramedNodeBase.resizing。readonly widthSizing: LayoutSizing源码"hug"让画框在这个轴上按内容定尺寸。在堆叠中,若有子节点在同一轴上填充,画框改为保持其存储的尺寸,这与 Figma 在这种情况下停止包裹内容一致。网格仍保持包裹内容:其填充子节点占据所在的单元格,而单元格的尺寸由其他子节点决定。readonly heightSizing: LayoutSizing源码
源码interface LayoutPaddingreadonly top: number源码readonly right: number源码readonly bottom: number源码readonly left: number源码
源码type LayoutSizing = "fixed" | "hug"自动布局画框在一个轴上如何确定自身尺寸:保持存储的尺寸(Fixed,固定),或包裹内容(Hug)。填充父节点则在子节点上用
FramedNodeBase.resizing设置。
自 0.15.0源码interface NodeResizing自动布局可以如何让节点的尺寸不同于其存储的画框。
把
width或height设为"fill",会让堆叠或网格自动布局的子节点在该轴上占据父节点给出的空间:同一行中的填充子节点平分该行主轴上的剩余空间,交叉轴上的填充占据该行的交叉尺寸,网格子节点填满其单元格。这个标志在自动布局之外、对旋转的节点、编组和连接线都不起作用。节点不能在它包裹自身内容的轴上填充(自动布局画框的"hug"尺寸,或文本和代码节点的autoResize)。尺寸限制约束自动布局给节点的尺寸:填充子节点分得的空间,以及自动布局画框自身的包裹内容或固定尺寸。
readonly width?: "fill"源码readonly height?: "fill"源码readonly minWidth?: number源码readonly maxWidth?: number源码readonly minHeight?: number源码readonly maxHeight?: number源码
译文已过期
A few rules are shared with the editor’s drop slots so both break a wrapping row or column at the same children. stackLineBreaks splits the children into lines from the sizes stackLineBreakSize gives; fillsAxis and canFillParent say when a child takes a Fill size.
源码type LayoutAxis = "width" | "height"节点的一个尺寸轴:宽度或高度。
源码function nodeResizing(node: SceneNode): NodeResizing | undefined节点的填充标志和尺寸限制;路径返回
undefined。
源码function canFillParent(node: SceneNode): boolean自动布局能否给
node一个填充(Fill)尺寸:它的框必须就是它的画框(不是路径,没有旋转),并且它不能是编组或连接线,因为它们的尺寸来自其他节点。
源码function fillsAxis(node: SceneNode, axis: LayoutAxis): booleannode是否在axis上填充其自动布局父节点。
源码function stackLineBreakSize(node: SceneNode, mainAxis: LayoutAxis): number拆分行时堆叠子节点所取的主轴尺寸:其框的尺寸,或在它于主轴上填充时取其最小尺寸。
源码function stackLineBreaks( layout: Pick<StackAutoLayout, "gap" | "justify" | "wrap">, availableMain: number, sizes: readonly number[] ): number[][]像 Figma 的换行那样把一行或一列拆分成多行:子节点保持顺序,一个子节点会超出
availableMain(画框去掉内边距后的主轴尺寸)时就开始新的一行。自动间距(between、around 或 evenly)在这里按零计算。不换行时只有一行。sizes是stackLineBreakSize给出的子节点主轴尺寸。按行分组返回子节点的索引;没有子节点时没有行。
The layout itself runs whenever the editor edits the document: withAutoLayoutOperations adds the node replacements that keep every affected auto layout frame laid out. layoutFrameTree lays out one frame and the frames inside it, and applyFrameLayout places one frame’s children. createFrameLayout makes a new layout of a given kind.
源码function withAutoLayoutOperations( document: DesignDocument, operations: readonly DocumentOperation[] ): readonly DocumentOperation[]operationsfollowed by the node replacements that keep auto layout frames laid out after them: frames the operations touch are laid out again, deepest first, and nodes the operations leave filling a parent without auto layout become Fixed. In a document with components, a text whose content is computed is first sized for the text it shows (fitComputedTextContent), and the component cascade then runs (cascadeComponentChanges): instances of changed components are refitted to their hugging size, their dead override keys dropped, and their ancestors laid out again, nested components first. The operations come back unchanged when nothing needs it.
源码function layoutFrameTree( nodes: Record<string, SceneNode>, frameId: NodeId, changed: Set<NodeId> = new Set() ): Set<NodeId>Lays out the auto layout frame
frameIdinnodes(changed in place), then lays out again each child frame whose size it changed, so Fill sizes reach nested auto layouts, and each auto layout frame that constraints resized. Returns the IDs of every node it changed. The caller lays out hugging descendants first, deepest first, so their sizes are known.
源码function applyFrameLayout( frame: FrameNode, childNodes: readonly SceneNode[], layout: Layout ): AppliedFrameLayoutLays out one frame’s direct children with
layoutand returns the frame with its new size and the moved or resized children. Child frames are not laid out again here;layoutFrameTreedoes that.
源码interface AppliedFrameLayoutA frame and its children after
applyFrameLayouthas placed them.readonly frame: FrameNode源码readonly children: ReadonlyMap<NodeId, SceneNode>源码
源码function createFrameLayout( kind: Layout["kind"], gap = DEFAULT_AUTO_LAYOUT_GAP ): LayoutA new layout of the given kind. Auto layouts start with a fixed width, a hugged height, no padding and
gapbetween children (a grid uses it for both its column and row gaps).
源码function frameLayoutGap(layout: Layout): numberThe gap a layout keeps between children: a stack’s gap or a grid’s column gap. Without an auto layout it is
DEFAULT_AUTO_LAYOUT_GAP.
源码const DEFAULT_AUTO_LAYOUT_GAP: 24The gap, in pixels, a new auto layout starts with.
Resize constraints say how a layer follows its frame when the frame is resized, with Figma’s five options on each axis: Left, Right, Left and right, Center and Scale horizontally, and their vertical counterparts. They apply to the children of frames without auto layout and to the absolute children of auto layout frames (layoutPositioning: "absolute", Figma’s “Ignore auto layout”), which the layout leaves out of its flow. constrainChildren places a frame’s children for a change of its size; the editor’s frame resize, the selection box and group resizing all use it, and so does layoutFrameTree when a layout changes a frame’s size. scaleLayerInParent scales one layer the way a resized box does.
自 0.25.0源码interface ResizeConstraintsA layer’s resize constraints, Figma’s five options on each axis. They act on the layer’s axis-aligned bounds in its frame (see
constrainChildren).readonly horizontal: HorizontalConstraint源码readonly vertical: VerticalConstraint源码
自 0.25.0源码type HorizontalConstraint = "left" | "right" | "left-right" | "center" | "scale"How a layer’s horizontal position and width follow its frame’s width.
"left","right"and"center"keep the width and the distance to the left edge, the right edge or the center line;"left-right"keeps both distances, so the width changes with the frame;"scale"keeps the layer’s position and width as shares of the frame’s width.
自 0.25.0源码type VerticalConstraint = "top" | "bottom" | "top-bottom" | "center" | "scale"How a layer’s vertical position and height follow its frame’s height; the vertical counterpart of
HorizontalConstraint.
自 0.25.0源码const DEFAULT_RESIZE_CONSTRAINTS: ResizeConstraintsThe constraints a layer has when it stores none: Left and Top, Figma’s default, which keeps the layer’s position and size.
自 0.25.0源码function nodeConstraints(node: SceneNode): ResizeConstraintsA layer’s constraints, with
DEFAULT_RESIZE_CONSTRAINTSwhen it stores none.
自 0.25.0源码function followsConstraints(parent: FrameNode, child: SceneNode): booleanWhether a child of
parentis placed by its constraints whenparentresizes: every child of a frame without auto layout, and only the absolute children (layoutPositioning: "absolute") of an auto layout frame, whose other children the layout places.
自 0.25.0源码function constrainChildren( nodes: NodeRecord, parentId: NodeId, from: FrameSize, to: FrameSize ): readonly SceneNode[]Places each child of the frame
parentIdfor a resize of that frame fromfromtoto, by the child’s constraints (NodeBase.constraints), as Figma does when a frame is resized.nodesholds the frame and its descendants before the change; the frame’s own record is only read for its children and layout, so it may hold either size.- Constraints act on each child’s axis-aligned bounds in the frame. A child whose bounds change size is resized like a layer in a resized selection box (
scaleLayerInParent): a rotated or flipped layer keeps its rotation and flips, and a frame’s own children follow by their constraints in turn. - An auto layout frame’s flow children are left to its layout; only its absolute children move (
followsConstraints). A child auto layout frame whose size changes is not laid out again here: the caller does that, aslayoutFrameTreeor the editor’s auto layout step do. - A group has no constraints of its own. The layers of an upright group (not rotated or flipped) are placed one by one by their own constraints relative to the frame, and the group is fitted to them again. A rotated or flipped group moves and resizes as one layer, by the option its layers share on each axis, or Left or Top when they differ.
Returns every changed node, children before descendants, each at most once. An unchanged size returns an empty list.
The instance resolver calls this to lay out a resized instance whose component root has no auto layout:
constrainChildren(nodes, rootId, componentRoot.frame, instance.frame), writing the result into its node record before it lays out auto layout frames withlayoutFrameTree.- Constraints act on each child’s axis-aligned bounds in the frame. A child whose bounds change size is resized like a layer in a resized selection box (
自 0.25.0源码interface FrameSizeA frame’s size before or after a resize. Constraints only need sizes: children are placed relative to their frame’s top-left corner, so where the frame moves on the page does not matter.
readonly width: number源码readonly height: number源码
自 0.25.0源码function scaleLayerInParent( nodes: NodeRecord, node: SceneNode, scaleX: number, scaleY: number ): readonly SceneNode[]Scales a layer’s position and size by (scaleX, scaleY) about its parent’s origin, in the parent’s coordinates, the way resizing a group or a selection box moves the layers inside it. Positions, sizes and vector geometry scale; stroke widths, corner radii, effects and font sizes do not.
- A rotated layer keeps its rotation and takes the size whose bounds are its old bounds scaled, when the rotation allows it (see the source of
rotatedSizefor the fallback near 45 degrees). - A group’s descendants scale with it.
- A frame’s box scales and its children follow by their constraints (
constrainChildren); an auto layout places its other children later. - Text or code that grew with its content gets a fixed size.
Returns the layer followed by every changed descendant.
nodesmust hold the layer’s descendants.- A rotated layer keeps its rotation and takes the size whose bounds are its old bounds scaled, when the rotation allows it (see the source of
The sizing helpers read and change a node’s Fixed, Hug or Fill sizing on each axis, keeping the rules of Figma’s resizing menu: only auto layout frames, instances of a component with auto layout, text and code can hug, and only children of an auto layout frame can fill. nodeAxisSizing is the one reader and withAxisSizing the one writer of Fixed and Hug: an instance’s sizing is its override of its component root’s sizing, so both take the document. withManualSize is the one place a size changed by hand (a resize, the Scale tool, a size variable) gets the sizing that keeps it: commands and drag previews pass their node through it.
源码type AxisSizing = "fixed" | "hug" | "fill"How a node is sized on one axis, as the width and height menus show it (Figma’s resizing menu): a stored size, its content’s size, or the space its auto layout parent gives it.
源码type SizingAxis = "width" | "height"The axis a sizing applies to.
源码function nodeAxisSizing( document: DesignDocument, node: SceneNode, axis: SizingAxis ): AxisSizingThe node’s sizing on an axis: the one reader of it. Nodes that cannot hug or fill are Fixed. An auto layout frame’s is its layout’s; text and code read their automatic sizing. An instance has no layout of its own: its sizing is its override of its component root’s sizing (
LayerSizingOverride, stored under the root’s path), and the root’s own sizing where it has none, which is what the instance resolver lays it out with. Fill is the node’s ownresizingfor every kind of node.
源码function canHugAxis(document: DesignDocument, node: SceneNode): booleanAuto layout frames hug their children, text and code blocks hug their content, and an instance hugs as its component root does: only when the root has auto layout.
源码function canFillAxis( document: DesignDocument, node: SceneNode, axis: SizingAxis, parent: SceneNode | undefined = parentNodeOf(document, node.id) ): booleanWhether the node can fill its parent on an axis: it must be a child of an auto layout frame, and not a path, group or connector, a rotated node, or (for the height) a line, whose height is always zero. Figma offers Fill container only on children of auto layout frames.
源码function withoutFill(node: SceneNode, axis: SizingAxis): SceneNodeThe node without a Fill flag on the axis.
源码function withoutAnyFill(node: SceneNode): SceneNodeThe node without any Fill flag, keeping its size limits.
源码function withAxisSizing( document: DesignDocument, node: SceneNode, axis: SizingAxis, sizing: "fixed" | "hug" ): SceneNodeThe node with its sizing on
axisset to Fixed or Hug: the one writer of it, the counterpart ofnodeAxisSizing. An auto layout frame stores it in its layout; an instance stores it as its override of its component root’s sizing. A node that has neither (a shape, a frame without auto layout, an instance of a component without auto layout) is returned as it is, and so is text or code, whose automatic sizing has rules of its own (sizingReplacements). Fill is not touched: seewithoutFill.
源码type ManualSizeChange = "resize" | "scale" | "variable"How a layer’s size was changed by hand, as opposed to by a layout, a constraint or its content:
"resize": a resize handle, a typed W or H, the box around a selection, a moved end of a line."scale": the Scale tool, on one layer or on the box around a selection."variable": a size variable bound to W or H.
源码function withManualSize( document: DesignDocument, before: SceneNode, after: SceneNode, change: ManualSizeChange, axes: readonly SizingAxis[] = changedSizeAxes(before, after) ): SceneNodeafter, the nodebeforewith a size changed by hand, with the sizing that change leaves: the one place the rule “a size set by hand is kept” is written. Every command that changes a size by hand, and every preview of one, passes its node through here, so the release commits what the drag drew and the next layout does not undo it.- A resize, on each axis whose size changed: Fill and Hug become Fixed (an instance’s Hug too) and a size variable on the axis is dropped.
- The Scale tool, on each axis whose size changed: an instance’s Hug becomes Fixed, since its layers are its component’s and do not scale. A frame keeps Hug: its children scaled with it, so it hugs the scaled size. Fill and a size variable are left as they are.
- A size variable: Fill and Hug become Fixed on
axes, which the caller names because the variable’s value may equal the size the node has.
A size that a layout, a constraint or the node’s content gives is not a change by hand and does not come here: the sizing stays.
源码function withManualSizes( document: DesignDocument, nodes: readonly SceneNode[], change: ManualSizeChange, only?: ReadonlySet<NodeId> ): readonly SceneNode[]nodes, the output of a resize or a scale of layers ofdocument, each passed throughwithManualSizeagainst the node it replaces.onlylimits the rule to the layers the user changed, where the others were only carried along (the descendants of a resized group or selection).
源码function withoutStretchWhereHugging( document: DesignDocument, node: SceneNode ): SceneNodeThe node without a stretching constraint on an axis it hugs: what the rule “no node hugs and stretches on the same axis” does to one node. Commands do not call it;
stretchWhereHuggingReplacementsapplies the rule to every edit, on the axes the edit brings to break it.
源码function stretchWhereHuggingReplacements( previous: DesignDocument, next: DesignDocument, changedNodeIds: ReadonlySet<NodeId> ): readonly SceneNode[]The one place the rule “no node has a stretching constraint (Left and right, Top and bottom, Scale) on an axis whose sizing is Hug” is enforced.
applyOperationscalls it for every batch of operations, so every command, preview, paste, undo-able edit and replayed commit passes through it and no command applies the rule itself.nextispreviousafter the batch andchangedNodeIdsthe nodes the batch wrote. The nodes looked at are the ones whose sizing or constraints can have changed:- every changed node that still exists (its own layout, automatic text sizing, overrides, component or constraints may be new);
- every instance, at any depth and on any page or inside any component, of a component whose root or root sizing changed. An instance with a sizing override on the axis keeps its own sizing, so only the ones that follow the component can lose a constraint.
Only a break of the rule that the batch brings is removed: an axis of a node that hugs and stretches in
nextand did not inprevious(the node is new, or it kept the rule on that axis there). A node that already hugged and stretched on an axis inprevious, as a document stored before the rule existed can hold, is left on that axis exactly as the batch leaves it, so a batch that does not touch the break, or keeps it, can be reversed exactly.Returned are those nodes, each with the stretching constraint turned into Left or Top on the axes that newly break the rule, in a stable order (the batch’s own, then the document’s). The sizing is never changed here, so one pass is enough. The cost is two sizing reads per changed node, two more for one that breaks the rule, and one comparison per component; the walk over every node of the document happens only for a batch that changed a component root’s sizing.
源码function sizingReplacements( document: DesignDocument, nodeIds: readonly NodeId[], axis: SizingAxis, sizing: AxisSizing ): ReadonlyMap<NodeId, SceneNode>The nodes that change when
nodeIdsare set tosizingonaxis, by id. Nodes that cannot take that sizing are left out.An instance follows every rule here as an auto layout frame does, through
nodeAxisSizingandwithAxisSizing, except the last part of the Hug rule: its layers are its component’s, so their Fill is not changed.- Fill turns the node’s own Hug on the axis into Fixed (text and code stop sizing that axis to their content), drops a size variable on the axis, and turns a hugging stack parent Fixed on the axis, as Figma does: “If any child objects within an auto layout frame are set to Fill container, the parent frame will no longer hug contents and become Fixed for the axis.”
- Hug on an auto layout frame turns its stack children that fill the axis into Fixed. A grid keeps its Fill children: they take their cell.
- Fixed and Hug drop the node’s own Fill on the axis.
Hug leaves a stretching constraint on the axis for
applyOperationsto turn into Left or Top, as it does after every edit (stretchWhereHuggingReplacements).
源码function resizingReplacements( document: DesignDocument, nodeId: NodeId, resizing: NodeResizing | undefined ): ReadonlyMap<NodeId, SceneNode>The nodes that change when a node’s Fill flags and size limits are replaced with
resizing(undefinedremoves them all). A newly set Fill follows the same rules as choosing Fill container in the sizing menu.
源码function isAutoLayoutFrame(node: SceneNode | undefined): node is AutoLayoutFrameWhether the node is a frame with a stack or grid auto layout.
源码function parentNodeOf( document: DesignDocument, nodeId: NodeId ): SceneNode | undefinedThe container that holds the node, or
undefinedfor a page’s top level node.
源码function documentWithNodes( document: DesignDocument, nodes: ReadonlyMap<NodeId, SceneNode> ): DesignDocumentThe document with
nodesreplacing their stored versions.
Paint、描边与样式
填充和描边接受一个 Paint:纯色、渐变或图片。每个 paint 都可以隐藏(visible: false),并可以与同一图层上位于其下方的 paint 混合(blendMode),与 Figma 相同;参见 PaintVisibility。VisualStyle 汇集了节点的填充、描边、圆角和效果。矩形和画框可以用 CornerRadii 单独设置每个角的圆角;styleCornerRadii 读取样式绘制时使用的四个半径。描边同样可以用 StrokeSides 给每条边单独设置粗细;strokeSideWeights 读取描边绘制时使用的四个粗细。
源码interface VisualStylereadonly styleId?: NodeStyleId源码readonly fills?: readonly Paint[]源码readonly strokes?: readonly Stroke[]自 0.5.0源码在填充之后绘制的有序描边,第一项位于最底层。
readonly cornerRadius?: number源码所有角共用的一个半径。矩形和画框在有
cornerRadii时改用它;多边形、星形和路径用这个半径给每个顶点倒圆角。readonly cornerRadii?: CornerRadii自 0.16.0源码矩形和画框各自独立的圆角半径。存在时在这些节点上代替
cornerRadius;其他形状忽略它。编辑器写入此字段时会清除cornerRadius,因此两者中只有一个描述圆角。readonly cornerSmoothing?: number自 0.9.0源码圆角平滑,取值从 0(圆形圆角)到 1(完全连续的曲率),与 Figma 相同。它只影响具有半径的圆角,每个平滑后的圆角最多占用
(1 + smoothing) * radius的边长。对于矩形,渲染器首先将半径 和平滑度 限制在预算 以内,然后计算圆角占用每条边的长度:
沿边进入圆角时,先由一段三次曲线平缓地离开该边,再由半径为 的圆弧转过 度,最后由一段镜像的三次曲线平缓地接入下一条边。设 度,圆弧在每条边上覆盖 ,三次曲线的控制距离为
因此 。当 时,它就是普通的四分之一圆。
readonly shadows?: readonly Shadow[]源码readonly layerBlur?: number自 0.7.0源码将节点及其后代作为一个图层整体应用的高斯模糊半径。
readonly backgroundBlur?: number自 0.7.0源码对节点形状后方的所有内容应用的高斯模糊半径。
自 0.16.0源码interface CornerRadii矩形或画框四个角各自的半径,与 Figma 的
topLeftRadius、topRightRadius、bottomRightRadius和bottomLeftRadius相同。每个半径都是非负的单位数;渲染器把每个半径限制在较短边的一半,与统一半径的限制相同,因此相邻的角不会重叠。readonly topLeft: number源码readonly topRight: number源码readonly bottomRight: number源码readonly bottomLeft: number源码
源码const CORNER_KEYS: readonly ["topLeft", "topRight", "bottomRight", "bottomLeft"]按 Figma 面板顺序排列的四个角:左上、右上、右下、左下。
源码type CornerKey = (typeof CORNER_KEYS)[number]矩形或画框的一个角,名称与
CornerRadii中的相同。
源码function styleCornerRadii( style: | Pick<VisualStyle, "cornerRadius" | "cornerRadii"> | undefined ): CornerRadii矩形或画框绘制时使用的半径:有
cornerRadii时取它,否则每个角都取统一的cornerRadius(缺省时为零)。
源码function uniformCornerRadii(radius: number): CornerRadii四个相等的半径。
源码function cornerRadiiAreUniform(radii: CornerRadii): boolean四个角半径相同时为 true。
源码function cornerRadiiAreRounded(radii: CornerRadii): boolean任一角有圆角时为 true。
源码function scaleCornerRadii(radii: CornerRadii, factor: number): CornerRadii把每个半径乘以
factor,与缩放工具的做法相同。
源码type Paint = SolidPaint | GradientPaint | ImagePaint
自 0.18.0源码interface PaintVisibility所有 paint 共有的字段,与 Figma 的
Paint相同:是否显示,以及如何与同一图层上位于其下方的 paint 混合。readonly visible?: boolean自 0.18.0源码为 false 时隐藏该 paint 而不删除它,如同 Figma 填充和描边列表中的眼睛按钮。默认为 true。
readonly blendMode?: BlendMode自 0.18.0源码该 paint 如何与同一图层上位于其下方的 paint 混合:填充下方的填充,或描边下方的填充和描边。使用与节点
blendMode相同的模式。默认为"normal"。
源码interface SolidPaint extends PaintVisibilityreadonly kind: "solid"源码readonly color: string源码readonly opacity?: number源码
源码type GradientPaint = | LinearGradientPaint | RadialGradientPaint | AngularGradientPaint
源码interface LinearGradientPaint extends PaintVisibilityreadonly kind: "linear-gradient"源码readonly angle: number源码readonly stops: readonly GradientStop[]源码readonly opacity?: number源码
自 0.6.0源码interface RadialGradientPaint extends PaintVisibility从中心点向外扩散的渐变。
readonly kind: "radial-gradient"源码readonly center?: PaintAnchor源码默认为边界的中心。
readonly radius?: PaintAnchor源码椭圆半径,以边界的比例表示;默认为宽度和高度的一半。
readonly stops: readonly GradientStop[]源码readonly opacity?: number源码
自 0.6.0源码interface AngularGradientPaint extends PaintVisibility围绕中心点旋转扫过的渐变。
readonly kind: "angular-gradient"源码readonly center?: PaintAnchor源码默认为边界框的中心。
readonly angle?: number源码起始角度,单位为度,从 x 轴正方向顺时针计算;默认为 0。
readonly stops: readonly GradientStop[]源码readonly opacity?: number源码
源码interface GradientStopreadonly offset: number源码readonly color: string源码
自 0.6.0源码interface PaintAnchor被绘制形状边界内的一个点,以其宽度和高度的比例表示。
readonly x: number源码readonly y: number源码
自 0.6.0源码interface ImagePaint extends PaintVisibility使用图片资源进行绘制。
readonly kind: "image"源码readonly assetId: AssetId源码readonly fit?: ImagePaintFit源码默认为 cover。
readonly opacity?: number源码
自 0.6.0源码type ImagePaintFit = "contain" | "cover" | "fill"图片绘制如何缩放到被绘制形状的边界中。
源码interface Strokereadonly paint: Paint源码readonly width: number源码每条边的粗细。有
sides时,编辑器让它保持为最大的一条边的粗细。readonly dash?: readonly number[]源码readonly position?: StrokePosition自 0.0.1源码旧的操作或文档省略此字段时默认为 center。
readonly sides?: StrokeSides自 0.17.0源码上、右、下、左四条边各自的粗细,在矩形和画框上代替
width。其他形状、连接线和代码块忽略它。粗细为 0 的边不绘制,粗细不同的边之间的角跟随形状的圆角。readonly join?: StrokeJoin自 0.22.0源码How the stroke turns a corner where two segments meet, as Figma’s
strokeJoin. Omitted keeps what the layer drew before 0.22.0: round on paths, ellipses, polygons, stars, lines and connectors, and on rectangles drawn as paths (rounded or with gradient, image or several fills); miter on frames, other rectangles and code blocks. SeedefaultStrokeJoin. Rectangles and frames with side weights ignore it.readonly miterAngle?: number自 0.22.0源码The miter angle in degrees, as Figma’s “Miter angle” (the REST API’s
strokeMiterAngle): a miter join whose corner is sharper than this is drawn beveled. Only a miter join uses it. It is more than 0 and at most 180; omitted isDEFAULT_STROKE_MITER_ANGLE, Figma’s default of about 28.96 degrees, which is a miter limit of 4 (limit = 1 / sin(angle / 2)).readonly dashCap?: DashCap自 0.22.0源码The ends of every dash of a dashed stroke, as Figma’s “Dash cap”. None stops a dash flat; round and square extend it by half the stroke width. Omitted keeps what the layer drew before 0.22.0: round on the layers whose join defaults to round, none on the others (see
defaultDashCap). A solid stroke ignores it.
自 0.0.1源码type StrokePosition = "center" | "inside" | "outside"描边绘制在轮廓的哪一侧。
自 0.17.0源码interface StrokeSides矩形或画框四条边的描边粗细。Figma 每个节点只保存一组边粗细,这里则是
VisualStyle.strokes中的每个描边各自携带一组。readonly top: number源码readonly right: number源码readonly bottom: number源码readonly left: number源码
源码const STROKE_SIDE_KEYS: readonly ["top", "right", "bottom", "left"]按 wire 格式和面板所用顺序排列的四条描边边。
源码type StrokeSideKey = (typeof STROKE_SIDE_KEYS)[number]描边的一条边,名称与
StrokeSides中的相同。
源码function strokeSideWeights(stroke: Pick<Stroke, "width" | "sides">): StrokeSides描边绘制时每条边的粗细:
sides,或四条边都取width。
源码function widestStrokeSide(sides: StrokeSides): number四条边粗细中的最大值。
源码type StrokeCap = (typeof STROKE_CAPS)[number]
自 0.12.0源码const STROKE_CAPS: readonly [ "none", "round", "square", "line-arrow", "triangle-arrow", "reversed-triangle", "circle-arrow", "diamond-arrow" ]译文已过期
Stroke end caps as Figma names them. None ends the stroke flat at the endpoint; round and square extend it by half the stroke width; the arrow caps draw a head in the stroke’s paint whose size follows the stroke width. Lines and connectors share these end styles and draw them the same way. Heads are always solid, even on a dashed stroke.
A stroke also sets how its corners join, how each dash of a dashed stroke ends, and the miter angle below which a miter join is beveled, as in Figma’s Stroke settings. A stroke that sets none of these draws as layers did before schema 0.22.0: defaultStrokeJoin and defaultDashCap give those defaults. Figma sets a miter angle where Skia takes a miter limit; miterLimitFromAngle and miterAngleFromLimit convert between them. Only an open path with one unbranched chain of segments takes end points (openPathChain).
源码type StrokeJoin = (typeof STROKE_JOINS)[number]How a stroke’s corners join: sharp (miter), cut off (bevel) or round.
自 0.22.0源码const STROKE_JOINS: readonly ["miter", "bevel", "round"]The stroke joins, as Figma names them (
MITER,BEVEL,ROUND).
源码type DashCap = (typeof DASH_CAPS)[number]How each dash of a dashed stroke ends: flat at the dash (none), round or square.
自 0.22.0源码const DASH_CAPS: readonly ["none", "round", "square"]The ends of each dash of a dashed stroke, as in Figma’s Dash cap menu.
自 0.22.0源码const DEFAULT_STROKE_MITER_ANGLE: numberFigma’s default miter angle in degrees, 2 * asin(1 / 4): the angle at which a miter limit of 4 bevels.
源码function strokeMiterAngle(stroke: Pick<Stroke, "miterAngle">): numberA stroke’s miter angle, or Figma’s default when it has none.
自 0.22.0源码function miterLimitFromAngle(angle: number): numberThe miter limit a miter angle gives, as SVG and Skia use it: the longest a miter may be, as a multiple of half the stroke width, before the join is beveled. A corner sharper than
angledegrees has a longer miter.
源码function miterAngleFromLimit(limit: number): numberThe miter angle, in degrees, that a miter limit of at least 1 gives.
自 0.22.0源码function defaultStrokeJoin( node: SceneNode, style: VisualStyle | undefined ): StrokeJoinThe join a stroke of
nodedraws with when it names none: what the layer drew before schema 0.22.0, round on layers stroked along a path and miter on layers stroked around a box.styleis the layer’s resolved style.
自 0.22.0源码function defaultDashCap( node: SceneNode, style: VisualStyle | undefined ): DashCapThe dash ends a dashed stroke of
nodedraws with when it names none: round on layers stroked along a path and none on layers stroked around a box, as before schema 0.22.0.
源码const DEFAULT_PATH_STROKE_CAP: StrokeCapThe end style an open path draws when it names none: round, as before 0.22.0.
自 0.22.0源码function openPathChain(network: VectorNetwork): readonly VectorSegment[] | nullThe segments of
networkwhen they form one open chain in order: each segment starts where the one before it ends, and the first segment’s start and the last segment’s end are each touched by that segment only. Only such a path takes end points (PathNode.startCapandendCap). Returns null for a closed, branched or empty network.
源码interface Shadowreadonly kind?: ShadowKind自 0.7.0源码旧文档省略此字段时默认为投影。
readonly x: number源码readonly y: number源码readonly blur: number源码readonly spread: number源码readonly color: string源码
自 0.7.0源码type ShadowKind = "drop" | "inner"
矢量网络
路径保存一个可编辑的矢量网络:顶点、顶点之间的线段、可选的切线约束,以及由有向环构成的填充区域。SVG 路径数据只是一种交换格式。
自 0.2.0源码interface VectorNetwork构成路径形状的顶点、线段和填充区域。
readonly vertices: readonly VectorVertex[]源码readonly segments: readonly VectorSegment[]源码readonly constraints?: readonly VectorTangentConstraint[]源码省略时等同于空的约束列表。
readonly regions: readonly VectorRegion[]源码按绘制顺序从后到前排列。
自 0.2.0源码interface VectorVertexVectorNetwork中的一个点,使用网络坐标。readonly id: VectorVertexId源码readonly x: number源码readonly y: number源码readonly cornerRadius?: number自 0.10.0源码该顶点处的圆角半径,覆盖节点样式的圆角半径。只有恰好连接两条线段的顶点才会被圆角化;渲染器会将半径限制为相邻较短线段长度的一半。
自 0.2.0源码type VectorSegment = | VectorLineSegment | VectorCubicSegment | VectorEllipticalArcSegmentVectorNetwork中两个顶点之间的边。
源码interface VectorLineSegment extends VectorSegmentBasereadonly kind: "line"源码
源码interface VectorCubicSegment extends VectorSegmentBasereadonly kind: "cubic"源码readonly startHandle: VectorHandle源码readonly endHandle: VectorHandle源码
源码interface VectorEllipticalArcSegment extends VectorSegmentBase用于精确迁移和 SVG 互转的兼容几何。编辑器最初只创建并直接编辑直线段和三次曲线段。
readonly kind: "elliptical-arc"源码readonly radiusX: number源码readonly radiusY: number源码readonly xAxisRotation: number源码readonly largeArc: boolean源码readonly sweep: boolean源码
源码interface VectorHandlereadonly id: VectorHandleId源码readonly dx: number源码控制点相对于线段端点的水平偏移。
readonly dy: number源码控制点相对于线段端点的垂直偏移。
源码interface VectorTangentConstraint将交汇于同一顶点的两个端点控制柄关联起来。成对的约束让分支网络能够描述彼此独立的平滑延续,而不必为整个顶点指定一种含糊的平滑模式。
readonly vertexId: VectorVertexId源码readonly handleIds: readonly [VectorHandleId, VectorHandleId]源码readonly mode: "angle" | "angle-and-length"源码仅镜像角度,或同时镜像角度和控制柄长度。
自 0.2.0源码interface VectorRegionVectorNetwork中的一块填充区域,由线段组成的环围成。readonly id: VectorRegionId源码readonly windingRule: "nonzero" | "evenodd"源码readonly loops: readonly VectorRegionLoop[]源码readonly fills?: readonly Paint[]源码省略时继承路径解析后的填充;空数组表示禁用填充。
源码interface VectorRegionLoopreadonly segments: readonly VectorSegmentReference[]源码readonly implicitClose?: true源码为填充而闭合一条开放的链,但不添加或描边另一条边,与 SVG 对开放子路径的隐式填充闭合一致。
源码interface VectorSegmentReferencereadonly segmentId: VectorSegmentId源码readonly direction: "forward" | "reverse"源码
源码type VectorWindingRule = VectorRegion["windingRule"]
源码function vectorNetworkFromSvgPathData( pathData: string, windingRule: VectorWindingRule = "nonzero" ): VectorNetwork将 SVG 路径转换为确定性的、节点局部的矢量网络拓扑。相对命令、简写命令、水平命令、垂直命令和二次曲线命令会被规范化。椭圆弧保留为精确的兼容线段。
源码function vectorRegionToSvgPathData( network: VectorNetwork, region: VectorRegion ): string
源码function vectorRegionPathDataById( network: VectorNetwork, regionId: string ): string | undefined投影第一个匹配的区域,适合保留了区域 ID 的调用方使用。
源码function vectorNetworkToStrokePathData(network: VectorNetwork): string将网络中的每条边各投影一次,用于与 SVG 兼容的描边和边界计算。区域环会尽可能保留作者绘制的链;其余的图边会成为独立的子路径,因为 SVG 无法表示分支连接。
源码function transformVectorPoint( x: number, y: number, transform: TransformMatrix ): { readonly x: number; readonly y: number }
源码function scaleVectorNetwork( network: VectorNetwork, scale: { readonly x: number; readonly y: number }, anchor: { readonly x: number; readonly y: number } ): VectorNetwork译文已过期
Scales a vector network in its own coordinate space around one anchor. An elliptical arc keeps its exact shape: see
scaleEllipticalArc.
源码function assertValidPathData(pathData: string): void
源码function isClosedPathData(pathData: string): boolean当每个子路径都闭合回到其起点时返回
true。
文本
文本节点保存由带样式的文本片段(run)组成的段落。每个文本片段指明一个主题 TextStyle,并可带有直接覆盖;段落则添加对齐、间距、缩进和列表标记。
源码interface TextParagraphTextNode的一个段落:其文本片段加上段落级布局。readonly runs: readonly TextRun[]源码readonly direction?: "auto" | "ltr" | "rtl"源码省略或显式设置为 auto 时,根据段落内容确定书写方向。
readonly align?: "left" | "center" | "right" | "justify"源码readonly spacingBefore?: number源码readonly spacingAfter?: number源码readonly indent?: { readonly left: number; readonly right: number; readonly firstLine: number; }源码readonly list?: { readonly kind: "ordered" | "unordered"; readonly level: number; readonly start?: number; readonly marker?: TextListMarker; }源码使该段落成为列表项。
源码interface TextRun共享同一样式的一段文本。
readonly text: string源码readonly styleId?: TextStyleId源码主题文本样式;省略时为主题的
defaultTextStyleId。readonly overrides?: TextStyleOverrides源码在样式之上直接应用的格式。
源码interface TextListMarker显示在列表段落前的项目符号或编号,及其样式。
readonly text?: string源码自定义标记文本;提供时不能为空。
readonly styleId?: TextStyleId源码readonly overrides?: TextStyleOverrides源码readonly gap?: number源码标记与段落文本之间的间距。非负。
源码interface TextStylereadonly name: string源码readonly fontFamily: string源码readonly fontAssetId?: AssetId源码readonly fontFallbackAssetIds?: readonly AssetId[]源码在
fontAssetId之后按顺序尝试的嵌入字体资源。readonly language?: string源码readonly fontSize: number源码readonly fontWeight: number源码readonly lineHeight: number源码readonly letterSpacing?: number源码readonly color: string源码readonly italic?: boolean源码readonly underline?: boolean源码readonly strikethrough?: boolean自 0.2.0源码在文本中间绘制一条删除线。
readonly openTypeFeatures?: Readonly<Record<string, boolean | number>>自 0.2.0源码相对于字体 OpenType 特性默认值的显式调整。
readonly fontVariations?: Readonly<Record<string, number>>自 0.2.0源码
自 0.2.1源码type TextStyleOverrides = & Partial<Omit<TextStyle, "name" | "fontAssetId" | "fontFallbackAssetIds">> & { readonly fontAssetId?: AssetId | null; readonly fontFallbackAssetIds?: readonly AssetId[]; }在单个文本片段或列表标记上直接设置的文本格式。
字体资源需要明确的清除语义,因为省略某个覆盖项会继承所选主题样式。将主字体设为
null会清除继承的fontAssetId,而空的回退列表会清除继承的回退字体。
源码function assertTextStyleOverrides( value: unknown ): asserts value is TextStyleOverrides校验一个独立的、由作者设置的文本片段或列表标记的文本样式覆盖。
源码const MAX_TEXT_FONT_FALLBACK_ASSETS: 4095规范上限;保留文本还另外携带一个主字体资源。
自 0.2.0源码type OpenTypeTag = Brand<string, "OpenTypeTag">由四个字符组成的 OpenType 特性标签或轴标签。使用
openTypeTag创建。
源码function openTypeTag(value: string): OpenTypeTag
资源与字体
图片、视频和字体存放在文档的资源映射中,通过 AssetId 引用。字体来自 Google Fonts(GoogleFontsSource)或电脑上安装的字体(LocalFontSource);本地字体只记下名称,其文件从不存入文档。
源码type Asset = ImageAsset | VideoAsset | FontAsset存储在
DesignDocument.assets中的文件,通过其kind字段区分类型。
源码interface ImageAssetImageNode和ImagePaint使用的图片文件。readonly id: AssetId源码与该资源在
DesignDocument.assets中的键一致。readonly kind: "image"源码readonly mimeType: string源码readonly source: AssetSource源码readonly width?: number源码固有宽度(像素),已知时提供。
readonly height?: number源码固有高度(像素),已知时提供。
源码interface VideoAssetVideoNode使用的视频文件。readonly id: AssetId源码与该资源在
DesignDocument.assets中的键一致。readonly kind: "video"源码readonly mimeType: string源码readonly source: AssetSource源码readonly width?: number源码固有宽度(像素),已知时提供。
readonly height?: number源码固有高度(像素),已知时提供。
源码interface FontAsset一个字体字面(font face),由
TextStyle.fontAssetId、TextStyle.fontFallbackAssetIds和CodeStyle.fontAssetId引用。readonly id: AssetId源码与该资源在
DesignDocument.assets中的键一致。readonly kind: "font"源码readonly mimeType: string源码来源为 Google Fonts 时必须为
font/woff2,来源为本地字体时必须为font/ttf或font/otf。readonly source: FontAssetSource源码readonly family: string源码readonly weight: number源码取值 1 到 1000,与 CSS
font-weight相同。readonly style: "normal" | "italic" | "oblique"源码
源码type AssetSource = | { readonly kind: "url"; readonly url: string } | { readonly kind: "data"; readonly data: string }资源字节的来源:一个 URL,或存储在文档中的数据。
自 0.13.0源码type FontAssetSource = AssetSource | GoogleFontsSource | LocalFontSource字体文件的来源。
自 0.13.0源码interface GoogleFontsSource由 Google Fonts 以许多小型 WOFF2 文件提供的字体族,每个文件覆盖 Unicode 的一部分(由 Google Fonts CSS 中的
unicode-range声明)。应用为每个内置字体族保存文件列表,只加载包含文档所用字符的文件。readonly kind: "google-fonts"源码readonly family: string源码Google Fonts 字体族名称,例如“Noto Sans SC”。
自 0.19.0源码interface LocalFontSource选择该字体的人的电脑上安装的字体,通过浏览器的本地字体访问 API(
window.queryLocalFonts())读取。文档只记下字体名称而不携带字体文件,因此一台电脑上安装的字体列表不会进入文档;只有文档中文本用到的字体才会被记下。在没有安装该字体的电脑上,应用会把这段文本显示为使用了缺失的字体。readonly kind: "local"源码readonly family: string源码已安装字体的字体族名称,例如 “Helvetica Neue”。
readonly postScriptName: string源码字面的 PostScript 名称,用于在已安装的字体中识别它。
readonly styleName: string源码已安装字体的样式名称,例如 “Bold Italic”。
readonly sha256: string源码字面字体文件的 SHA-256,为 64 位小写十六进制数字。PostScript 名称相同但字节不同的已安装字面是该字体的另一个版本,排版结果可能不同。
主题、样式与变量
主题保存共享的节点样式、文本样式和代码样式、命名颜色以及变量集合。节点可以把受支持的属性绑定到变量;绑定的值同时也写在节点上,因此解除绑定后外观保持不变。
源码interface DocumentTheme文档共享的样式、命名颜色和变量。节点通过 ID 引用它们,并可以在其上保留直接覆盖的值。
readonly defaultTextStyleId: TextStyleId源码未指定文本样式的文本片段所使用的文本样式。
readonly defaultCodeStyleId: CodeStyleId源码未指定代码样式的代码节点所使用的代码样式。
readonly colors: Readonly<Record<string, string>>源码命名颜色,以名称为键。
readonly nodeStyles: Readonly<Record<string, NodeStyle>>源码readonly textStyles: Readonly<Record<string, TextStyle>>源码readonly codeStyles: Readonly<Record<string, CodeStyle>>源码readonly variableCollections?: Readonly<Record<string, VariableCollection>>源码存储在本文档中的变量集合。跨文档共享的库有意不在支持范围内。
源码interface NodeStyle extends Omit<VisualStyle, "styleId">readonly name: string源码
源码interface CodeStyle提供调色板颜色,以及新建代码节点时使用的默认排版设置。
readonly name: string源码readonly fontFamily: string源码readonly fontAssetId?: AssetId源码readonly fontSize: number源码readonly lineHeight: number源码readonly letterSpacing?: number自 0.1.2源码字符之间额外增加的间距。
readonly background: string源码readonly foreground: string源码readonly syntax: Readonly<Record<string, string>>源码
源码interface VariableCollectionreadonly name: string源码readonly defaultModeId: VariableModeId源码readonly activeModeId?: VariableModeId源码译文已过期
The mode this document shows where no page or layer chooses one (see
VariableModes). It defaults todefaultModeIdwhen omitted.readonly modeOrder: readonly VariableModeId[]源码readonly modes: Readonly<Record<string, VariableMode>>源码readonly variables: Readonly<Record<string, VariableDefinition>>源码
源码interface VariableModereadonly name: string源码
源码type VariableDefinition = | VariableDefinitionBase<"color", string> | VariableDefinitionBase<"number", number> | VariableDefinitionBase<"string", string> | VariableDefinitionBase<"boolean", boolean>
源码type VariableType = "color" | "number" | "string" | "boolean"
源码type VariableValue = string | number | boolean
源码type VariableProperty = | "visibility" | "opacity" | "width" | "height" | "cornerRadius" | "fillColor" | "strokeColor" | "strokeWidth" | "gap" | "wrapGap" | "columnGap" | "rowGap" | "paddingTop" | "paddingRight" | "paddingBottom" | "paddingLeft" | "fontFamily" | "fontSize" | "fontWeight" | "lineHeight" | "letterSpacing" | "textColor"
源码type VariableBindings = Readonly<Partial<Record<VariableProperty, VariableId>>>
源码const VARIABLE_PROPERTY_TYPES: Readonly<Record<VariableProperty, VariableType>>
源码interface LocatedVariablereadonly collectionId: string源码readonly collection: VariableCollection源码readonly variableId: VariableId源码readonly variable: VariableDefinition源码
源码function findVariable( theme: DocumentTheme, variableId: VariableId | string ): LocatedVariable | undefined
源码function resolveVariableValue( theme: DocumentTheme, variableId: VariableId | string, modes?: VariableModes ): VariableValue | undefinedThe variable’s value in the mode its collection shows under
modes(the modes in effect at a layer, seevariableModesAt): the inherited choice, else the collection’s active mode, else its default mode. A mode without a value reads the default mode’s value.
源码function listVariablesForProperty( theme: DocumentTheme, property: VariableProperty ): readonly LocatedVariable[]
源码function variableSupportsProperty( variable: VariableDefinition, property: VariableProperty ): boolean
源码function nodeSupportsVariableProperty( node: SceneNode, property: VariableProperty ): boolean
### Variable modes
A page, frame, group, component or instance can choose a mode per variable collection in variableModes. A collection it leaves out is Auto: the layer inherits the mode from its parent, up to the page, and a page without one uses the collection’s activeModeId. An instance’s modes apply to its component’s layers. Stored bound values are written for the active modes; the resolver and the page compiler write them again for layers under other modes.
自 0.26.0源码type VariableModes = Readonly<Record<string, VariableModeId>>A variable mode per collection, keyed by collection ID. A collection left out is Auto: the layer takes the mode of its parent, up to the page, and a page without one uses the collection’s
activeModeId(else itsdefaultModeId). Omitted when empty.
自 0.26.0源码function inheritVariableModes( parent: VariableModes | undefined, own: VariableModes | undefined ): VariableModes | undefinedThe modes a layer uses: its parent’s modes with the layer’s own choices on top. A collection the layer leaves out (Auto) keeps the parent’s mode. Returns
parentitself whenownchooses nothing.
自 0.26.0源码function variableModeFor( collectionId: string, collection: VariableCollection, modes?: VariableModes ): VariableModeIdThe mode a collection shows under
modes: the inherited choice, else the collection’sactiveModeId, else itsdefaultModeId.
自 0.26.0源码function variableModesAt( document: DesignDocument, nodeId: NodeId ): VariableModes | undefinedThe modes in effect at a stored node: the page’s modes, then each ancestor’s, then the node’s own. A layer of a component (outside any page) starts from the document’s active modes at the component root; an instance applies its own modes on top when it is resolved. Undefined means every collection shows its active mode.
自 0.26.0源码function inheritedVariableModes( document: DesignDocument, nodeId: NodeId ): VariableModes | undefinedThe modes a stored node inherits:
variableModesAtits parent, or the page’s modes for a page root. The node’s own choices are not included.
自 0.26.0源码function locatedVariableValue( located: LocatedVariable, modes?: VariableModes ): VariableValue | undefinedresolveVariableValuefor a variable already found withfindVariable.
自 0.26.0源码function applyVariableBindings( document: DesignDocument, node: SceneNode, modes: VariableModes | undefined ): SceneNodeWrites each of the node’s variable bindings in the modes
modesinto the bound field (seewithVariableValue). A binding to a missing variable, or one the node cannot take, is skipped. A text layer that sizes itself is measured again. Returnsnodeitself when it has no bindings.
自 0.26.0源码function withVariableValue( theme: DocumentTheme, node: SceneNode, property: VariableProperty, value: VariableValue ): SceneNodeWrites one variable value into the node field it is bound to, the way the editor does when a variable is applied: a color drives the bottom fill or the first stroke, a radius sets every corner, a text property restyles every run. Sizes and opacity are clamped. A value of the wrong type changes nothing.
自 0.26.0源码function bindingsDependOnModes( theme: DocumentTheme, node: SceneNode, modes: VariableModes | undefined ): booleanWhether a node’s variable bindings read any collection in a mode other than its active mode under
modes. Stored values are written for the active modes, so only such a node needsapplyVariableBindings.
自 0.26.0源码function variableModesKey( theme: DocumentTheme, modes: VariableModes | undefined ): stringA stable text form of
modesfor cache keys: the collections in sorted order. Modes that match a collection’s active mode are left out, so Auto and an explicit choice of the active mode give the same key.
ID
ID 是带品牌标记的字符串(branded string):运行时就是普通字符串,但类型系统会阻止把一种 ID 当作另一种使用。每种 ID 都有一个构造函数,会拒绝空字符串。
源码type DocumentId = Brand<string, "DocumentId">带品牌的字符串 ID。运行时它们都是普通字符串,但品牌可以防止把一种 ID 传到需要另一种 ID 的地方。请用对应的构造函数创建,例如
nodeId,它会拒绝空字符串。
源码const documentId: (value: string) => DocumentId把字符串标记为
DocumentId品牌类型。空字符串会抛出TypeError。
源码type PageId = Brand<string, "PageId">Page的 ID。
源码const pageId: (value: string) => PageId
源码type NodeId = Brand<string, "NodeId">SceneNode的 ID。
源码const nodeId: (value: string) => NodeId
源码type AssetId = Brand<string, "AssetId">Asset的 ID。
源码const assetId: (value: string) => AssetId
源码type NodeStyleId = Brand<string, "NodeStyleId">DocumentTheme.nodeStyles中某个NodeStyle的 ID。
源码const nodeStyleId: (value: string) => NodeStyleId将字符串标记(brand)为
NodeStyleId类型。对空字符串抛出TypeError。
源码type TextStyleId = Brand<string, "TextStyleId">DocumentTheme.textStyles中某个TextStyle的 ID。
源码const textStyleId: (value: string) => TextStyleId将字符串标记(brand)为
TextStyleId类型。对空字符串抛出TypeError。
源码type CodeStyleId = Brand<string, "CodeStyleId">DocumentTheme.codeStyles中某个CodeStyle的 ID。
源码const codeStyleId: (value: string) => CodeStyleId把字符串标记为
CodeStyleId品牌类型。空字符串会抛出TypeError。
源码type VariableCollectionId = Brand<string, "VariableCollectionId">VariableCollection的 ID。
源码const variableCollectionId: (value: string) => VariableCollectionId将字符串标记(brand)为
VariableCollectionId类型。对空字符串抛出TypeError。
源码type VariableModeId = Brand<string, "VariableModeId">VariableMode在其所属集合中的 ID。
源码const variableModeId: (value: string) => VariableModeId将字符串标记(brand)为
VariableModeId类型。对空字符串抛出TypeError。
源码type VariableId = Brand<string, "VariableId">VariableDefinition的 ID。
源码const variableId: (value: string) => VariableId将字符串标记(brand)为
VariableId类型。对空字符串抛出TypeError。
源码type CommitId = Brand<string, "CommitId">DocumentStore中某个CommitRecord的 ID。
源码const commitId: (value: string) => CommitId
自 0.2.0源码type VectorVertexId = Brand<string, "VectorVertexId">VectorVertex的 ID。
源码const vectorVertexId: (value: string) => VectorVertexId将字符串标记(brand)为
VectorVertexId类型。对空字符串抛出TypeError。
自 0.2.0源码type VectorSegmentId = Brand<string, "VectorSegmentId">VectorSegment的 ID。
源码const vectorSegmentId: (value: string) => VectorSegmentId将字符串标记(brand)为
VectorSegmentId类型。对空字符串抛出TypeError。
自 0.2.0源码type VectorHandleId = Brand<string, "VectorHandleId">VectorHandle的 ID。
源码const vectorHandleId: (value: string) => VectorHandleId将字符串标记(brand)为
VectorHandleId类型。对空字符串抛出TypeError。
自 0.2.0源码type VectorRegionId = Brand<string, "VectorRegionId">VectorRegion的 ID。
源码const vectorRegionId: (value: string) => VectorRegionId将字符串标记(brand)为
VectorRegionId类型。对空字符串抛出TypeError。
加载与保存
deserializeDocument 对文档进行迁移、校验和冻结;serializeDocument 把它写回为键已排序的 JSON。每种失败都是一个带有错误码和 JSON 路径的 ModelError。
源码function deserializeDocument( input: string | unknown, migrations: MigrationRegistry = defaultMigrations ): DesignDocument从 JSON 字符串或已解析的值加载文档。
依次运行
migrations直到CURRENT_DOCUMENT_SCHEMA_VERSION,用assertDocument校验结果,把每个编组重新适配到其子节点的范围(这会修复以过时编组尺寸保存的文件),并返回一个深度冻结的副本。输入不会被修改。抛出
ModelError:字符串无法解析时为INVALID_JSON,也可能是迁移错误码(见MigrationRegistry.migrate)或校验错误。
源码function serializeDocument(document: DesignDocument, indentation = 0): string使用
assertDocument校验document,并以键排序的 JSON 写出,因此同一文档总是得到相同的文本。indentation会传给JSON.stringify;为 0 时写成一行。
源码function snapshotDocument(input: DesignDocument | unknown): DesignDocument返回经过校验且深度冻结的文档副本。等同于使用默认迁移的
deserializeDocument。
源码function assertDocument(value: unknown): asserts value is DesignDocument检查
value是否为CURRENT_DOCUMENT_SCHEMA_VERSION版本下有效的DesignDocument:包括每个实体的结构、节点树(每个节点恰好能从一个页面到达,没有环,也没有共享的子节点)、页面顺序,以及样式、变量、连接线、媒体节点和字体的引用。它不做迁移;较旧的数据请使用deserializeDocument。抛出的
ModelError会指明发现的第一个问题。
源码function assertSceneNode(value: unknown): asserts value is SceneNode单独检查一个节点的结构。不检查对其他节点、样式和资源的引用。失败时抛出
ModelError。
源码function assertDocumentTheme(value: unknown): asserts value is DocumentTheme单独检查一个主题的结构。失败时抛出
ModelError。
源码function assertAsset(value: unknown): asserts value is Asset单独检查一个资源的结构。失败时抛出
ModelError。
源码class ModelError extends Error本包在数据无效和编辑被拒绝时抛出的错误。消息以
at <path>结尾。new ( readonly code: ModelErrorCode, message: string, readonly path = "$", options?: ErrorOptions )源码
源码type ModelErrorCode = | "INVALID_JSON" | "INVALID_SCHEMA" | "INVALID_TREE" | "UNSUPPORTED_VERSION" | "MISSING_MIGRATION" | "MIGRATION_FAILED" | "NOT_IMPLEMENTED"ModelError报告的问题类型:INVALID_JSON:输入字符串不是 JSON,或某个值不是纯 JSON(包含undefined、非有限数字、循环引用或类实例)。INVALID_SCHEMA:某个值的结构错误、含有未知属性或数字超出范围。被拒绝的操作和 store 调用也使用此代码。INVALID_TREE:值的格式正确,但其引用之间不匹配:缺失或被共享的子节点、循环、不可达的节点,或者缺失的样式、变量、资源或提交。UNSUPPORTED_VERSION:数据比本包支持的版本更新。MISSING_MIGRATION:没有从该数据版本出发的迁移步骤。MIGRATION_FAILED:某个迁移步骤抛出了异常或产生了错误的版本。
较旧的文档在校验前会经过一串迁移步骤升级。
源码class MigrationRegistry由
DocumentMigration步骤组成的有序链。除非另行传入注册表,deserializeDocument和deserializeStore使用defaultMigrations。new (migrations: readonly DocumentMigration[] = [])源码register(migration: DocumentMigration): this源码添加一个步骤并返回该注册表。如果该步骤没有按
DocumentMigration.to所述向前推进版本,或者已注册了从同一版本出发的步骤,则抛出代码为INVALID_SCHEMA的ModelError。migrateOperation( operation: unknown, from: DocumentSchemaVersion, target: DocumentSchemaVersion = CURRENT_DOCUMENT_SCHEMA_VERSION ): unknown源码使用与文档相同的有序步骤,把一条已存储的操作从其记录时的版本迁移到当前版本。没有
migrateOperation的步骤会原样传递该操作。当某个步骤返回null时返回null。migrate( input: unknown, target: DocumentSchemaVersion = CURRENT_DOCUMENT_SCHEMA_VERSION ): unknown源码从输入的
schemaVersion开始依次运行各步骤直到target,并以纯 JSON 形式返回结果。它不会校验结果。抛出
ModelError:输入比target新时为UNSUPPORTED_VERSION;途中某个版本没有对应的起始步骤时为MISSING_MIGRATION;某个步骤抛出异常或写入了错误的版本时为MIGRATION_FAILED。
源码interface DocumentMigration把文档从一个 schema 版本升级到下一个版本的一个步骤。请在
MigrationRegistry中注册这些步骤。readonly from: DocumentSchemaVersion源码此步骤读取的版本。每个版本只能有一个从它开始的步骤。
readonly to: DocumentSchemaVersion源码此步骤写出的版本:对旧式数字版本为
from + 1,从旧式版本 1 升级时为"0.0.0",否则为一个更新的语义化版本。migrate(input: unknown): unknown源码以纯 JSON 返回升级后的文档,并把
schemaVersion设为to。输入是私有副本,可以直接原地修改。migrateOperation?(operation: unknown): unknown源码把一个已存储的操作迁移过同一个版本步骤。
已存储的历史在操作中保存了完整的节点、页面、主题和资源,因此这些结构中任何一个发生变化,都会让已记录的操作过时。只要
migrate改写了操作可能携带的内容,就应提供此函数;如果变化只涉及没有任何操作会包含的文档级字段,则可以省略。操作以纯 JSON 形式传入。原样返回没有问题,返回一个不再改变文档的操作也没有问题:该提交会被丢弃,而它的子提交在历史中保持原位。
源码const defaultMigrations: MigrationRegistry此包自带的迁移:每个 schema 版本一步,从旧式版本 1 到
0.0.0,再到之后直至CURRENT_DOCUMENT_SCHEMA_VERSION的每个版本。以没有对应迁移步骤的版本保存的数据会以MISSING_MIGRATION失败。
源码function readDocumentSchemaVersion( value: unknown, path: string ): DocumentSchemaVersion检查
value是否为文档 schema 版本:非负整数(旧格式)或major.minor.patch字符串。原样返回该值。否则在path处抛出代码为INVALID_SCHEMA的ModelError。
源码function compareDocumentSchemaVersions( left: DocumentSchemaVersion, right: DocumentSchemaVersion ): number比较两个 schema 版本的先后,返回 -1、0 或 1。语义化版本逐段比较。旧式数字版本 0 和 1 排在所有语义化版本之前,更大的数字排在其后。版本字符串格式错误时抛出
TypeError。
这些辅助函数适用于任意普通 JSON 值。
源码type JsonValue = | JsonPrimitive | readonly JsonValue[] | { readonly [key: string]: JsonValue }任意 JSON 值。用于自由格式的
metadata字段。
源码type JsonPrimitive = string | number | boolean | nullJSON 标量:字符串、有限数字、布尔值或
null。
源码function canonicalJson(value: unknown, indentation = 0): string序列化一个 JSON 值,并对对象的键排序,使相等的值得到相同的文本。如果
value不是纯 JSON(例如undefined、NaN或类实例),抛出ModelError。
源码function cloneJson<Value>(value: Value): Value深拷贝一个纯 JSON 值。如果它不是纯 JSON,抛出
ModelError。
源码function deepFreeze<Value>(value: Value): Readonly<Value>冻结一个值及其包含的所有内容。
已冻结的对象会被视为整体都已深度冻结,因为此包只通过这个函数冻结值。如果没有这条规则,每次编辑后重新冻结文档都要遍历所有节点。
Schema 历史
对存储的文档结构的每次改动都会提升 schema 版本,并新增一个迁移步骤。下表由这些步骤生成,最新的在前:摘要是 codec.ts 中每个步骤上方的注释,提交是引入该版本字符串的那次提交。标注了引入版本的类型和字段列在对应行下方,并在其文档处带有“since”徽标。
defaultMigrations 中每个迁移步骤对应一行;编解码器可以迁移版本 1 及之后的文档。摘要取自 codec.ts 中每个步骤上方的注释;提交信息来自对版本字符串执行的 git log -S。
操作
每次编辑都是一组 DocumentOperation。applyOperations 要么全部应用,要么全部不应用,并返回新文档、用于撤销它的操作,以及一个指明改动内容的 ChangeSet。
源码function applyOperations( input: DesignDocument, operations: readonly DocumentOperation[] ): ApplyOperationsResult译文已过期
Applies
operationsin order and returns the new document, the inverse operations, and aChangeSet. It never changes the input.After the operations run, every group that contains a changed node, at any depth, is refitted to its children, and a group left with no children is removed; the inverse operations undo that too. A connector end attached to a node that is gone after that (a removed node, anything inside it, or such a group) becomes a free end at the
xandyit has, so removing a connector’s target is never refused; the inverse operations attach the end again. Then every changed node, and every instance of a component whose root’s sizing changed, loses a stretching constraint (Left and right, Top and bottom, Scale) on an axis it hugs: it becomes Left or Top, and the inverse operations put it back. That is done only where the operations bring it: an axis of a node that already hugged and stretched in the input document (one stored before this rule) is left as the operations write it. The result is then validated. A document that is not frozen is first validated and copied withsnapshotDocument.All or nothing: if any operation does not fit the document, or the result is invalid, it throws a
ModelErrorand returns nothing.
源码interface ApplyOperationsResultapplyOperations的返回值。readonly document: DesignDocument源码新的、深度冻结的文档;没有任何变化时为输入文档本身。
readonly inverseOperations: readonly DocumentOperation[]源码译文已过期
Operations that turn
documentback into the input, already in the order to apply them. Empty when nothing changed.One exception: when the input held a node with a stretching constraint on an axis it hugs (a document stored before
applyOperationskept that rule) and the operations themselves repaired that axis or removed the node, these operations bring it back with Left or Top on that axis.readonly changes: ChangeSet源码
源码type DocumentOperation = | { readonly type: "document.set-title"; readonly title: string } | { readonly type: "document.set-metadata"; readonly metadata: Readonly<Record<string, JsonValue>> | null; } | { readonly type: "node.insert"; readonly parentId: NodeId; readonly index: number; readonly subtree: SerializedSubtree; } | { readonly type: "node.remove"; readonly nodeId: NodeId } | { readonly type: "node.move"; readonly nodeId: NodeId; readonly newParentId: NodeId; readonly index: number; } | { readonly type: "node.replace"; readonly node: SceneNode } | { readonly type: "page.insert"; readonly index: number; readonly page: Page; readonly subtree: SerializedSubtree; } | { readonly type: "page.remove"; readonly pageId: PageId } | { readonly type: "page.move"; readonly pageId: PageId; readonly index: number; } | { readonly type: "page.replace"; readonly page: Page } | { readonly type: "theme.replace"; readonly theme: DocumentTheme } | { readonly type: "asset.put"; readonly asset: Asset } | { readonly type: "asset.remove"; readonly assetId: AssetId } | { readonly type: "component.insert"; readonly component: ComponentDefinition; readonly subtree: SerializedSubtree; } | { readonly type: "component.remove"; readonly componentId: ComponentId } | { readonly type: "component.replace"; readonly component: ComponentDefinition; }译文已过期
One edit to a document. Every change goes through these operations, so each can be recorded, inverted for undo, and sent over the wire as JSON.
document.set-title,document.set-metadata: change document fields;nullmetadata removes it.node.insert: addssubtreeas a child ofparentIdatindex(0 to the child count). None of its node IDs may exist yet.node.remove: removes a node and its descendants. Not for a page root. A connector end attached to a removed node becomes a free end.node.move: moves a node tonewParentIdatindex, counted after the node is taken out of its old parent. Not for a page root, and not into the node’s own subtree.node.replace: replaces a node’s data by ID. It cannot change the node’stypeor a container’schildren; use insert, remove and move.page.insert,page.remove,page.move: add, delete or reorder pages. An inserted page’srootIdmust match its subtree’s root. Removing a page removes its nodes.page.replace: replaces a page’s fields; it cannot changerootId.theme.replace: replaces the whole theme.asset.put: adds an asset or replaces the one with the same ID.asset.remove: deletes an asset. It fails validation while an image or video node or a text or code style still refers to it.
源码interface SerializedSubtree一个节点及其所有后代,由插入操作携带。
readonly rootId: NodeId源码readonly nodes: Readonly<Record<string, SceneNode>>源码根节点及其每个后代,以
NodeId为键。
源码function serializeSubtree( document: DesignDocument, rootId: NodeId ): SerializedSubtree将一个节点及其后代复制到
SerializedSubtree中,可直接用于node.insert或page.insert操作。节点不存在时抛出ModelError。
源码function getSubtreeNodeIds( document: DesignDocument, rootId: NodeId ): ReadonlySet<NodeId>一个节点及其所有后代的 ID。节点不存在时为空。
源码function nodeIdsRemovedBy( input: DesignDocument, operations: readonly DocumentOperation[] ): readonly NodeId[]The IDs of the nodes that are in
inputand gone onceoperationshave run, in the orderinput.nodeslists them. That is every node the operations remove themselves (node.remove,page.removeandcomponent.remove, each with everything inside) and every group removed because the edit left it with no children. A node that is removed and put back by the same operations is not listed.It runs the same steps as
applyOperationsbut does not validate the result and returns no document. Use it to learn what an edit removes before applying it, for example to let go of the connector ends attached to those nodes, without whichapplyOperationswould refuse the edit.It throws a
ModelErrorwhen an operation does not fit the document.
源码interface ChangeSet一次编辑改变了什么,用来决定要重绘哪些内容以及通知哪些订阅者。每个 ID 列表都已排序。没有任何变化时,其值为
EMPTY_CHANGE_SET。readonly documentChanged: boolean源码仅当文档未变化时为 false;此时每个列表都为空。
readonly themeChanged: boolean源码readonly changedNodeIds: readonly NodeId[]源码数据或位置发生变化、或外观可能不同的节点。包括插入和移除的节点、子节点发生变化的父节点、被移动子树中的每个节点、使用了已变化资源的节点,以及主题变化时的所有节点。
readonly insertedNodeIds: readonly NodeId[]源码之前不存在的节点。在同一次编辑中被移除后又重新插入的节点,既不在此列表中,也不在
removedNodeIds中。readonly removedNodeIds: readonly NodeId[]源码已不再存在的节点。
readonly changedPageIds: readonly PageId[]源码被添加、移除、修改或在
pageOrder中移动的页面。readonly changedAssetIds: readonly AssetId[]源码readonly changedComponentIds: readonly ComponentId[]自 0.23.0源码Components added, removed or replaced, and components any of whose layers changed. Their instances, and the instances of every component that nests them, may look different (see
componentsNesting).
源码const EMPTY_CHANGE_SET: ChangeSet没有任何变化时返回的冻结
ChangeSet。
源码function diffDocuments( previous: DesignDocument, current: DesignDocument ): ChangeSet计算两个有效文档之间的
ChangeSet,用于并非来自applyOperations的变化(例如DocumentStore中的撤销或检出)。按引用共享的部分会直接跳过,不读取。
源码function serializeOperations( operations: readonly DocumentOperation[], indentation = 0 ): string使用
assertOperation检查每个操作,并将列表以键排序的 JSON 写出。indentation会传给JSON.stringify。
源码function deserializeOperations( input: string | unknown ): readonly DocumentOperation[]从 JSON 字符串或已解析的值读取操作列表,用
assertOperation逐一检查,并返回深度冻结的副本。抛出ModelError(字符串无法解析时为INVALID_JSON)。
源码function assertOperation(value: unknown): asserts value is DocumentOperation检查一个操作的结构:它的
type、确切的键集合,以及它携带的任何节点、页面、主题或资源。它是否适用于某个具体文档,只由applyOperations检查。抛出ModelError。
源码function assertChangedDocument( value: unknown, changed: ChangedDocumentEntities ): asserts value is DesignDocument校验由一个已有效的文档编辑而来的文档。会检查被修改实体的结构,并完整检查所有跨实体的规则——节点树、页面顺序、分区和引用。
源码interface ChangedDocumentEntities列出一个事务涉及的部分。文档中原样保留的内容在首次进入文档时已经校验过,因此只有出现在这里时才会再次检查其结构。
如果变更集遗漏了事务写入的内容,就会放过无效的值,因此只应在产生它的那次编辑中一并生成变更集。
readonly nodeIds: ReadonlySet<string>源码readonly pageIds: ReadonlySet<string>源码readonly assetIds: ReadonlySet<string>源码readonly componentIds: ReadonlySet<string>自 0.23.0源码Components whose definition was written.
readonly themeChanged: boolean源码
Store 与历史记录
DocumentStore 保存当前文档和一棵提交树。它支持撤销、重做、把多次分派合并为一个撤销步骤、命名分支,以及对文档局部的订阅。
源码class DocumentStore保存一个文档及其编辑历史。每次修改都是由
DocumentOperation组成的一个提交;head 提交的文档就是当前文档。历史是一棵提交树,而不是一条直线:撤销后再派发会开出一个新的子提交,较早的子提交仍可通过
DocumentStore.checkout或带 ID 的DocumentStore.redo访问。命名分支指向提交,在被检出时会跟随 head 移动。新的 store 从main分支开始,包含一个根提交。监听器在每次修改后同步运行。监听器可以读取 store,但不能修改它:在通知期间调用
dispatch、undo、redo、检出和分支相关方法都会抛出ModelError。new (initialDocument: DesignDocument | unknown, options: StoreOptions = {})源码用
snapshotDocument校验并冻结initialDocument,并把它作为根提交。getSnapshot(): DesignDocument源码head 提交的文档。
getHeadCommitId(): CommitId源码getRootCommitId(): CommitId源码getCurrentBranch(): string | null源码当前检出的分支;head 处于分离状态时为
null。getBranches(): Readonly<Record<string, CommitId>>源码每个分支名及其指向的提交。
getCommit(id: CommitId): CommitRecord | undefined源码getHistoryGroupId(id: CommitId = this.#headCommitId): string | undefined源码提交所属的历史分组(如果派发时指定了分组)。之后使用相同分组的派发会修订该提交,而不是新增一条撤销记录。
getDocumentAt(id: CommitId): DesignDocument | undefined源码某个提交时的文档;ID 未知时为
undefined。listCommits(): readonly CommitRecord[]源码所有提交,按
CommitRecord.sequence排序。listChildren(id: CommitId = this.#headCommitId): readonly CommitId[]源码直接基于
id(默认为 head)创建的提交。preview( operations: readonly DocumentOperation[] ): ReturnType<typeof applyOperations>源码把操作应用到 head 文档上,但不提交。
dispatch(input: TransactionInput): CommitResult | null源码把
input.operations应用到 head 文档并记录结果。通常会在 head 之上新增一个提交,把当前分支移到该提交,并清空重做记录。如果指定了amendHead,或historyGroupId与 head 的相同,这些操作会被合并进 head 提交;如果合并后的提交不再改变任何内容,它会被移除,head 退回到其父提交。返回新的 head;没有任何变化(或被修订的提交被移除)时返回
null。当baseCommitId不是 head、某个操作不适用或结果无效时,抛出ModelError,此时 store 保持不变。setFrozen(frozen: boolean): void自 0.27.0源码Freezes or unfreezes the document. While frozen,
dispatch,undo,redo,squashHistory,checkoutandcheckoutBranchchange nothing and returnnull, the same answer as for a change that changes nothing, and no listener is called. Reading still works. A caller that hands the document to someone else (before the page that shows it is loaded again, for example) freezes it first, so that what it handed over stays the latest document.isFrozen(): boolean源码True between
setFrozen(true)andsetFrozen(false).canUndo(): boolean源码只要 head 不是根提交,就为 true。
canRedo(): boolean源码不带参数调用
redo时有可移动到的提交,则为 true。undo(): CommitResult | null源码把 head(以及当前分支)移到 head 的父提交,并记住旧的 head 以供
redo使用。在根提交处返回null。redo(id?: CommitId): CommitResult | null源码把 head 移到一个子提交。不传
id时,选择最近被撤销的子提交,或者在恰好只有一个子提交时选择它;没有可选的子提交时返回null。id不是 head 的子提交时抛出ModelError。getNextSequence(): number源码The sequence number the next new commit gets.
squashHistory( fromSequence: number, options: { readonly onlyCommits?: ReadonlySet<CommitId>; } = {} ): CommitResult | null源码Folds the commits made since
fromSequence(seegetNextSequence) on the way to the head into one commit, so one undo takes them all back. The walk from the head stops at the first commit made beforefromSequence, which becomes the folded commit’s parent. Commits that hang off the folded ones (typing undone and then replaced) are removed with them; the head’s own children stay. The folded commit keeps the head’s ID and document, so the document does not change; when the folded commits change nothing in total, they are all removed and the head moves to the parent.With
onlyCommits, nothing changes andnullis returned when a commit it would fold or remove is not in that set, so commits made by someone else (another tab, an outside change) are never folded into or removed with the caller’s.Returns the folded commit, or
nullwhen there were fewer than two commits to fold, they were removed, or a commit outsideonlyCommitswas found. Throws aModelErrorwhen a branch other than the checked-out one points at a commit it would remove.checkout(id: CommitId): CommitResult | null源码把 head 移到任意提交,并使其脱离所在分支,因此之后的提交不会移动任何分支。清空重做记录。
id已经是 head 时返回null。提交未知时抛出ModelError。createBranch(name: string, from: CommitId = this.#headCommitId): void源码新增一个指向
from(默认为 head)的分支,但不检出它。如果名称为空、包含null字符或已被占用,或者提交未知,抛出ModelError。checkoutBranch(name: string): CommitResult | null源码把
name设为当前分支,并把 head 移到它指向的提交。清空重做记录。head 没有移动时返回null。分支未知时抛出ModelError。renameBranch(previousName: string, nextName: string): void源码重命名分支。如果旧名称未知,或新名称无效或已被占用,抛出
ModelError。deleteBranch(name: string): void源码删除一个分支名;它的提交会保留。删除当前分支会使 head 处于分离状态。分支未知时抛出
ModelError。subscribe(target: SubscriptionTarget, listener: StoreListener): Unsubscribe源码每当 head 移动且其变化涉及
target(见SubscriptionTarget)时调用listener。返回一个用于移除该监听器的函数。subscribeState(listener: StoreStateListener): Unsubscribe源码store 的状态发生任何变化后(head、分支、当前分支或重做记录),不带参数调用
listener。适合显示撤销、重做按钮或分支列表的 UI。toJSON(): PersistedStore源码整个 store 的保存形式,为一个冻结的纯对象。
serialize(indentation = 0): string源码把
toJSON写成键已排序的 JSON。与serializeStore相同。static fromJSON( input: string | unknown, options: StoreOptions = {}, storeMigrations: StoreMigrationRegistry = defaultStoreMigrations, documentMigrations: MigrationRegistry = defaultMigrations ): DocumentStore源码加载由
serialize保存的 store。与deserializeStore相同。
源码interface StoreOptionsDocumentStore和deserializeStore的选项。readonly rootCommitId?: CommitId源码根提交的 ID。加载时忽略此项,保留已保存的 ID。
readonly idFactory?: () => CommitId源码生成新的提交 ID。它不能生成 store 中已有的 ID,否则
dispatch会抛出异常。默认实现组合了时间、计数器和随机字符。readonly now?: () => number源码CommitRecord.timestamp使用的时钟。默认为Date.now。readonly onListenerError?: (error: unknown) => void源码接收监听器抛出的错误,使一个监听器失败不会影响其他监听器。省略时这些错误会被丢弃。
源码interface TransactionInput-
readonly operations: readonly DocumentOperation[]源码readonly baseCommitId?: CommitId源码调用方生成这些操作时所基于的 head 提交。如果提供了此项且 head 此后已移动,
dispatch会抛出异常,而不是应用这些操作。readonly historyGroupId?: string源码将一连串 dispatch(例如一次拖拽的各个步骤)合并为一个撤销步骤。当 head 提交是以相同的编组 ID dispatch 的时,这些操作会并入该提交,而不是新增一个提交。必须是不含
null字符的非空字符串。readonly message?: string源码readonly actor?: CommitActor源码readonly amendHead?: boolean源码将这些操作并入 head 提交而不是新增提交,因此不会增加撤销步骤;除非提供了新消息,head 保留原有消息。用于从 head 提交派生出的变更,例如渲染器为该提交所编辑的文本测得的尺寸。根提交不能被修改,并且修改会丢弃重做条目,因此调用方应先检查
canRedo。
源码interface CommitResulthead 当前指向的提交及其文档。
readonly commit: CommitRecord源码readonly document: DesignDocument源码
源码interface CommitRecordDocumentStore历史中的一条记录。提交构成一棵树。readonly id: CommitId源码readonly parentId: CommitId | null源码此提交所基于的提交;仅根提交为
null。readonly sequence: number源码在 store 内的创建顺序:根提交为 0,之后依次递增。它也决定了
DocumentStore.listCommits的顺序。readonly timestamp: number源码提交创建或最近一次修订的时间,取自
StoreOptions.now。readonly message?: string源码readonly actor?: CommitActor源码readonly operations: readonly DocumentOperation[]源码把父提交的文档变为此提交文档的操作。
readonly inverseOperations: readonly DocumentOperation[]源码把此提交的文档变回父提交文档的操作。
readonly changes: ChangeSet源码operations相对于父提交所做的变化。
源码interface CommitActor提交的作者。根提交的作者为
{ kind: "system", id: "taco-slides" }。readonly kind: "human" | "assistant" | "system"源码readonly id: string源码由应用定义的、代表某个人或智能体的标识符。
源码interface StoreChangeEventhead 移动后传给
DocumentStore.subscribe监听器的事件。该事件是深度冻结的。readonly reason: TransitionReason源码readonly previousCommitId: CommitId源码变更前的 head。当某次 dispatch 原地修改了 head 提交时,它等于
currentCommitId。readonly currentCommitId: CommitId源码readonly previous: DesignDocument源码readonly current: DesignDocument源码readonly operations: readonly DocumentOperation[]源码在此次转换中把
previous变换为current的操作。readonly changes: ChangeSet源码
源码type TransitionReason = "dispatch" | "undo" | "redo" | "checkout"是哪个
DocumentStore调用移动了 head。checkout也涵盖checkoutBranch。
源码type SubscriptionTarget = | { readonly kind: "document" } | { readonly kind: "node"; readonly nodeId: NodeId } | { readonly kind: "page"; readonly pageId: PageId } | { readonly kind: "asset"; readonly assetId: AssetId }DocumentStore.subscribe监听器所关注的对象:document:所有变更。node:该节点或其任意后代发生的变更,无论是变更前还是变更后的后代。page:该页面出现在ChangeSet.changedPageIds中,或其树中的任意节点发生了变更。asset:该资源发生的变更。
源码type StoreListener = (event: StoreChangeEvent) => void
源码type StoreStateListener = () => void
源码type Unsubscribe = () => void移除返回此函数的那次订阅所注册的监听器。
整个历史记录都可以保存和加载。保存的历史有自己的整数版本和迁移;其中的文档和操作则经过文档迁移。
源码function serializeStore(store: DocumentStore, indentation = 0): string将 store 的完整历史以键排序的 JSON 写出:根文档和每个提交的操作,以及 head、分支和重做条目。
源码function deserializeStore( input: string | unknown, options: StoreOptions = {}, storeMigrations: StoreMigrationRegistry = defaultStoreMigrations, documentMigrations: MigrationRegistry = defaultMigrations ): DocumentStore从
serializeStore写出的 JSON 字符串或已解析的值加载 store。它先运行
storeMigrations,再用documentMigrations把根文档和每个已存储的操作迁移到当前文档 schema(见DocumentMigration.migrateOperation),然后重放每个提交,以重建文档、逆操作和变更集。迁移后不再改变任何内容的提交会被丢弃,由其子提交取代它的位置。未经迁移时,这样的提交会被视为错误。数据无效或不一致时抛出
ModelError。
源码type PersistedStore = PersistedStoreV1当前的已保存历史格式。
源码interface PersistedStoreV1DocumentStore的保存形式:根文档加上每个提交的操作、head、分支和重做栈。由DocumentStore.toJSON生成。readonly storeVersion: typeof CURRENT_STORE_SCHEMA_VERSION源码readonly documentSchemaVersion: typeof CURRENT_DOCUMENT_SCHEMA_VERSION源码readonly rootCommitId: CommitId源码readonly rootDocument: DesignDocument源码readonly commits: readonly PersistedCommitV1[]源码readonly headCommitId: CommitId源码readonly branches: Readonly<Record<string, CommitId>>源码readonly currentBranch: string | null源码readonly redoStack: readonly CommitId[]源码
源码interface PersistedCommitV1保存时的提交。逆操作和变更不会被保存;加载时通过重放操作重新计算它们。
readonly id: CommitId源码readonly parentId: CommitId | null源码readonly sequence: number源码readonly timestamp: number源码readonly message?: string源码readonly actor?: CommitActor源码readonly operations: readonly DocumentOperation[]源码
源码const CURRENT_STORE_SCHEMA_VERSION: 1serializeStore写出的已保存历史格式的版本。它独立于CURRENT_DOCUMENT_SCHEMA_VERSION,按整数递增。
源码class StoreMigrationRegistry由
StoreMigration步骤组成的有序链,供deserializeStore使用。new (migrations: readonly StoreMigration[] = [])源码register(migration: StoreMigration): this源码添加一个步骤并返回该注册表。如果该步骤不是从一个非负版本恰好前进一个版本,或者已存在从同一版本出发的步骤,则抛出代码为
INVALID_SCHEMA的ModelError。migrate(input: unknown): unknown源码从输入的
storeVersion开始依次运行各步骤直到CURRENT_STORE_SCHEMA_VERSION。抛出代码为UNSUPPORTED_VERSION、MISSING_MIGRATION或MIGRATION_FAILED的ModelError。
源码interface StoreMigration将已保存历史升级一个
storeVersion的单个步骤。其中的文档数据由文档迁移单独升级。readonly from: number源码readonly to: number源码必须为
from + 1。migrate(input: unknown): unknown源码以纯 JSON 返回升级后的 store,其
storeVersion设为to。
源码const defaultStoreMigrations: StoreMigrationRegistry此包自带的 store 迁移。只存在版本 1 时为空。
几何与形状
用于节点边界、旋转后的框、编组以及内置形状顶点的辅助函数。
源码interface Rect与坐标轴对齐的矩形;
x和y是其左上角。readonly x: number源码readonly y: number源码readonly width: number源码readonly height: number源码
源码type TransformMatrix = readonly [ a: number, b: number, c: number, d: number, e: number, f: number ]SVG 风格的仿射矩阵
[a, b, c, d, e, f]。它将点 (x, y) 映射为 (a*x + c*y + e, b*x + d*y + f),即如下 3×3 矩阵乘积:
源码const IDENTITY_TRANSFORM: TransformMatrix
源码function getNodeBounds(node: SceneNode): Rect返回节点在其父节点坐标系中的布局边界。
源码function getRotatedRectBounds(frame: Rect, rotation: number): Rect返回旋转画框在父空间中的轴对齐边界。
源码function resizeRotatedRect( frame: Rect, rotation: number, size: { readonly width: number; readonly height: number }, anchor: { readonly x: number; readonly y: number } = { x: 0, y: 0 } ): Rect改变 frame 的尺寸,同时保持其某个局部点在父坐标系中固定不动。默认锚点是局部左上角。
anchor是相对于尺寸的比例,因此 表示中心。设 为旋转rotation度的旋转(在 y 轴向下的空间中为顺时针),锚点相对于 frame 的x、y的偏移为:新位置为 。
源码function getPathBounds( pathData: string, transform: TransformMatrix = IDENTITY_TRANSFORM ): Rect | null
源码function getVectorNetworkBounds( vectorNetwork: VectorNetwork, transform: TransformMatrix = IDENTITY_TRANSFORM ): Rect | null返回应用仿射变换后,网络各边的紧密边界。
源码function getGroupChildrenBounds( nodes: NodeRecord, group: GroupNode ): Rect | null返回编组各子节点边界在编组自身坐标系中的并集;没有子节点的编组返回
null。旋转的子节点贡献其旋转后的包围盒,嵌套编组贡献其自身(已适配的)画框。
源码function fitGroupToChildren( nodes: NodeRecord, group: GroupNode ): FittedGroup | null把编组的画框适配到其子节点,而不移动页面上的任何内容。画框已经匹配时返回
null。空编组保持其位置,尺寸收缩为零。
源码interface FittedGroupreadonly group: GroupNode源码readonly children: readonly SceneNode[]源码由于编组原点移动而改变了局部位置的子节点。
源码function fitAllGroups(nodes: NodeRecord): NodeRecord适配节点记录中的每个编组,最深层的编组优先,这样父编组看到的是其嵌套编组的最终画框。在加载文档时使用,可修复以过时编组尺寸保存的文件。
源码function buildParentMap(nodes: NodeRecord): Map<NodeId, NodeId>
源码function nodeDepth(parents: ReadonlyMap<NodeId, NodeId>, nodeId: NodeId): number
源码interface ShapePoint参数化形状(多边形、星形、椭圆弧和直线)的纯几何计算。渲染器编译器、编辑器和测试共用这些辅助函数,使所有使用方得到相同的顶点。
readonly x: number源码readonly y: number源码
自 0.12.0源码const MIN_SHAPE_POINT_COUNT: 3Figma 的多边形和星形顶点数。
源码const MAX_SHAPE_POINT_COUNT: 60
源码const DEFAULT_POLYGON_POINT_COUNT: 3Figma 为新绘制图形设置的默认值。
源码const DEFAULT_STAR_POINT_COUNT: 5
源码const DEFAULT_STAR_INNER_RADIUS: 0.382
源码function isValidShapePointCount(value: number): boolean
源码function polygonPoints( pointCount: number, width: number, height: number ): ShapePoint[]正多边形在 frame 局部坐标中的各个角,从顶部中央开始按顺时针排列。多边形会被拉伸,使其边界等于 frame。 个角中的第 个角起初位于单位圆上(y 轴向下)
然后按其包围盒缩放到 frame 中: , 同理使用高度计算(跨度为 0 时取 0)。
源码function starPoints( pointCount: number, innerRadius: number, width: number, height: number ): ShapePoint[]星形在 frame 局部坐标中交替排列的外顶点和内顶点,从顶部外顶点开始按顺时针排列。
innerRadius是内顶点距离相对于外半径的比例。星形会被拉伸,使其所有顶点的边界等于 frame。拉伸前, 个顶点中的第 个为其中 =
innerRadius;拉伸方式与polygonPoints相同。
源码function closedPolygonVectorNetwork( points: readonly ShapePoint[], idPrefix = "shape" ): VectorNetwork穿过给定各点、由直边构成的闭合网络,包含一个区域。
源码function validateEllipseArc(arc: EllipseArc): string | null
源码function ellipseArcSweep(arc: EllipseArc): number扫描角度,单位为度,顺时针为正;最多一整圈: 。
源码function isWholeEllipseArc(arc: EllipseArc | undefined): boolean当该圆弧绘制的是完整的普通椭圆时为 true。
源码function ellipseVectorNetwork( width: number, height: number, arc?: EllipseArc, idPrefix = "shape" ): VectorNetwork填满
width×height画框的椭圆所对应的网络,可以用可选的弧形裁切:完整椭圆、圆环(完整扫描并带内半径)、扇形(部分扫描且无内半径)或环形扇区。扫描角为零时不绘制任何内容,返回空网络。以度为单位的角度 (0 指向右方;由于 y 轴向下,正值为顺时针)落在其中外边缘上 ,内边缘上 =
innerRadius。
源码function lineEndpoints( line: Pick< LineNode, | "frame" | "rotation" | "flipX" | "flipY" > ): { readonly start: ShapePoint; readonly end: ShapePoint }直线在其父节点坐标系中的起点和终点。设 frame 中心为 ,宽度为 ,旋转角为 (由角度换算为弧度),设置了
flipX时 ,否则 :
源码function lineFrameFromEndpoints( start: ShapePoint, end: ShapePoint ): { readonly frame: Rect; readonly rotation: number }连接两个父空间点的直线所对应的零高度 frame 和旋转。旋转以角度表示,范围为 (-180, 180]。
源码function constrainLineEndpoint( anchor: ShapePoint, point: ShapePoint ): ShapePoint移动
point,使从anchor出发的线段保持长度不变,但转到最接近的 45 度整数倍方向,效果与绘制直线时按住 Shift 相同。
Connectors
Where connector ends go on a layer’s outline. The Connector tool offers a layer’s key points as dots (connectorKeyPoints); an end pinned to one of them stores a side or an anchor (ConnectorKeyPlace), and connectorPinnedPlace finds where it sits on the layer. An automatic end sits where the outline meets the line toward the other end (connectorOutlinePointToward). The page compiler and the editor share these, so the dot a connector is dropped on is where its end is drawn. Positions are in the layer’s own coordinates.
源码function connectorKeyPoints(node: SceneNode): readonly ConnectorKeyPoint[]The key points of a layer, in the order the Connector tool shows them:
- A rectangle, frame, text, image or any other box: the middle of each side, as FigJam’s
TOP,RIGHT,BOTTOMandLEFTmagnets. - An ellipse: its top, right, bottom and left points (on the curve, which touches its box there), keeping only those an arc draws, and the two ends of an arc that stops short of a full turn.
- A polygon: every corner, and the middle of every edge when it has at most
MAX_CONNECTOR_EDGE_KEY_POINT_COUNTpoints. - A star: its outer tips. Its inner corners point into the star, so a connector there would cross it.
- A rectangle, frame, text, image or any other box: the middle of each side, as FigJam’s
源码interface ConnectorKeyPoint extends ShapePointA point on a layer’s outline that a connector end can be pinned to.
readonly place: ConnectorKeyPlace源码readonly normal: ShapePoint源码The outline’s outward direction at the point.
源码type ConnectorKeyPlace = | { readonly side: ConnectorSide; readonly anchor?: undefined } | { readonly anchor: ConnectorAnchor; readonly side?: undefined }How an end is pinned to a key point: by a side (Figma’s magnet) or an anchor.
源码function sameConnectorKeyPlace( a: ConnectorKeyPlace, b: ConnectorKeyPlace ): booleanTwo places are the same pin: the same side, or the same kind and index of anchor.
源码function connectorPinnedPlace( node: SceneNode, endpoint: ConnectorEndpoint ): ConnectorOutlinePlace | undefinedThe place of an attached end pinned by
side,pointoranchoronnode, or undefined for an automatic end (including an anchor the layer does not have). A side on a box or ellipse is the middle of that side of the box; on a polygon or star it is where the outline meets the line from the centre (the average of its corners) straight toward that side. A side or anchor has the outward normal; a fixed point has none.
源码function connectorAnchorPoint( node: SceneNode, anchor: ConnectorAnchor ): ConnectorOutlinePlace | undefinedThe place of an anchor on a layer, or undefined when the layer has no such point: an index past its corners, or an anchor on a box or whole ellipse.
源码function connectorOutlinePointToward( node: SceneNode, toward: ShapePoint ): ShapePointWhere on its outline a layer meets the line from its centre toward
toward: the box’s edge, the ellipse’s curve (a whole ellipse, even for an arc) or the polygon’s or star’s outermost crossing. The layer’s centre whentowardis the centre.
源码interface ConnectorOutlinePlace extends ShapePointA place on a layer an end is drawn at, with the outward direction when it has one.
readonly normal?: ShapePoint源码
源码const CONNECTOR_SIDE_NORMALS: Readonly<Record<ConnectorSide, ShapePoint>>The outward direction of each side of a layer’s box.
源码const MAX_CONNECTOR_EDGE_KEY_POINT_COUNT: 8A polygon above this many points shows its corners only: with more, the dots in the middle of its edges crowd the corners.
Components and instances
A component is a reusable layer tree stored once per document, never on a page: its layers live in nodes under ComponentDefinition.rootId, listed in DesignDocument.components. An InstanceNode shows it on a page. It stores a reference and LayerOverrides keyed by layer path, and its layers are derived by resolveInstance with virtual IDs <instance>;<path> (parseVirtualNodeId). editTargetFor decides whether an edit to a selected ID goes to a stored node or to an instance override, and setOverrideOperations writes one. After an edit, withAutoLayoutOperations runs the component cascade (cascadeComponentChanges): instances of changed components are refitted to their hugging size, their override keys that name deleted layers are dropped (pruneOverrides), and their auto layout ancestors are laid out again, nested components first. remapOverrides carries overrides over to another component tree by layer name and position, for swap, redefine and paste. The nesting graph (componentNestingGraph) says which components contain which, for the cycle rule and for invalidation. The sample documents are what the compiler, editor and web tests build on. See docs/components/design.md.
自 0.23.0源码interface ComponentDefinitionA reusable layer tree, stored once per document and shown in the Assets panel, never on a page. Its layers live in
DesignDocument.nodesunderrootId, so every node operation, undo and validation works on them unchanged. Instances (InstanceNode) show it on pages.readonly id: ComponentId源码Matches the key in
DesignDocument.components.readonly key: string源码A stable identity separate from
id, a UUID string, unique in the document. Paste between documents and, later, libraries match components by key, so a component edited after a paste is still recognised as the same component. It never changes.readonly name: string源码Shown in the Assets panel. Must not be empty.
readonly description?: string源码Optional free text shown in the Assets panel.
readonly rootId: NodeId源码The root of the component’s layer tree: always a frame with no parent that no page uses. Its
frame.xandframe.yare 0; its width and height are the natural size, which is the size shown in the component view. Itslayoutsizing (Hug or Fixed) is the size behaviour every instance starts with; seeLayerOverride.sizing.readonly properties?: readonly ComponentPropertyDefinition[]自 0.24.0源码The component’s properties, in the order the instance section lists them. IDs and names are unique within the component. Omitted when empty.
readonly metadata?: Readonly<Record<string, JsonValue>>源码Free-form JSON data kept with the component. The model does not read it.
自 0.23.0源码type ComponentId = Brand<string, "ComponentId">The ID of a
ComponentDefinition, its key inDesignDocument.components.
自 0.23.0源码const componentId: (value: string) => ComponentIdBrands a string as a
ComponentId. Throws aTypeErrorfor an empty string.
自 0.23.0源码interface InstanceNode extends FramedNodeBaseOne use of a component on a page, or inside another component. It stores a reference and its overrides; its layers are derived when the page is compiled (see
resolveInstance) and get virtual IDs<instance id>;<layer path>(seeparseVirtualNodeId).The instance has no
children;isContainerNodeis false for it. ItsNodeBasefields apply to the whole instance, like a frame’s, and itsframe,rotation, flips andresizingplace it like any framed node.frameholds the resolved size, so geometry, selection and snapping code works without the resolver;applyOperationskeeps hugging axes equal to the resolved size (from step 1.2). The instance’s own paints come from the component root and are overridden under the component root’s path.readonly type: "instance"源码readonly componentId: ComponentId源码readonly overrides?: Readonly<Record<string, LayerOverride>>源码Changes to the component’s layers, keyed by layer path: the component node IDs from the component root down to the layer, joined by
;, without the instance ID. Omitted when empty. A key naming a node the component no longer has is allowed and has no effect.readonly propertyValues?: ComponentPropertyValues自 0.24.0源码The instance’s values for the component’s properties, keyed by property ID. Missing means the default; a value equal to the default is still kept, so Reset is what makes the instance follow the default again. Omitted when empty.
自 0.23.0源码interface LayerOverrideThe changes one instance makes to one layer of its component, stored in
InstanceNode.overridesunder the layer’s path. Every field replaces the layer’s resolved value as a whole; a field that is absent follows the component. Structure (layers, layout kind and spacing, geometry of inner layers, masks, blend modes, names) is not overridable: that needs an edit to the component, or Detach.Precedence for one field of one layer, decided per field:
- A variable ID in
variableBindingsfor the field’s property: the variable’s value wins. - Otherwise a plain value in this override for the field (or
nullinvariableBindingsfor its property): the override value wins, and the component layer’s own binding for that property is ignored in this instance. Overriding a field therefore never gets repainted by the component’s binding. - Otherwise the component layer’s own binding, then its stored value.
When instances nest, the override stored on the outer instance wins over the one stored on the nested instance node inside the component, which wins over the component’s value, again field by field.
readonly visible?: boolean源码readonly opacity?: number源码From 0 (transparent) to 1 (opaque).
readonly characters?: string源码Text layers: the whole text as plain characters, paragraphs separated by
"\n". Every character takes the style of the component’s first run, so a component font change still reaches an instance that only changed its label. Not allowed together withparagraphs.readonly paragraphs?: readonly TextParagraph[]源码Text layers: the whole content with styled runs, stored only when the user styles part of the text differently from the rest. Not allowed together with
characters.readonly textStyleId?: TextStyleId | null源码Text layers: the theme text style every run takes instead of its own;
nullclears the runs’ style IDs so they use the theme default.readonly textStyle?: TextStyleOverrides源码Text layers: direct formatting (font, size, weight, line height, letter spacing, colour and the rest) applied on top of every run’s style.
readonly styleId?: NodeStyleId | null源码Frames and shapes: the node style to use;
nullclears the layer’s.readonly fills?: readonly Paint[]源码readonly strokes?: readonly Stroke[]源码readonly shadows?: readonly Shadow[]源码readonly layerBlur?: number源码readonly backgroundBlur?: number源码readonly imageAssetId?: AssetId源码Image layers: the image asset to show instead.
readonly componentId?: ComponentId源码Nested instance layers: the component to show instead (a swap).
readonly sizing?: LayerSizingOverride源码Frame layers, and the component root for the instance’s own size.
readonly variableBindings?: LayerOverrideVariableBindings源码readonly propertyValues?: ComponentPropertyValues自 0.24.0源码Nested instance layers: property values keyed by property ID, each replacing the value the nested instance has in the component (stored or computed). Overrides are constants, never expressions.
- A variable ID in
自 0.23.0源码interface LayerSizingOverrideWhich axes of a layer inside an instance hug their content or keep a fixed size, replacing the component frame’s
layout.widthSizingandlayout.heightSizing. Under the component root’s path it is the instance’s own size behaviour: resizing an instance on the canvas stores"fixed"on that axis, and Reset size removes the entry, so the instance follows the component root again. Fill is not stored here: an instance fills its parent through its ownresizing, like any framed node.readonly width?: "hug" | "fixed"源码readonly height?: "hug" | "fixed"源码
自 0.23.0源码type LayerOverrideVariableBindings = Readonly< Partial<Record<VariableProperty, VariableId | null>> >Variable bindings an instance stores for one layer, keyed by property. A variable ID binds the property in that instance;
nullremoves the component’s binding for that property in that instance and leaves the plain value (the layer’s, or the override’s) in force.
自 0.23.0源码const LAYER_PATH_SEPARATOR: ";"The character that joins the IDs in a layer path and a virtual node ID. Stored node IDs never contain it.
自 0.23.0源码interface VirtualNodeIdThe parts of a virtual node ID: the stored instance the layer belongs to and the layer path inside it.
readonly instanceId: NodeId源码The stored
InstanceNodeon a page or inside a component.readonly path: readonly NodeId[]源码The component node IDs from the instance down to the layer, in order. Component roots that are passed through are left out; a component root is only named when it is the addressed layer itself (for the instance’s own paints and size). Never empty.
源码const isVirtualNodeId: (id: string) => booleanTrue when
idnames a layer inside an instance rather than a stored node.
自 0.23.0源码function parseVirtualNodeId(id: string): VirtualNodeId | nullSplits a virtual node ID
<instance id>;<layer path>into its instance and layer path. Returnsnullfor a stored node ID (no separator) and for a malformed ID with an empty segment. This is the only place that splits virtual IDs.
源码function virtualNodeId(instanceId: NodeId, path: readonly NodeId[]): NodeIdBuilds the virtual node ID of the layer at
pathinsideinstanceId.
源码function layerPathKey(path: readonly NodeId[]): stringThe key of
InstanceNode.overridesfor the layer atpath.
自 0.23.0源码function parseLayerPath(key: string): readonly NodeId[] | nullSplits an override key into its component node IDs, or returns
nullwhen the key is malformed (empty, or with an empty segment). Whether the named nodes still exist is not checked: such a key is allowed and has no effect.
源码function storedNodeIdOf(id: NodeId): NodeIdThe stored node an ID refers to: the instance for a virtual ID, the ID itself otherwise. Selection code uses it to find the node that moves, deletes or reorders when a layer inside an instance is selected.
源码function componentRootIds(document: DesignDocument): readonly NodeId[]The root node IDs of every component, in
componentsorder.
源码function findComponentByRoot( document: DesignDocument, rootId: NodeId ): ComponentDefinition | undefinedThe component whose root is
rootId, if any.
源码function componentOwningNode( document: DesignDocument, nodeId: NodeId, parents: ReadonlyMap< NodeId, NodeId > = buildParentMap(document.nodes) ): ComponentDefinition | undefinedThe component whose layer tree contains the stored node
nodeId(the root included), orundefinedwhen the node is on a page or does not exist. Passparents(frombuildParentMap) when calling this for many nodes.
源码function isComponentLayer(document: DesignDocument, nodeId: NodeId): booleanTrue when the stored node is a component layer (its root included) rather than a page node.
源码function instanceNodeOf( document: DesignDocument, instanceId: NodeId ): InstanceNode | undefinedThe node an instance ID names, checked to be an
InstanceNode.
源码function componentReferencesOf(node: SceneNode): readonly ComponentId[]The components a node refers to: an instance’s
componentId, and every component its overrides swap a nested instance to. Empty for other nodes.
源码function instancesOfComponent( document: DesignDocument, componentId: ComponentId ): readonly NodeId[]The stored instance nodes of
componentId, by ID, sorted. Swaps in overrides do not count.
自 0.23.0源码interface ComponentNestingGraphWhich components contain which.
nests.get(a)holds everybsuch that a node undera’s root is an instance ofb, or an override undera’s root swaps a nested instance tob.nestedByis the reverse. Every component appears as a key of both maps, with an empty set when it has no edges. Instances on pages add no edges.readonly nests: ReadonlyMap<ComponentId, ReadonlySet<ComponentId>>源码readonly nestedBy: ReadonlyMap<ComponentId, ReadonlySet<ComponentId>>源码
源码function componentNestingGraph(document: DesignDocument): ComponentNestingGraphBuilds the
ComponentNestingGraphof a document. Missing component references are kept as edges.
自 0.23.0源码function findComponentCycle( graph: ComponentNestingGraph ): readonly ComponentId[] | nullFinds a cycle in the nesting graph: a list of component IDs where each nests the next and the last equals the first. Returns
nullwhen the graph has no cycle.
源码function componentsNesting( graph: ComponentNestingGraph, componentId: ComponentId ): ReadonlySet<ComponentId>Every component whose tree contains
componentId, directly or through nesting. A change tocomponentIdalso changes the instances of these.
源码function componentsNestedIn( graph: ComponentNestingGraph, componentId: ComponentId ): ReadonlySet<ComponentId>Every component that
componentId’s tree contains, directly or through nesting.
自 0.23.0源码function wouldNestCycle( document: DesignDocument, hostId: ComponentId, placedId: ComponentId ): booleanReports whether placing an instance of
placedIdinsidehostId’s tree, or swapping a nested instance there toplacedId, would make a component contain itself. The editor disables such choices;assertDocumentrejects the result.
自 0.23.0源码interface ResolvedLayerOne derived layer of a resolved instance.
nodeis the component node with the instance’s overrides applied (by the precedence onLayerOverride) and itsframelaid out for the instance’s size, so the compiler compiles it exactly as it compiles a stored node, withvirtualIdas the render node ID.node.idequalsvirtualId, and a container’schildrenlist holds the virtual IDs ofchildren, in paint order.pathnames the nested instance nodes passed through and then the layer itself; frames passed through inside one component are left out, as component roots are, since node IDs are unique in the document.- The root layer stands for the instance itself: its
virtualIdis the instance’s own ID, itspathis[component root ID](the override key for the instance’s paints and size), and itsnodeis aFrameNodecarrying the instance’sNodeBasefields,frame,rotation, flips andresizing, with the component root’slayout,styleandclipContent(overrides applied).instancenames the stored instance. A nested instance layer’spathis the path to the nested instance node, which is also its override key on the outer instance for its paints and sizing, aseditTargetForwrites it. - A nested instance inside the component is expanded the same way: its
nodeis aFrameNodebuilt like the root layer (the nested instance node’s placement andNodeBasefields, after the outer overrides, with the nested component root’slayout,styleandclipContent),instancegives the nested instance and the component it shows after any swap, andchildrenare the nested component’s layers, whose paths continue through it.
readonly virtualId: NodeId源码readonly sourceNodeId: NodeId源码The component node this layer is derived from.
readonly path: readonly NodeId[]源码The layer path inside the outermost instance; see
VirtualNodeId.path.readonly node: SceneNode源码readonly children: readonly ResolvedLayer[]源码readonly instance?: ResolvedLayerInstance源码Present on the root layer and on nested instance layers.
readonly inheritedVariableModes?: VariableModes自 0.26.0源码The variable modes the layer inherits from its parent layer, as
inheritedVariableModesgives them for a stored node; the layer’s own choices (an instance’s, for the root and nested instance layers) are not included. Present on the layers of a resolved instance.readonly variableModes?: VariableModes自 0.26.0源码The variable modes in effect at the layer, which its bound fields read. Present on the layers of a resolved instance.
自 0.23.0源码interface ResolvedLayerInstanceThe stored instance a resolved layer stands for, set on the root layer and on every nested instance layer.
readonly instanceId: NodeId源码The stored
InstanceNode: the outer instance, or a nested one inside a component.readonly componentId: ComponentId源码The component shown, after any swap by an outer override.
readonly node: InstanceNode自 0.26.0源码The instance node as resolved: swapped, with outer overrides and the enclosing component’s computed fields (its own
propertyValuesincluded) applied. The component view draws a nested instance from it.readonly propertyValues?: ComponentPropertyValues自 0.26.0源码The property values the component is resolved with: the stored instance’s own, or for a nested instance its outer override, else its expression over the outer properties, else its stored value. Absent when none is set (every property at its default).
自 0.23.0源码interface ResolvedInstanceWhat
resolveInstancereturns: the instance’s derived layer tree.readonly instanceId: NodeId源码readonly componentId: ComponentId源码readonly root: ResolvedLayer源码The layer standing for the instance itself; see
ResolvedLayer.readonly layers: ReadonlyMap<NodeId, ResolvedLayer>源码Every resolved layer by virtual ID, the root under the instance ID.
readonly componentIds: readonly ComponentId[]源码The components this instance draws, its own first, then every nested one after swaps, without repeats. A change to any of them changes the result.
readonly expressionErrors: readonly ComponentExpressionError[]自 0.25.0源码Computed values this instance’s property values make invalid, such as a font family with no font in the document, for every component it draws; each such field shows its stored value.
自 0.23.0源码interface InstanceResolveCacheResolved trees kept between calls so a component is resolved once for all its instances (design 4.3). One cache belongs to one document line; call
clearwhen the document is replaced.A component’s version rises when any node in its own layer tree is a new object; an entry is reused only while every component it draws keeps its version and the theme and assets are the same objects. An instance entry also needs the instance node itself to be the same object.
clear(): void源码readonly stats: { readonly hits: number; readonly misses: number; readonly evaluations: number; }源码How many
resolveInstanceandresolveComponentcalls were served from the cache, and how many times a component’s conditions and computed fields were evaluated (evaluations, since 0.25.0): once per component, component version, variables and property values with defaults filled in, however many instances share them.
源码function createInstanceResolveCache(): InstanceResolveCacheMakes an
InstanceResolveCacheto pass toresolveInstance.
自 0.23.0源码interface ResolveInstanceOptionsreadonly cache?: InstanceResolveCache源码readonly variableModes?: VariableModes自 0.26.0源码The variable modes the instance inherits from its parent, as
inheritedVariableModesreturns them. Read from the document when omitted; the page compiler passes them as it walks the page.
自 0.23.0源码function resolveInstance( document: DesignDocument, instanceId: NodeId, options?: ResolveInstanceOptions ): ResolvedInstanceDerives the layers an instance shows: virtual IDs, overrides applied by precedence, nested instances expanded, and the component root’s auto layout run for the instance’s size and overridden text. A hugging axis takes its natural size, whatever the stored frame says; a fixed axis and an axis the instance fills keep the stored size.
With component properties (design 8.6, since 0.25.0), each component in the instance is resolved in this order: conditions leave layers out (with their sublayers, taking no space in auto layout), computed fields are evaluated for the instance’s property values and written into the model fields, overrides go on top (an override wins over a computed value), and then layout runs. A nested instance’s property values are its outer override, else its expression over the outer properties, else its stored value, else the nested component’s default. An expression that does not check is skipped (see
componentExpressionErrors). A root without auto layout lays out a resized instance by its children’s constraints (constrainChildren).Throws a
ModelErrorwith codeINVALID_TREEwheninstanceIdis not an instance node or its component is missing.
自 0.23.0源码function resolveComponent( document: DesignDocument, componentId: ComponentId, options?: ResolveInstanceOptions ): ResolvedLayerDerives the component view: the component’s own layer tree at its natural size with no overrides, as
ResolvedLayers whosevirtualIds are the stored node IDs. Isolation mode draws it; a nested instance inside it is expanded as inresolveInstance, under its own stored ID. A component with properties or expressions shows its default values (design 8.9): conditions and computed fields are evaluated with the defaults, and its auto layout frames are laid out again.
自 0.23.0源码function huggedInstanceSize( document: DesignDocument, instanceId: NodeId, options?: ResolveInstanceOptions ): { readonly width?: number; readonly height?: number }The size an instance takes on each axis it hugs, from its resolved root.
undefinedon an axis the instance keeps as stored (Fixed, Fill, or a component root without auto layout).
源码function cascadeComponentChanges( document: DesignDocument, nodes: Record<string, SceneNode>, changedNodeIds: ReadonlySet<NodeId>, changedComponentIds: readonly ComponentId[], changed: Set<NodeId> ): voidThe component cascade of one edit (design question D): after the ordinary layout pass, refits every instance whose component changed (or that nests a changed component, or that the edit touched itself) to its hugging size, drops its override keys that name deleted layers, and lays out its auto layout ancestors again, on pages and inside components. Nested components go first, so a component that nests a changed one is laid out with the new nested sizes before its own instances are refitted.
nodesis the working copy after the operations and the layout pass; it is changed in place, and every node it changes is added tochanged.changedNodeIdsare the nodes the operations and the layout pass changed.
自 0.23.0源码interface OverrideRemapTreeOne component’s layer tree as a remap or prune reads it: the document that holds the nodes and the component’s root. Swap passes one document with two roots; redefine and paste pass the old and the new document.
readonly document: DesignDocument源码readonly rootId: NodeId源码readonly shownComponentAt?: (path: readonly NodeId[]) => ComponentId | undefined自 0.26.0源码The component the nested instance at a layer path (inside the instance whose overrides are remapped) shows, for when its component is computed from a property value. Without it, or when it returns undefined, the nested instance node’s stored component counts. An override swap at the path still wins.
自 0.23.0源码function remapOverrides( overrides: | Readonly<Record<string, LayerOverride>> | undefined, from: OverrideRemapTree, to: OverrideRemapTree, mapComponent: ( id: ComponentId ) => ComponentId = (id) => id ): Record<string, LayerOverride>Carries an instance’s overrides over to another component tree by layer name and position (design 3.5): each key’s layers are matched from the root down by name at the same index among their siblings, else by the first sibling with that name; a nested instance segment continues into the component it shows. Keys with no match are dropped, and a key that is remapped onto another key’s target is dropped as well (the earlier key wins). Property values on a nested instance’s entry are carried to the component that layer shows on the other side (
carryPropertyValues, withmapComponentfor instance swap values). Swap, redefine and paste use this, then store the result.
自 0.23.0源码function overridePathResolves( document: DesignDocument, componentId: ComponentId, path: readonly NodeId[], overrides: Readonly<Record<string, LayerOverride>> = {}, shownComponentAt?: (path: readonly NodeId[]) => | ComponentId | undefined ): booleanWhether an override key names a layer the component still has: every segment but the last must be a nested instance node in the tree entered so far (after any swap in
overrides, else the componentshownComponentAtgives), and the last a node in that tree.
自 0.23.0源码function pruneOverrides( document: DesignDocument, instance: InstanceNode ): InstanceNodeThe instance without the override keys that name layers its component no longer has (design 3.5); the same node when every key still resolves.
自 0.23.0源码type OverrideField = keyof LayerOverrideThe fields an instance can override; the keys of
LayerOverride.
源码const OVERRIDE_FIELDS: readonly OverrideField[]Every
OverrideField, inLayerOverrideorder.
自 0.23.0源码type EditTarget = | { readonly kind: "node"; readonly nodeId: NodeId; readonly node: SceneNode } | { readonly kind: "override"; readonly instanceId: NodeId; readonly instance: InstanceNode; readonly key: string; readonly path: readonly NodeId[]; readonly sourceNodeId: NodeId; readonly field: OverrideField; } | { readonly kind: "unsupported"; readonly reason: string }Where an edit to one field of one selected ID goes.
node: a stored node on a page or inside a component (editing in isolation changes the component). Write it withnode.replace.override: a layer inside an instance, or an instance’s own paints and size. Write it withsetOverrideOperations(anode.replaceof the instance with the changedoverrides[key]);sourceNodeIdis the component node the layer is derived from, for reading the base value.unsupported: the edit cannot be made here;reasonsays why, for the user (a structural field on a layer inside an instance, or a layer the component no longer has).
自 0.23.0源码function editTargetFor( document: DesignDocument, id: string, field: string ): EditTargetDecides where an edit goes.
idis a stored node ID or a virtual ID (<instance>;<path>);fieldis the layer field being edited: anOverrideField, a node field name with the same meaning (assetIdforimageAssetId), orvariableBindings.<property>for one binding.A virtual ID always targets an override on its outermost instance, so an edit to a layer of a nested instance is stored on the instance the user selected through. Fields that are not in
LayerOverride(position, size, rotation, name, layout, masks, blend mode) areunsupportedon a virtual ID: they need an edit to the component, or Detach.
自 0.23.0源码type LayerOverridePatch = { readonly [Field in OverrideField]?: LayerOverride[Field] | undefined }A change to one override entry: each present key replaces that field, and a key set to
undefinedremoves it (Reset for that field).
自 0.23.0源码function withOverride( instance: InstanceNode, key: string, patch: LayerOverridePatch ): InstanceNodeReturns the instance with
patchmerged intooverrides[key]. Settingcharactersremovesparagraphsand the other way round, so the two never coexist. An entry left with no fields is removed, and an emptyoverridesmap is dropped. Pure: the input is not changed.
自 0.23.0源码function withoutOverride( instance: InstanceNode, key?: string, field?: OverrideField ): InstanceNodeReturns the instance without an override: one field of one layer, one whole layer (
fieldomitted), or every override (keyomitted). Pure.
自 0.23.0源码function setOverrideOperations( document: DesignDocument, instanceId: NodeId, key: string, patch: LayerOverridePatch ): readonly DocumentOperation[]The operations that write
patchintooverrides[key]of the instance: onenode.replace, or none when the instance is not an instance node.applyOperationsdrops a replace that changes nothing.
自 0.23.0源码function resetOverrideOperations( document: DesignDocument, instanceId: NodeId, key?: string, field?: OverrideField ): readonly DocumentOperation[]The operations that reset overrides of the instance: one field of one layer, one layer, or all (see
withoutOverride). An axis that hugs again loses its stretching constraint when the operations are applied, as after every edit (applyOperations).
自 0.23.0源码const componentSampleIds: { readonly document: DocumentId; readonly page: PageId; readonly pageRoot: NodeId; readonly textStyle: TextStyleId; readonly button: ComponentId; readonly buttonRoot: NodeId; readonly buttonLabel: NodeId; readonly buttonIcon: NodeId; readonly card: ComponentId; readonly cardRoot: NodeId; readonly cardTitle: NodeId; readonly cardButton: NodeId; readonly iconButton: ComponentId; readonly iconButtonRoot: NodeId; readonly iconButtonIcon: NodeId; readonly buttonInstance: NodeId; readonly secondButtonInstance: NodeId; readonly cardInstance: NodeId; readonly colors: VariableCollectionId; readonly lightMode: VariableModeId; readonly primary: VariableId; readonly danger: VariableId; }The IDs the component sample documents use, so tests can refer to them by name. Layer paths for overrides are built from the node IDs, for example
layerPathKey([componentSampleIds.cardButton, componentSampleIds.buttonLabel]).
自 0.23.0源码const componentSampleDocuments: { readonly plain: () => DesignDocument; readonly nested: () => DesignDocument; readonly textOverride: () => DesignDocument; readonly variableBoundOverride: () => DesignDocument; readonly swappedNested: () => DesignDocument; }Every component sample by name, for tests that run over all of them.
自 0.23.0源码function plainInstanceSample(): DesignDocumentOne Button component and one instance of it on the page, with no overrides. The instance is at the component’s natural size.
自 0.23.0源码function nestedInstanceSample(): DesignDocumentA Card component whose tree holds an instance of Button, and one Card instance on the page. The nesting graph has the edge Card → Button.
自 0.23.0源码function textOverrideSample(): DesignDocumentTwo Button instances with text overrides:
button-1changes the label’s characters only, andbutton-2stores styled paragraphs because part of its label is bold. Both keep the component’s font.
自 0.23.0源码function variableBoundOverrideSample(): DesignDocumentThe Button label’s colour is bound to the
primaryvariable in the component. The instance rebinds it todangerfor the label, and for the root it overrides the fills with a plain colour while removing the component’sfillColorbinding, so the plain override cannot be repainted by the variable.
自 0.23.0源码function swappedNestedInstanceSample(): DesignDocumentThe nested sample plus an Icon button component. The Card instance swaps its nested Button to Icon button, and keeps a characters override under the old label’s path, which Icon button does not have: the entry is allowed and has no effect.
### Isolation mode
Editing a component in isolation (design 5.5) keeps a stack of IsolationLevels, one per opened component. isolationEditRoute applies the edit rules: in the instance view an edit changes the override that wins at that place when the opened instance side already overrides the field, and the component otherwise; in the component view it always changes the component. Its reach says whether the edit changes only this instance or a component and how many instances that has. isolationViews is what the canvas draws besides the instance in place: the component views, laid out as a grid inside one set outline when there are several, never saved or exported. The editor draws them in the split’s component pane.
自 0.23.0源码interface IsolationLevelOne level of isolation mode (design 5.5): the component being edited and the instance it was opened from.
Levels form a stack. The first level opens a component from an instance on a page (or from the Assets panel, with no instance); each deeper level opens the component of a nested instance seen in the level above.
readonly componentId: ComponentId源码The component edited at this level. For a swapped nested instance, the component it is swapped to.
readonly instanceId: NodeId | null源码The instance the level was opened from, drawn as the instance view, or
nullwhen the level was opened from the Assets panel (only the component view is shown). It is a stored instance ID (an instance on a page, or a nested instance node inside the component view of the level above) or a virtual ID (<instance>;<path>, a nested instance as it appears inside the instance view of the level above).
自 0.23.0源码type IsolationView = "instance" | "component"Which of the two isolation views an edit is made in (design 5.5): the instance view shows the opened instance with its overrides and uses virtual IDs; the component view shows the component’s own nodes by their stored IDs.
自 0.23.0源码type EditReach = | { readonly kind: "this-instance"; readonly instanceId: NodeId } | { readonly kind: "component"; readonly componentId: ComponentId; readonly instanceCount: number; }How far an edit reaches (question F in the components plan): only the opened instance, or a component and so every instance of it. The editor shows “Only this instance” or “Changes the component (N instances)”.
自 0.23.0源码type IsolationEditRoute = | { readonly kind: "edit"; readonly target: WritableTarget; readonly overridden: boolean; readonly reach: EditReach; } | { readonly kind: "unsupported"; readonly reason: string }Where an edit made in isolation goes (design 5.5, Edit rules).
edit: writetargetaseditTargetFordescribes it.overriddenis true when the edit changes an override that wins at that place on the instance side of the level (the first row of the design’s table); the editor marks such fields “Overridden”.reachis the question F signal.unsupported: the edit cannot be made in this view;reasonis for the user.
自 0.23.0源码function isolationEditRoute( document: DesignDocument, level: IsolationLevel, view: IsolationView, id: NodeId, field: string ): IsolationEditRouteWhere an edit to
fieldof the layerid, made inviewat isolation levellevel, goes (design 5.5, Edit rules and nesting).fieldis as foreditTargetFor: an override field, a node field name,variableBindings.<property>, ortextStyle.<member>for one text style member (routed by that member and its own binding only).Component view:
idis a stored node of the level’s component, or a virtual ID of a layer inside a nested instance node of it. The edit always changes the component; this iseditTargetFor’s answer, checked to stay inside the component.Instance view:
idis the level’s instance ID (its root) or a virtual ID under it. The overrides that can apply at that place are those stored on the level’s instance and on every instance it is nested in (the instance side). When the override whose value shows there (by the resolver’s precedence: a binding beats a plain value, then outermost first) is one of them, the edit changes that override: only this instance when that instance is on a page, or the component that holds it when it is a nested instance node inside a component. Otherwise the edit changes the level’s component, as the same edit in the component view would. Isolation never creates an override (design 5.5). Geometry, structure and other fields that cannot be overridden always go to the component.
自 0.23.0源码function componentOfInstance( document: DesignDocument, instanceId: NodeId ): ComponentId | undefinedThe component an instance shows: a stored instance’s
componentId, or for a virtual ID naming a nested instance, the component it is swapped to by the override that wins at that place (outer instance first), else the nested instance node’s owncomponentId.A nested instance whose
componentIdis computed from the properties of the component that holds it (an instance swap property) shows the computed component, unless an override swaps it. That one is read from the tree the instance resolver draws, so it is the property values of the instance on the page, or in a component’s own view the property defaults. A nested instance that is not drawn (a condition leaves it out) has its stored component.undefinedwhen the ID does not name an instance or the component is missing.
自 0.23.0源码function componentInstanceCount( document: DesignDocument, componentId: ComponentId ): numberHow many instances an edit to the component reaches, for “Editing affects N instances”: every stored instance node of the component in the document, on pages and inside other components. A nested instance inside a component counts once, however many instances of the outer component show it, and swaps in overrides do not count (as
instancesOfComponent).
自 0.23.0源码interface IsolationBreadcrumbOne crumb of the isolation bar: the page, then one per level.
readonly label: string源码readonly depth: number源码How many levels stay open when the crumb is chosen: 0 for the page.
自 0.23.0源码function isolationBreadcrumbs( document: DesignDocument, pageName: string, levels: readonly IsolationLevel[] ): readonly IsolationBreadcrumb[]The isolation bar’s breadcrumbs: page › component › nested component.
自 0.23.0源码interface ComponentViewOne component view: the component drawn by its stored node IDs at its natural size (the root’s frame size), with no overrides, under the label “Component”. “Show all variants” adds one view per combination of property values, laid out beside it inside one set outline (design 8.2).
readonly componentId: ComponentId源码readonly rootId: NodeId源码The component root; the view draws the component’s layer tree from it.
readonly label: string源码readonly bounds: Rect源码The view’s place at the natural size, in the coordinates of the set of views: the first view (the defaults) is at 0,0.
readonly variant?: { readonly values: ComponentPropertyValues; readonly key: string; }自 0.26.0源码A variant view’s property values (the ones that differ from the defaults) and its combination key; absent for the view at the defaults, which draws the stored nodes.
源码interface IsolationViewsOptionsWhat
isolationViewsdraws besides the component view.readonly vary?: readonly ComponentPropertyId[]自 0.26.0源码“Show all variants”: the enum and boolean properties to vary. One view per combination is drawn when there are at most
VARIANT_VIEW_CAP; otherwise only the component view.readonly also?: ComponentPropertyValues自 0.27.0源码Property values whose view is drawn as well, whatever
varyholds: the opened instance’s, so the variant it shows can be edited beside the defaults. Adds nothing when they are the defaults or already drawn.
自 0.23.0源码interface IsolationViewsWhat the canvas draws for one isolation level. The views are not part of the document; they are never saved or exported.
readonly componentId: ComponentId源码readonly instanceId: NodeId | null源码The instance view: the opened instance, drawn in place with its overrides;
nullfrom the Assets panel.readonly componentViews: readonly ComponentView[]源码The component views, the defaults first, in reading order (row by row, left to right).
readonly setBounds?: Rect自 0.27.0源码The outline around the views when more than one is drawn, in the same coordinates as their bounds: the views with
COMPONENT_SET_PADDINGaround them, as Figma outlines a component set. Absent with one view.
源码const COMPONENT_VIEW_GAP: 40The gap between two views, in canvas units.
自 0.27.0源码const COMPONENT_SET_PADDING: 40The space between the set outline and the views inside it, in canvas units.
自 0.27.0源码function isolationViewCombinations( component: ComponentDefinition, options?: IsolationViewsOptions ): readonly VariantCombination[]The combinations
isolationViewsdraws foroptions, in drawing order: the defaults alone with no options; every combination ofvary; and the combination ofalsoafter them when it is not one of those already.
自 0.23.0源码function isolationViews( document: DesignDocument, level: IsolationLevel, options?: IsolationViewsOptions ): IsolationViews | undefinedThe views to draw for
level, laid out as a grid inside one set outline: with one varied property (or none) the views are one row; with more, the last varied property’s values are the columns and every combination of the others is a row. A column is as wide as its widest view and a row as tall as its tallest, so the views line up. A view added byoptions.alsogoes at the end of the first row.
导出设置
每个节点可以为其“导出”面板携带若干行设置。这些辅助函数用于检查这些行、选取默认值并生成文件名。
自 0.14.0源码interface ExportSetting图层“导出”区域中的一行。每个字段都始终存储,因此切换格式时该行会保留其值;不适用于当前格式的字段在导出时会被忽略。
readonly format: ExportFormat源码readonly constraint: ExportConstraint源码readonly suffix: string源码添加在文件名中图层名之后;可以为空。
readonly quality: ExportQuality源码readonly resampling: ExportResampling源码readonly ignoreOverlappingLayers: boolean源码仅适用于 PNG、JPEG 和 SVG。为
true时只绘制该图层及其子图层;为false时绘制该图层边界内的所有可见图层。readonly includeIdAttribute: boolean源码仅适用于 SVG:为绘制的元素添加由图层名生成的 “id” 属性。
源码type ExportFormat = (typeof EXPORT_FORMATS)[number]
自 0.14.0源码const EXPORT_FORMATS: readonly ["png", "jpeg", "svg", "pdf"]图层可以导出的文件格式。
自 0.14.0源码type ExportConstraint = | { readonly type: "scale"; readonly value: number } | { readonly type: "width"; readonly value: number } | { readonly type: "height"; readonly value: number }光栅导出的输出尺寸:图层尺寸的倍数,或固定的像素宽度或高度,另一边按比例保持。
源码type ExportQuality = (typeof EXPORT_QUALITIES)[number]
自 0.14.0源码const EXPORT_QUALITIES: readonly ["low", "medium", "high"]
源码type ExportResampling = (typeof EXPORT_RESAMPLINGS)[number]
自 0.14.0源码const EXPORT_RESAMPLINGS: readonly ["detailed", "basic"]“detailed” 使用双三次插值对图片采样;“basic” 使用最近邻像素。
源码const MAX_EXPORT_SCALE: 100缩放约束可取的最大倍数。
源码const MAX_EXPORT_DIMENSION: 16384尺寸约束可取的最大像素宽度或高度;即渲染器自身的上限。
源码const MAX_EXPORT_SUFFIX_LENGTH: 100
源码const MAX_EXPORT_SETTINGS: 64一个节点最多可包含的行数。
源码function defaultExportQuality(format: ExportFormat): ExportQuality一行导出设置切换到
format时的初始质量。
源码function isVectorExportFormat(format: ExportFormat): format is "svg" | "pdf"当该格式忽略尺寸约束并以 1x 导出时为 true。
源码function nextExportSetting(existing: readonly ExportSetting[]): ExportSetting导出区域的 + 按钮所添加的行。第一行为 1x 的 PNG,不带后缀。之后每一行复制最后一行的格式和选项,并取下一个整数倍率,配上对应的“@Nx”后缀,与 Figma 的做法一致。
源码function exportConstraintProblem(constraint: ExportConstraint): string | null约束无效的原因;有效时为
null。
源码function exportSuffixProblem(suffix: string): string | null后缀无效的原因;有效时为
null。
源码function formatExportConstraint(constraint: ExportConstraint): string约束在缩放字段中显示的形式:“2x”、“512w” 或 “512h”。
源码function parseExportConstraint(text: string): ExportConstraint | null读取用户在缩放字段中输入的内容。“2”、“2x” 和 “2X” 表示倍数,“512w” 表示固定宽度,“512h” 表示固定高度。当文本不是有效的约束时返回
null。
源码function exportFileExtension(format: ExportFormat): string某种格式的文件扩展名;与 Figma 一样,JPEG 文件使用 “.jpg”。
源码function exportFileStem(name: string): string图层名中在所有常见系统的文件名里都安全的部分。路径分隔符和保留字符会变为 “-”。
源码function exportFileName( name: string, setting: Pick<ExportSetting, "format" | "suffix"> ): string<layer name><suffix>.<extension>,与 Figma 为每个导出文件命名的方式相同。
源码function uniqueExportFileNames(names: readonly string[]): readonly string[]使一次导出中的每个文件名都唯一。重复的名称会在扩展名前加上“ 2”、“ 3”等,因此不会有下载文件覆盖另一个。
源码function uniqueSvgId(name: string, used: Set<string>): string由图层名称生成的有效 XML id:空格变为“_”,字母、数字、“_”、“-”和“.”以外的其他字符被删除,不以字母或“_”开头的名称会在开头加上“_”。
used保存文件中已有的 id;重复的 id 会加上“_2”、“_3”等。结果会被加入used。
Component expressions
The component expression language (docs/components/design.md 8.4 and 8.5) lets a layer field inside a component be computed from the component’s properties and the document’s variables. This part of the package parses source text into an Expression tree with spans, type-checks it against an ExpressionEnvironment (the properties, the variables and what stored reads) and the field’s ExpressionType, and rewrites the source when a property, an enum option or a variable is renamed. EXPRESSION_LIBRARY holds the signatures of every constructor and standard library function. evaluateExpression runs a checked expression against an ExpressionValueEnvironment and always gives an ExpressionValue, which wraps the model’s own types where one exists (design.md 8.4, “Values as the model stores them”); ExpressionCache keeps parsed and checked forms per source text and environment version.
源码function parseExpression(source: string): ExpressionParseResultParses source text into an expression tree, or reports the first syntax error.
源码type ExpressionParseResult = | { readonly ok: true; readonly expression: Expression } | { readonly ok: false; readonly error: ExpressionError }What
parseExpressiongives back: a tree, or the first error.
源码const EXPRESSION_SOURCE_LIMIT: 4000The longest expression source the parser accepts, in UTF-16 code units.
源码const EXPRESSION_DEPTH_LIMIT: 64The deepest nesting of sub-expressions the parser accepts.
源码type Expression = | { readonly kind: "boolean"; readonly value: boolean; readonly span: ExpressionSpan; } | { readonly kind: "number"; readonly value: number; readonly unit?: ExpressionUnit; readonly span: ExpressionSpan; } | { readonly kind: "string"; readonly value: string; readonly span: ExpressionSpan; } | { readonly kind: "color"; readonly value: ExpressionColor; readonly span: ExpressionSpan; } | { readonly kind: "option"; readonly name: string; readonly span: ExpressionSpan; } | { readonly kind: "name"; readonly name: string; readonly span: ExpressionSpan; } | { readonly kind: "stored"; readonly span: ExpressionSpan } | { readonly kind: "variable"; readonly name: string; readonly nameSpan: ExpressionSpan; readonly span: ExpressionSpan; } | { readonly kind: "call"; readonly callee: string; readonly calleeSpan: ExpressionSpan; readonly args: readonly ExpressionArgument[]; readonly span: ExpressionSpan; } | { readonly kind: "list"; readonly items: readonly Expression[]; readonly span: ExpressionSpan; } | { readonly kind: "field"; readonly target: Expression; readonly name: string; readonly nameSpan: ExpressionSpan; readonly span: ExpressionSpan; } | { readonly kind: "with"; readonly target: Expression; readonly updates: readonly ExpressionFieldUpdate[]; readonly span: ExpressionSpan; } | { readonly kind: "unary"; readonly operator: "-" | "not"; readonly operand: Expression; readonly span: ExpressionSpan; } | { readonly kind: "binary"; readonly operator: ExpressionBinaryOperator; readonly operatorSpan: ExpressionSpan; readonly left: Expression; readonly right: Expression; readonly span: ExpressionSpan; } | { readonly kind: "if"; readonly condition: Expression; readonly then: Expression; readonly else: Expression; readonly span: ExpressionSpan; } | { readonly kind: "let"; readonly name: string; readonly nameSpan: ExpressionSpan; readonly value: Expression; readonly body: Expression; readonly span: ExpressionSpan; } | { readonly kind: "match"; readonly subject: Expression; readonly arms: readonly ExpressionMatchArm[]; readonly otherwise?: Expression; readonly span: ExpressionSpan; }A node of the expression syntax tree.
kindtells the construct.
源码interface ExpressionSpanA half-open range of UTF-16 offsets in an expression’s source text.
readonly start: number源码readonly end: number源码
源码interface ExpressionErrorA parse or type error, with the text it points at and an optional fix.
readonly message: string源码readonly span: ExpressionSpan源码readonly hint?: string源码A short suggested fix, for example “write
8px”.
源码type ExpressionUnit = "px" | "%" | "deg"The unit suffix of a number literal:
8px,50%,45deg.
源码type ExpressionBinaryOperator = | "or" | "and" | "==" | "!=" | "<" | "<=" | ">" | ">=" | "++" | "+" | "-" | "*" | "/"The two-operand operators, from
or(lowest precedence) to/(highest).
源码interface ExpressionColorAn sRGB colour with every channel from 0 to 1, as a
#rrggbb[aa]literal parses to.readonly red: number源码readonly green: number源码readonly blue: number源码readonly alpha: number源码
源码interface ExpressionArgumentOne argument of a call: positional, or named with
name: value.readonly name?: string源码readonly nameSpan?: ExpressionSpan源码readonly value: Expression源码
源码interface ExpressionFieldUpdateOne
name: valuepair insidewith { ... }.readonly name: string源码readonly nameSpan: ExpressionSpan源码readonly value: Expression源码
源码type ExpressionPattern = | { readonly kind: "option"; readonly name: string; readonly span: ExpressionSpan; } | { readonly kind: "boolean"; readonly value: boolean; readonly span: ExpressionSpan; }A
matcharm pattern: an enum option (.small) or a boolean (true).
源码interface ExpressionMatchArmOne arm of a
match: one or more patterns and the value they give.readonly patterns: readonly ExpressionPattern[]源码readonly body: Expression源码
源码const EXPRESSION_KEYWORDS: readonly [ "if", "then", "else", "let", "in", "match", "with", "or", "and", "not", "true", "false", "stored", "var" ]The words the language reserves; they cannot name a property or a
let.
源码type ExpressionKeyword = (typeof EXPRESSION_KEYWORDS)[number]
源码function parseColorLiteral(text: string): ExpressionColor | undefinedReads a
#rgb,#rgba,#rrggbbor#rrggbbaaliteral into channels from 0 to 1.
源码type ExpressionType = | { readonly kind: "boolean" } | { readonly kind: "number" } | { readonly kind: ExpressionUnitTypeKind } | { readonly kind: "string" } | { readonly kind: "color" } | { readonly kind: "component" } | ExpressionEnumType | { readonly kind: "point" } | { readonly kind: "size" } | { readonly kind: "insets" } | { readonly kind: "corners" } | { readonly kind: "paint" } | { readonly kind: "stroke" } | { readonly kind: "effect" } | { readonly kind: "text_style" } | { readonly kind: "list"; readonly element: ExpressionType }A type of the expression language. Every value has exactly one.
源码type ExpressionUnitTypeKind = "length" | "percent" | "angle"The unit types: numbers that carry a unit and never mix with each other.
源码interface ExpressionEnumTypeAn enum type: a named set of options. Two enum types are the same when their names match.
readonly kind: "enum"源码readonly name: string源码Unique within one checking environment. The property model gives each enum property its own name; layer field enums use the field’s name.
readonly options: readonly string[]源码Option names in display order, as written after the dot:
.large.
源码const EXPRESSION_TYPES: { readonly boolean: { readonly kind: "boolean" }; readonly number: { readonly kind: "number" }; readonly length: { readonly kind: "length" }; readonly percent: { readonly kind: "percent" }; readonly angle: { readonly kind: "angle" }; readonly string: { readonly kind: "string" }; readonly color: { readonly kind: "color" }; readonly component: { readonly kind: "component" }; readonly point: { readonly kind: "point" }; readonly size: { readonly kind: "size" }; readonly insets: { readonly kind: "insets" }; readonly corners: { readonly kind: "corners" }; readonly paint: { readonly kind: "paint" }; readonly stroke: { readonly kind: "stroke" }; readonly effect: { readonly kind: "effect" }; readonly text_style: { readonly kind: "text_style" }; }The types with a single
kindand nothing else, ready to use.
源码const STROKE_ALIGN_TYPE: ExpressionEnumTypeThe enum type of a stroke’s
alignargument and field.
源码function expressionListType(element: ExpressionType): ExpressionTypelist(element).
源码function expressionEnumType( name: string, options: readonly string[] ): ExpressionEnumTypeAn enum type with the given name and options.
源码function expressionTypesEqual(a: ExpressionType, b: ExpressionType): booleanTrue when a value of type
ais also a value of typeb. Enums match by name.
源码function isExpressionUnitType( type: ExpressionType ): type is { readonly kind: ExpressionUnitTypeKind }True for
length,percentandangle.
源码function isExpressionNumeric(type: ExpressionType): booleanTrue for
numberand the unit types: what arithmetic, comparison andminaccept.
源码function formatExpressionType(type: ExpressionType): stringThe type as the language writes it:
length,list(paint),Size (.small, .large).
源码function expressionRecordFields( type: ExpressionType ): Readonly<Record<string, ExpressionType>> | undefinedThe fields a record type exposes to
value.fieldandvalue with { field: ... }, or undefined for a type that is not a record. Field names follow the language’s snake_case (top_left,line_height).
源码const EXPRESSION_LIBRARY: Readonly<Record<string, ExpressionFunction>>Every constructor and standard library function, by name. A null prototype keeps
toStringand the like out of lookups.
源码interface ExpressionFunctionA constructor or standard library function with its overloads, tried in order.
readonly name: string源码readonly group: "numbers" | "colours" | "strings" | "constructors"源码readonly summary: string源码readonly overloads: readonly ExpressionSignature[]源码
源码interface ExpressionSignatureOne way to call a function: its parameters, in order, and its result type.
readonly parameters: readonly ExpressionParameter[]源码readonly rest?: ExpressionType源码When set, any number of extra positional arguments of this type may follow the parameters.
readonly result: ExpressionType源码
源码interface ExpressionParameterOne parameter of a signature. A parameter with a default may be left out.
readonly name: string源码readonly type: ExpressionType源码readonly defaultSource?: string源码The default, as expression source text (
0px,.center); absent for a required parameter.
源码function formatExpressionSignature( name: string, signature: ExpressionSignature ): stringA signature as the language writes it:
min(a: number, b: number, ...) -> number.
源码function checkExpression( expression: Expression, expected: ExpressionType, environment: ExpressionEnvironment ): ExpressionCheckResultType-checks an expression against the type its field expects (
booleanfor a condition), the component’s properties and the document’s variables.
源码function checkExpressionSource( source: string, expected: ExpressionType, environment: ExpressionEnvironment ): ExpressionCheckResultParses and checks source text in one step; a syntax error is the only error reported.
源码interface ExpressionEnvironmentWhat an expression may read, as the checker sees it. Step 3.2 builds one from a component’s properties and the document’s variables.
propertyType(name: string): ExpressionType | undefined源码The type of the component property with this name, or undefined when there is none.
variableType(name: string): ExpressionType | undefined源码The type of the document variable written
"Collection/Name", or undefined when there is none.readonly storedType?: ExpressionType源码The type of the component’s base value of the field being computed, which is what
storedreads. Leave it out for a condition, wherestoredhas no meaning.
源码interface ExpressionCheckResultThe outcome of checking one expression.
readonly ok: boolean源码True when there are no errors.
readonly type?: ExpressionType源码The type of the whole expression, when it could be told.
readonly errors: readonly ExpressionError[]源码readonly references: readonly ExpressionReference[]源码Every property, option and variable the expression names, in source order.
源码type ExpressionReference = | { readonly kind: "property"; readonly name: string; readonly span: ExpressionSpan; } | { readonly kind: "option"; readonly enum: string; readonly name: string; readonly span: ExpressionSpan; } | { readonly kind: "variable"; readonly name: string; readonly span: ExpressionSpan; }A place in the source that names something the editor can rename.
源码function renameInExpression( source: string, expected: ExpressionType, environment: ExpressionEnvironment, renames: | ExpressionRename | readonly ExpressionRename[] ): ExpressionRenameResultRewrites every reference to the renamed properties, options or variables in the source text. The environment and expected type describe the field as it is before the rename, so
.largecan be told apart between enums. Several renames are found in one check of the original source, so a reference half-way through a batch never meets names the environment does not know yet. Source that does not parse is returned unchanged; type errors elsewhere in the expression do not stop the references that do resolve from being rewritten. Aletname that shadows a property is not a reference to it.
源码type ExpressionRename = | { readonly kind: "property"; readonly from: string; readonly to: string } | { readonly kind: "option"; readonly enum: string; readonly from: string; readonly to: string; } | { readonly kind: "variable"; readonly from: string; readonly to: string }What to rename. Names are the ones in force before the rename.
源码interface ExpressionRenameResultThe rewritten source and how many references changed.
readonly source: string源码readonly count: number源码
源码function expressionSignatureAccepts( signature: ExpressionSignature, positionalCount: number, named: ReadonlySet<string> ): booleanTrue when this many positional arguments plus these named ones fill the signature without gaps or extras: every parameter is given once, by position, by name or by its default. The checker and the evaluator pick an overload with it.
源码type ExpressionValue = | { readonly kind: "boolean"; readonly value: boolean } | { readonly kind: "number"; readonly value: number } | { readonly kind: ExpressionUnitTypeKind; readonly value: number } | { readonly kind: "string"; readonly value: string } | { readonly kind: "color"; readonly value: ExpressionColor } | { readonly kind: "component"; readonly id: string } | { readonly kind: "enum"; readonly option: string } | { readonly kind: "point"; readonly x: number; readonly y: number } | { readonly kind: "size"; readonly width: number; readonly height: number } | { readonly kind: "insets"; readonly value: LayoutPadding } | { readonly kind: "corners"; readonly value: CornerRadii } | { readonly kind: "paint"; readonly value: Paint } | { readonly kind: "stroke"; readonly value: Stroke } | { readonly kind: "effect"; readonly value: ExpressionEffect } | { readonly kind: "text_style"; readonly value: ExpressionTextStyle } | { readonly kind: "list"; readonly items: readonly ExpressionValue[] }A value of the expression language.
kindmatches the type’skind.
源码type ExpressionEffect = | { readonly kind: "shadow"; readonly shadow: Shadow } | { readonly kind: "layer_blur"; readonly radius: number } | { readonly kind: "background_blur"; readonly radius: number }One effect. The model keeps shadows in
shadowsand the two blurs as plain radii, so this is the union step 3.3 sorts into those fields.
源码type ExpressionTextStyle = & Pick<TextStyle, "fontFamily" | "fontWeight" | "fontSize"> & { readonly lineHeightPixels: number; readonly letterSpacing: number }The parts of a text style an expression can build; the name and colour come from elsewhere.
lineHeightPixelsis the language’sline_height, a length in pixels. The model’sTextStyle.lineHeightis a multiple of the font size, so whatever applies this value must divide byfontSizefirst.
源码function expressionColorToHex(color: ExpressionColor): stringThe colour as the model stores it:
#rrggbb, or#rrggbbaawhen the alpha is below 1.
源码function expressionColorFromHex(text: string): ExpressionColorReads a model colour string; a string that is not a hex colour reads as opaque black.
源码function zeroExpressionValue(type: ExpressionType): ExpressionValueThe value
0of a type: false, 0, “”, transparent black, the first option, empty records and lists. It is what a division by zero gives and what a missing value falls back to.
源码function expressionValuesEqual(a: ExpressionValue, b: ExpressionValue): booleanTrue when two values of one type are equal, compared by value; what
==gives.
源码function evaluateExpression( expression: Expression, environment: ExpressionValueEnvironment ): ExpressionValueEvaluates an expression that has passed the check. It never throws for such an expression when the environment holds every property, variable and stored value the checking environment typed; a missing one is a programming error and throws, since a wrong value would be a silent failure.
源码interface ExpressionValueEnvironmentWhat an expression reads while it runs: the counterpart of the checking
ExpressionEnvironment, with values in place of types. Every name the checking environment typed must have a value here.propertyValue(name: string): ExpressionValue | undefined源码The value of the component property with this name, or undefined when there is none.
variableValue(name: string): ExpressionValue | undefined源码The value of the document variable
"Collection/Name"in the active mode, or undefined when there is none.readonly stored?: ExpressionValue源码The component’s base value of the field being computed, which
storedreads.
源码function finiteExpressionNumber(value: number): number0 for a number that is not finite (from very large values or 0 / 0); negative zero is plain 0.
源码function clampExpressionAmount(value: number): numberA number held between 0 and 1: what amounts and colour channels become.
源码class ExpressionCacheKeeps parsed and checked expressions per source text for one version of a checking environment. Bump
versionwhenever the properties, the variables or the components change; the cache then starts over.check( source: string, expected: ExpressionType, environment: ExpressionEnvironment, version: string | number ): CheckedExpression源码Parses and checks
sourceagainst the field’s type, or returns the cached result for this version.get size(): number源码How many expressions are cached for the current version.
clear(): void源码Forgets everything.
源码interface CheckedExpressionA parsed and checked expression.
expressionis absent after a syntax error.readonly expression?: Expression源码readonly result: ExpressionCheckResult源码
The expression editor reads the rest. expressionTypeNotes gives the type expected and found at every node, which completion uses on unfinished text through completeExpression; highlightExpression colours source text that may not parse. expressionValueSource writes a value back as source. readValueTable and readShowWhen recognise exactly the value table and “Show when” forms of design.md 8.8, and writeValueTable, setValueTableRow and writeShowWhen build them again.
源码function expressionTypeNotes( expression: Expression, expected: ExpressionType, environment: ExpressionEnvironment ): readonly ExpressionTypeNote[]Checks the expression and returns, for every node and
matchpattern, the type expected there and the type found, in the order the checker visited them. The expression editor reads it for completion (which options fit a.here, which fields a value has) and for the type shown under the text.
源码interface ExpressionTypeNoteWhat the checker knew about one node or
matchpattern: the type it expected there, and the type it found.readonly span: ExpressionSpan源码readonly expected?: ExpressionType源码The type the place asks for, when it asks for one (a field, an argument, the other side of
==, amatchpattern).readonly type?: ExpressionType源码The node’s type, when it could be told.
源码function completeExpression( source: string, caret: number, context: ExpressionCompletionContext, explicit = false ): ExpressionCompletion | undefinedThe completions at
caret. After a.that starts an option literal or pattern it offers the options of the enum expected there; after a.that reads a field, the fields of the value’s type; insidevar("..."), the variables; in a word, properties, variables written asvar("Collection/Name"), functions with their signature and keywords, the ones whose type fits the place first. Names that start with the typed text come before names that only contain it. Returns undefined inside a comment, a colour or another string, or at an empty word unless it followsmatchorexplicitis set (the user asked with Ctrl+Space).
源码interface ExpressionCompletionContextWhat completion offers and where it comes from.
readonly expected: ExpressionType源码The type the whole expression must have: the field’s type, or
booleanfor a condition.readonly environment: ExpressionEnvironment源码readonly properties: readonly string[]源码The component’s property names, in panel order.
readonly variables: readonly string[]源码The document’s variables as
"Collection/Name".
源码interface ExpressionCompletionThe completions at a caret, for the text between
fromandto.readonly from: number源码readonly to: number源码readonly expected?: ExpressionType源码The type expected at the caret, when the checker could tell.
readonly items: readonly ExpressionCompletionItem[]源码
源码interface ExpressionCompletionItemOne completion. Choosing it replaces
from–toof the completion withinsert.readonly kind: | "property" | "option" | "field" | "variable" | "function" | "keyword"源码readonly label: string源码What the list shows.
readonly insert: string源码readonly caret?: number源码Where the caret goes inside
insert(after the(of a function); the end when absent.readonly detail?: string源码The type, or a function’s signature.
readonly fits: boolean源码True when its type is the type expected at the caret; these come first.
源码function highlightExpression( source: string, isProperty: (name: string) => boolean ): ExpressionHighlight[]Splits source text into coloured stretches. It never fails: text the lexer would reject (an unknown character, an unfinished string) comes out as
invalidor as far as it goes. Names arepropertywhenisPropertysays so,functionbefore a(, andnameotherwise (letnames and unknown names).
源码interface ExpressionHighlightOne coloured stretch;
fromandtoare UTF-16 offsets,toexclusive.readonly from: number源码readonly to: number源码readonly kind: ExpressionHighlightKind源码
源码type ExpressionHighlightKind = | "keyword" | "property" | "function" | "name" | "option" | "field" | "number" | "string" | "color" | "comment" | "operator" | "punctuation" | "invalid"What a stretch of source text is, for its colour.
源码function expressionValueSource(value: ExpressionValue): string | undefinedThe value as expression source text that evaluates back to it, such as
8px,.large,insets(4px, 8px)orsolid(#ff0000, 0.5), or undefined when the language cannot write it: a component (there is no component literal), an image paint, a gradient with uneven stops, a paint with a blend mode, a dashed stroke. Numbers keep four decimals.
源码function formatExpressionNumber(value: number): stringUp to four decimals, without trailing zeros and never in exponent form.
源码function formatExpressionString(value: string): stringA string literal with
",\and line breaks escaped as the lexer reads them.
源码function readValueTable( source: string, environment: ExpressionEnvironment ): ExpressionValueTable | undefinedRecognises a value table: a
matchon one enum or boolean property, one pattern per arm, noelse, every arm a constant. Rows follow the property’s option order (“on” before “off”); an option thematchdoes not cover yet (added to the enum later) is a row withoutsource. Returns undefined for anything else, which the editor shows as an expression.
源码function writeValueTable( table: Pick<ExpressionValueTable, "property" | "subject" | "rows"> ): stringWrites a value table as a
match, one arm per row in row order; rows withoutsourceare left out. It fits on one line when short enough, as inmatch size { .small => 4px, .large => 8px }, and otherwise puts each arm on its own line.
源码function startValueTable( property: string, subject: ValueTableSubject, rowSource: string ): stringA new value table over the property with every row holding
rowSource, the field’s current value.
源码function setValueTableRow( source: string, environment: ExpressionEnvironment, key: string, rowSource: string ): stringReplaces one row’s constant. A row that is already written is replaced in place, so the rest of the text (comments, line breaks) stays; a row the
matchdoes not cover yet is added by writing the table again. Throws whensourceis not a value table orkeyis not one of its rows: the caller only offers rows of a table it read.
源码function valueTableSubject( property: string, environment: ExpressionEnvironment ): ValueTableSubject | undefinedThe subject for a property, or undefined when a table cannot vary by it (it is not an enum or boolean).
源码function valueTableKeys( subject: ValueTableSubject ): readonly { readonly key: string; readonly label: string }[]The rows a value table over this subject has, without values.
源码function isConstantExpression(expression: Expression): booleanTrue when the expression reads nothing that changes with property values: no property,
stored,if,letormatch.
源码interface ExpressionValueTableA value table read from source text: one row per option, in the property’s option order.
readonly property: string源码The property the table varies by.
readonly subject: ValueTableSubject源码readonly rows: readonly ValueTableRow[]源码
源码interface ValueTableRowOne row of a value table.
readonly key: string源码The option name, or
"true"/"false"for a boolean.readonly label: string源码What the row shows: the option name, or “on” / “off”.
readonly source?: string源码The row’s constant as source text; absent when the
matchhas no arm for it yet.
源码type ValueTableSubject = | { readonly kind: "enum"; readonly type: ExpressionEnumType } | { readonly kind: "boolean" }What a value table varies by: an enum property’s options, or a boolean’s on and off.
源码function readShowWhen( source: string, environment: ExpressionEnvironment ): ShowWhenCondition | undefinedRecognises a “Show when” condition:
showIcon,not showIcon,size == .large, orsize == .a or size == .b ...with one property, known options and no option twice. Options come back in the order written. Returns undefined for anything else.
源码function writeShowWhen(condition: ShowWhenCondition): stringWrites a “Show when” condition. Throws for an enum condition without options, which would never show the layer.
源码type ShowWhenCondition = | { readonly kind: "boolean"; readonly property: string; readonly on: boolean; } | { readonly kind: "enum"; readonly property: string; readonly options: readonly string[]; }A “Show when” condition in one of the forms of design 8.8.
Component properties
A component’s properties (docs/components/design.md 8.2 and 8.7) are named, typed inputs listed in ComponentDefinition.properties; each instance sets values in InstanceNode.propertyValues, keyed by the stable property ID, and an outer instance can set a nested instance’s values in LayerOverride.propertyValues. Layers inside a component can store expressions (source text keyed by ComputableField) and a condition. assertDocument checks only their shape: an expression that does not check is an allowed state, and the field then shows its stored value.
The adapters connect a document to the expression language: componentExpressionEnvironment and componentValueEnvironment give the checking and evaluation environments of a component (its properties, the document’s variables by "Collection/Name" in the active mode, and stored), computableFieldType and storedFieldValue give a field’s expected type and base value, and expressionFieldContext puts them together for one field. A number variable reads as a length when all its scopes are lengths (variableExpressionType). The operation builders keep expressions valid through edits: renames rewrite every affected expression in the same edit; deletions and kind changes remove instance values that no longer apply and report how many expressions use what changed.
自 0.24.0源码type ComponentPropertyDefinition = | (ComponentPropertyBase<"boolean"> & { readonly defaultValue: boolean }) | ( & ComponentPropertyBase<"number"> & { readonly unit: ComponentNumberUnit; readonly defaultValue: number; readonly min?: number; readonly max?: number; readonly step?: number; }) | ( & ComponentPropertyBase<"text"> & { readonly defaultValue: string; readonly multiline?: boolean }) | ( & ComponentPropertyBase<"enum"> & { readonly options: readonly ComponentPropertyOption[]; readonly defaultValue: string; }) | (ComponentPropertyBase<"color"> & { readonly defaultValue: string }) | ( & ComponentPropertyBase<"instance"> & { readonly defaultValue: ComponentId; readonly preferred?: readonly ComponentId[]; })A named, typed input on a component. Each instance chooses a value for it in
InstanceNode.propertyValues, or leaves the default.
自 0.24.0源码interface ComponentPropertyBase<Kind extends ComponentPropertyKind>Fields every component property has.
readonly id: ComponentPropertyId源码Stable and never shown; instance values are keyed by it.
readonly kind: Kind源码readonly name: string源码Unique in the component and an identifier (letters, digits and
_, not starting with a digit, not a keyword of the expression language): expressions read the property by this name.readonly description?: string源码
自 0.24.0源码type ComponentPropertyKind = (typeof COMPONENT_PROPERTY_KINDS)[number]One of
COMPONENT_PROPERTY_KINDS.
自 0.24.0源码const COMPONENT_PROPERTY_KINDS: readonly [ "boolean", "number", "text", "enum", "color", "instance" ]The kinds of component property, as
ComponentPropertyDefinition.kind.
自 0.24.0源码type ComponentNumberUnit = (typeof COMPONENT_NUMBER_UNITS)[number]One of
COMPONENT_NUMBER_UNITS.
自 0.24.0源码const COMPONENT_NUMBER_UNITS: readonly ["none", "px", "%", "deg"]The unit of a number property:
"none"reads as anumberin expressions,"px"as alength,"%"as apercentand"deg"as anangle.
自 0.24.0源码interface ComponentPropertyOptionOne option of an enum property. The ID is stable; the name is what expressions write after the dot (
.large) and must be an identifier, unique within the property.readonly id: string源码readonly name: string源码
自 0.24.0源码type ComponentPropertyId = Brand<string, "ComponentPropertyId">The stable ID of a component property (
ComponentPropertyDefinition.id), unique within its component. It never changes, so instance values keyed by it survive a rename.
自 0.24.0源码const componentPropertyId: (value: string) => ComponentPropertyIdBrands a string as a
ComponentPropertyId. Throws aTypeErrorfor an empty string.
自 0.24.0源码type ComponentPropertyValue = boolean | number | stringA value an instance sets for a property: a boolean, a number, a string (text), an option ID (enum), a colour string or a component ID (instance swap). A value that does not fit the property’s current kind is ignored, as is a value for a property the component no longer has.
自 0.24.0源码type ComponentPropertyValues = Readonly<Record<string, ComponentPropertyValue>>Property values keyed by
ComponentPropertyId. Missing means the default.
自 0.24.0源码type ComputableField = | (typeof COMPUTABLE_FIELDS)[number] | `propertyValues.${string}`A field that can hold an expression: a
COMPUTABLE_FIELDSname orpropertyValues.<property id>.
自 0.24.0源码const COMPUTABLE_FIELDS: readonly [ "visible", "opacity", "fills", "strokes", "effects", "cornerRadius", "cornerRadii", "cornerSmoothing", "width", "height", "minWidth", "maxWidth", "minHeight", "maxHeight", "gap", "wrapGap", "columnGap", "rowGap", "padding", "direction", "align", "justify", "wrap", "characters", "fontFamily", "fontSize", "fontWeight", "lineHeight", "letterSpacing", "textColor", "textStyle", "componentId" ]The layer fields that can hold an expression. Which ones apply depends on the node type (see
computableFieldsOf);propertyValues.<property id>computes a nested instance’s property value. Position, rotation, flips, blend modes, masks and the layer name are not computable.
自 0.24.0源码type NamedComputableField = (typeof COMPUTABLE_FIELDS)[number]A computable field other than
propertyValues.<id>.
自 0.24.0源码type NodeExpressions = Readonly<Partial<Record<ComputableField, string>>>Expression source text keyed by computed field.
自 0.24.0源码function computableFieldsOf(node: SceneNode): readonly NamedComputableField[]The named fields a node of this type can compute, in
COMPUTABLE_FIELDSorder. An instance node can also computepropertyValues.<property id>for any property of its component.
自 0.24.0源码function isComputableField( node: SceneNode, field: string ): field is ComputableFieldTrue when
fieldcan hold an expression on this node. It checks the name only: apropertyValues.<id>field naming a property the nested component does not have is allowed and has no effect.
自 0.24.0源码function propertyValueFieldId(field: string): string | undefinedThe property ID in a
propertyValues.<property id>field, or undefined for any other field.
自 0.24.0源码const PROPERTY_VALUE_FIELD_PREFIX: "propertyValues."The prefix of the computed field that holds a nested instance’s property value.
自 0.24.0源码const COMPUTABLE_FIELD_VARIABLE_PROPERTIES: Readonly< Record<NamedComputableField, readonly VariableProperty[]> >The variable binding properties that set the same value as a computed field. A field holds a binding or an expression, never both: saving an expression removes these bindings.
自 0.24.0源码function variablePropertiesOfField(field: string): readonly VariableProperty[]The variable binding properties that clash with a computed field; empty for
propertyValues.<id>.
自 0.24.0源码function isExpressionIdentifier(name: string): booleanTrue when
namecan be written in an expression as a property or an enum option name: letters, digits and_, not starting with a digit, and not a keyword of the language.
自 0.24.0源码function findComponentProperty( component: ComponentDefinition, propertyId: string ): ComponentPropertyDefinition | undefinedThe property with this ID, or undefined.
自 0.24.0源码function findComponentPropertyByName( component: ComponentDefinition, name: string ): ComponentPropertyDefinition | undefinedThe property with this name, or undefined.
自 0.24.0源码function propertyValueFits( property: ComponentPropertyDefinition, value: ComponentPropertyValue ): booleanTrue when
valuefits the property’s kind: a boolean for a boolean, a finite number for a number, a string for text and colour, an existing option ID for an enum, and a non-empty string for an instance swap.
自 0.24.0源码function effectivePropertyValue( property: ComponentPropertyDefinition, value: ComponentPropertyValue | undefined ): ComponentPropertyValueThe value a property takes: the given value when it fits the property’s kind, else the default.
自 0.24.0源码const LENGTH_VARIABLE_PROPERTIES: readonly VariableProperty[]The binding properties that hold a length in pixels. A
numbervariable whose scopes are all in this list reads as alengthin expressions.
自 0.24.0源码function variableExpressionType(variable: VariableDefinition): ExpressionTypeThe type a variable reads as in expressions. Colour, string and boolean variables read as
color,stringandboolean. Anumbervariable reads as alength(pixels) when it has scopes and every scope is a length (LENGTH_VARIABLE_PROPERTIES), and as a plainnumberotherwise: with no scopes, or any scope such as opacity, font weight or line height.
自 0.24.0源码function variableExpressionName( collectionName: string, variableName: string ): stringThe name an expression reads a variable by:
"Collection/Name".
自 0.24.0源码function variablesByExpressionName( theme: DocumentTheme ): ReadonlyMap<string, LocatedVariable>The document’s variables by
"Collection/Name". A name that two variables share is left out, so an expression that uses it shows an unknown-variable error instead of reading either one.
自 0.24.0源码function variableExpressionValue( located: LocatedVariable, modes?: VariableModes ): ExpressionValue | undefinedThe value of a variable in the mode its collection shows under
modes(seeresolveVariableValue; withoutmodes, the active mode), typed asvariableExpressionType.
自 0.24.0源码function componentPropertyExpressionType( property: ComponentPropertyDefinition, enumName: string = property.name ): ExpressionTypeThe type a property reads as:
boolean,string(text),color,component(instance swap), an enum type namedenumName(the property name by default) with the option names, or for a number propertynumber,length,percentorangleby its unit.
自 0.24.0源码function componentPropertyExpressionValue( property: ComponentPropertyDefinition, value?: ComponentPropertyValue ): ExpressionValueThe expression value of a property:
valuewhen it fits the property’s kind, else the default. An enum value reads as its option’s name.
自 0.24.0源码function nestedPropertyEnumName( component: ComponentDefinition, property: ComponentPropertyDefinition ): stringThe enum type name of a nested component’s property, as an outer component’s expressions see it:
"<component name>.<property name>". A property name has no dot, so it never clashes with the outer component’s own enum types, which are named after their properties.
自 0.24.0源码function componentExpressionEnvironment( document: DesignDocument, component: ComponentDefinition | ComponentId, storedType?: ExpressionType ): ExpressionEnvironmentThe checking environment of a component’s expressions: its properties by name, the document’s variables by
"Collection/Name", andstoredTypeforstored(leave it out for a condition).
自 0.24.0源码function componentValueEnvironment( document: DesignDocument, component: ComponentDefinition | ComponentId, propertyValues: ComponentPropertyValues = {}, stored?: ExpressionValue, modes?: VariableModes ): ExpressionValueEnvironmentThe evaluation environment matching
componentExpressionEnvironment: each property’s value frompropertyValues(an instance’s values; values that do not fit and missing ones read as the default), each variable in the mode its collection shows undermodes(the active mode by default), andstored.
自 0.24.0源码type ExpressionField = ComputableField | "condition"A computed field, or
"condition".
自 0.24.0源码const LAYOUT_DIRECTION_TYPE: ExpressionEnumTypeThe enum type of the
directionfield.
自 0.24.0源码const LAYOUT_ALIGN_TYPE: ExpressionEnumTypeThe enum type of the
alignfield.
自 0.24.0源码const LAYOUT_JUSTIFY_TYPE: ExpressionEnumTypeThe enum type of the
justifyfield;space_betweenand the others are the model’s"space-between"and so on.
自 0.24.0源码function computableFieldType( document: DesignDocument, node: SceneNode, field: ExpressionField ): ExpressionType | undefinedThe type an expression in
fieldmust have:booleanfor a condition, the field’s type from the table in design 8.3, or forpropertyValues.<id>the type of that property of the nested instance’s component (with its enum named bynestedPropertyEnumName). Undefined for a field the node cannot compute or a property the nested component does not have.
自 0.24.0源码function storedFieldValue( document: DesignDocument, node: SceneNode, field: ExpressionField ): ExpressionValue | undefinedThe base value of a computed field, which
storedreads: the plain value stored on the node, as an expression value. Absent optional values read as zero (for example a missingmaxWidthis 0 px, a missing corner radius 0 px). The text fields read the first run’s resolved style; line height, a multiplier in the model, reads as a percent (1.5 is 150%), and as a length intext_style(1.5 at 16 px is 24 px). A height, a multiplier in the model, reads as a percent (1.5 is 150%), and as pixels inside atext_style(1.5 at 14 px is 21 px). A nested instance’spropertyValues.<id>reads the value stored on the node, else the nested component’s default. Undefined for a condition and for fieldscomputableFieldTypedoes not type.
自 0.24.0源码interface ExpressionFieldContextWhat checking one computed field or condition needs.
readonly expected: ExpressionType源码readonly environment: ExpressionEnvironment源码
自 0.24.0源码function expressionFieldContext( document: DesignDocument, component: | ComponentDefinition | ComponentId, node: SceneNode, field: ExpressionField ): ExpressionFieldContext | undefinedThe expected type and checking environment of one field of a layer in
component, or undefined when the field has no type (seecomputableFieldType).
自 0.24.0源码function expressionFieldValueEnvironment( document: DesignDocument, component: ComponentDefinition | ComponentId, node: SceneNode, field: ExpressionField, propertyValues: ComponentPropertyValues = {}, modes?: VariableModes ): ExpressionValueEnvironmentThe evaluation environment of one field of a layer in
componentfor an instance withpropertyValues:componentValueEnvironmentwithstoredset tostoredFieldValue.
自 0.24.0源码interface ComponentExpressionSiteOne stored expression: a computed field or a condition of a layer.
readonly nodeId: NodeId源码readonly field: ExpressionField源码readonly source: string源码
自 0.24.0源码function componentLayerIds( document: DesignDocument, component: ComponentDefinition | ComponentId ): readonly NodeId[]The IDs of a component’s layers, root first, in tree order.
自 0.24.0源码function componentExpressionSites( document: DesignDocument, component: | ComponentDefinition | ComponentId ): readonly ComponentExpressionSite[]Every expression and condition stored on a component’s layers, in tree order, conditions after the node’s computed fields.
自 0.24.0源码function componentPropertyUsage( document: DesignDocument, componentId: ComponentId, propertyId: string, optionId?: string ): numberHow many of
component’s expressions and conditions name the property (or, withoptionId, that option of an enum property), plus thepropertyValues.<id>expressions of nested instances of it in other components that name the option. The editor shows it before a deletion or a kind change (“3 expressions use size”).
自 0.24.0源码interface ExpressionEditResultOperations for one edit, and how many expressions it touches.
readonly operations: readonly DocumentOperation[]源码Apply them together, in one
applyOperationscall.readonly count: number源码For a rename, how many references were rewritten; for a deletion or a kind change, how many expressions use what changed and will stop checking (see
componentPropertyUsage).
自 0.24.0源码function renameComponentPropertyOperations( document: DesignDocument, componentId: ComponentId, propertyId: string, name: string ): ExpressionEditResultRenames a property and rewrites every expression in the component that reads it, in one edit. Throws a
ModelErrorwhen the name is not an identifier or another property has it.
自 0.24.0源码function renameComponentPropertyOptionOperations( document: DesignDocument, componentId: ComponentId, propertyId: string, optionId: string, name: string ): ExpressionEditResultRenames an option of an enum property and rewrites every expression that names it: in the component, and in
propertyValues.<id>expressions of nested instances of the component inside other components. Option IDs do not change, so instance values need no edit.
自 0.24.0源码function deleteComponentPropertyOperations( document: DesignDocument, componentId: ComponentId, propertyId: string ): ExpressionEditResultDeletes a property. In the same edit it removes every instance’s value for it (instance nodes and nested instance overrides) and the
propertyValues.<id>expressions of nested instances of the component. Expressions that read the property are kept and stop checking, so they fall back to the stored value;countsays how many there are.
自 0.24.0源码function deleteComponentPropertyOptionOperations( document: DesignDocument, componentId: ComponentId, propertyId: string, optionId: string ): ExpressionEditResultDeletes one option of an enum property. Instance values that chose it are removed in the same edit, so those instances take the default; when the option was the default, the first remaining option becomes the default. Expressions that name the option are kept and stop checking;
countsays how many. Throws aModelErrorfor the last option.
自 0.24.0源码function changeComponentPropertyOperations( document: DesignDocument, componentId: ComponentId, next: ComponentPropertyDefinition ): ExpressionEditResultReplaces a property’s definition with one of another kind (or the same kind with other settings), keeping its ID and name; rename with
renameComponentPropertyOperations. Instance values that do not fit the new definition are removed in the same edit. Expressions that read the property, andpropertyValues.<id>expressions of nested instances of the component, are kept and may stop checking;countis how many there are (0 when the kind is unchanged and so are a number’s unit and an enum’s option names: a new option makes amatchnon-exhaustive and a removed one leaves references unresolved). Throws aModelErrorwhen a number property’s minimum is above its maximum.
自 0.24.0源码function renameVariableOperations( document: DesignDocument, variableId: VariableId, name: string ): ExpressionEditResultRenames a variable and rewrites every
var("Collection/Name")that reads it, in every component, in one edit.
自 0.24.0源码function renameVariableCollectionOperations( document: DesignDocument, collectionId: VariableCollectionId, name: string ): ExpressionEditResultRenames a variable collection and rewrites every
var("Collection/Name")that reads one of its variables, in every component, in one edit.
自 0.24.0源码const propertySampleIds: { readonly document: DocumentId; readonly page: PageId; readonly pageRoot: NodeId; readonly textStyle: TextStyleId; readonly button: ComponentId; readonly buttonRoot: NodeId; readonly buttonIcon: NodeId; readonly buttonLabel: NodeId; readonly size: ComponentPropertyId; readonly small: "opt-small"; readonly large: "opt-large"; readonly kind: ComponentPropertyId; readonly primary: "opt-primary"; readonly secondary: "opt-secondary"; readonly disabled: ComponentPropertyId; readonly label: ComponentPropertyId; readonly icon: ComponentPropertyId; readonly showIcon: ComponentPropertyId; readonly plus: ComponentId; readonly plusRoot: NodeId; readonly plusShape: NodeId; readonly iconSize: ComponentPropertyId; readonly iconSmall: "icon-small"; readonly iconLarge: "icon-large"; readonly minus: ComponentId; readonly minusRoot: NodeId; readonly buy: NodeId; readonly plain: NodeId; readonly brand: VariableCollectionId; readonly brandMode: VariableModeId; readonly accent: VariableId; readonly radius: VariableId; readonly fade: VariableId; }The IDs the property sample uses, so tests can refer to them by name.
自 0.24.0源码function propertyButtonSample(): DesignDocumentThe Button of design 8.10 with its expressions, nested Icon/Plus instance and text label, two Button instances on the page, and a Brand variable collection with a colour, a length (
radius, scoped to corner radius) and a plain number (fade, unscoped).
代码样式
新代码节点的默认值以及两套内置语法配色,改编自采用 MIT 许可证的 Code - OSS 主题。
源码const CODE_FONT_FAMILY: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace"
源码const CODE_FONT_SIZE: 32
源码const CODE_LINE_HEIGHT: 1.3
源码const BUILT_IN_CODE_STYLES: Readonly<Record<string, CodeStyle>>
源码const DARK_2026_CODE_STYLE: CodeStyle
源码const DARK_2026_CODE_STYLE_ID: CodeStyleId
源码const LIGHT_2026_CODE_STYLE: CodeStyle
源码const LIGHT_2026_CODE_STYLE_ID: CodeStyleId
源码function getCodeLineNumberStart( lineNumbers: CodeNode["lineNumbers"] ): number | null行号隐藏时返回
null,否则返回首行行号。
文本测量
解析文本的实际生效样式,并用 2D 画布上下文(OffscreenCanvas 或 DOM 画布)测量文本节点,用于在渲染器之外进行的布局,例如自动调整大小的文本框。两种画布都不可用时,测量会抛出错误。
源码function resolveTextStyle( document: DesignDocument, styleId: string | undefined, overrides: TextStyleOverrides | undefined ): TextStyle
源码function resolveTextFontFamily( document: DesignDocument, style: TextStyle ): string将嵌入字体的标识解析为特定于资源的 CSS 字体族栈。主嵌入字体替换作者指定的主字体族,其后依次是有序的嵌入回退字体,作者指定的 CSS 回退部分保留在最后。资源别名使同一字体族的不同字体保持区分且结果确定。
源码function documentFontFamilyAlias(assetId: string): string返回某个文档字体资源标识所使用的稳定 CSS 字体族名。
源码function textStyleToCanvasFont( style: TextStyle, document?: DesignDocument ): string
源码function measureTextNode( document: DesignDocument, node: TextualNode, paragraphs: readonly TextParagraph[] = node.paragraphs ): TextMeasurement
源码interface TextMeasurementreadonly width: number源码readonly height: number源码readonly lineCount: number源码readonly lines: readonly TextLineMetrics[]源码
源码interface TextLineMetricsreadonly width: number源码readonly ascent: number源码readonly descent: number源码readonly height: number源码
源码function getTextNodeBaselines( document: DesignDocument, node: TextualNode, paragraphs: readonly TextParagraph[] = node.paragraphs ): readonly number[]
源码function getAutoSizedTextFrame( document: DesignDocument, node: TextualNode, paragraphs: readonly TextParagraph[] = node.paragraphs ): Rect译文已过期
The frame an auto-sized text box takes for its content: the size the renderer gave a text like it (
recordDrawnTextSize), or, until the renderer has drawn one, an estimate measured with the browser canvas. Fixed-size text keeps its frame. The new frame keeps the point fromtextAutoResizeAnchorin place on the page.
源码function autoResizedTextFrame( node: Pick<TextualNode, "frame" | "rotation">, paragraphs: readonly TextParagraph[], size: { readonly width: number; readonly height: number } ): Rect自动调整大小的文本框在内容改变其尺寸后的画框。文本框绕其中心旋转,因此若保持
frame.x和frame.y不变,旋转的文本会在增长时在页面上移动;此函数改为让textAutoResizeAnchor给出的锚点在页面空间中保持不动。
源码function textAutoResizeAnchor( paragraphs: readonly TextParagraph[] ): { readonly x: number; readonly y: number }内容改变文本框尺寸时,文本框在页面上保持不动的点,以画框局部宽度和高度的比例表示。与 Figma 相同,顶边保持不动,自动宽度的文本保持其对齐边:左对齐或两端对齐的文本保持左边,居中文本保持中心,右对齐文本保持右边。各段落对齐方式不一致时,保持左边不动。
源码function resolveTextListLayout( document: DesignDocument, paragraph: TextParagraph, paragraphIndex: number ): TextListLayout | null
源码interface TextListLayoutreadonly text: string源码readonly style: TextStyle源码readonly gap: number源码readonly nestingOffset: number源码由作者指定的列表层级额外带来的正文和标记缩进。
readonly left: number源码readonly right: number源码readonly firstLine: number源码readonly markerWidth: number源码readonly markerBoxWidth: number源码
源码function resolveListMarkerStyle( document: DesignDocument, paragraph: Pick<TextParagraph, "runs" | "list"> ): TextStyleThe style a list marker of the paragraph is drawn in. A marker takes the shared style and the overrides it does not name itself from the first run of its paragraph, each on its own: a marker with a style and no overrides still takes the first run’s overrides. A marker the renderer writes itself (a bullet or a number) takes both. The page compiler, the canvas estimate and
textLayoutKeyall resolve markers here, so they cannot disagree.
源码function getTextNodeFontRequests( document: DesignDocument, node: TextualNode, paragraphs: readonly TextParagraph[] = node.paragraphs ): readonly TextFontRequest[]
源码interface TextFontRequestreadonly font: string源码readonly text: string源码
源码function clearTextMeasurementCache(): void
其他导出
尚未归入上述章节的导出,按字母顺序排列。
自 0.25.0源码function applyComputedFields( document: DesignDocument, node: SceneNode, results: readonly { readonly field: ComputableField; readonly value: ExpressionValue; }[], onError?: (field: ComputableField, message: string) => void ): SceneNodenodewith each computed value written into its model field and clamped to the field’s range. Fields the node type cannot compute are ignored. A text layer that sizes itself is measured again when its text changed.
自 0.26.0源码function carryPropertyExpressions( from: ComponentDefinition | undefined, to: ComponentDefinition, expressions: NodeExpressions | undefined ): NodeExpressions | undefinedExpressions carried from one component’s instance to another’s, as property values are: a
propertyValues.<id>field is renamed to the new component’s property with the same name and kind, and dropped when there is none or the old component lacks the ID. Other fields stay. Undefined when nothing is left.
自 0.26.0源码function carryPropertyValues( from: | ComponentDefinition | undefined, to: ComponentDefinition, values: | Readonly< Record< string, ComponentPropertyValue > > | undefined, mapComponent: ( id: ComponentId ) => ComponentId = (id) => id ): Record<string, ComponentPropertyValue> | undefinedProperty values carried from one component to another, as a swap does (design 8.9): a value is kept when the new component has a property with the same name and kind; an enum value only when the new property has an option with the same name, and then as that option’s ID. Values that do not fit, or name a property the old component does not have, are dropped. An instance swap value goes through
mapComponent, for a paste that maps component IDs. Undefined when nothing is left.
源码function clearDrawnTextSizes(documentId?: DocumentId): voidForgets every drawn text size of one document, or of all documents when none is given.
自 0.25.0源码interface ComponentExpressionErrorA stored expression or condition that does not parse or check. It is not evaluated: the field shows its stored value, and a condition counts as no condition (design 8.5).
readonly nodeId: NodeId源码readonly field: ExpressionField源码readonly source: string源码readonly errors: readonly ExpressionError[]源码
自 0.25.0源码function componentExpressionErrors( document: DesignDocument, componentId: ComponentId, options?: ResolveInstanceOptions ): readonly ComponentExpressionError[]The expressions and conditions on
componentId’s layers that do not parse or check, in tree order. Each is left out when the component is resolved: the field shows its stored value, and a condition counts as no condition (design 8.5). After them come the computed values the default property values make invalid, such as a font family with no font in the document, which show their stored value too. A nested component’s errors are listed under its own ID.
自 0.25.0源码interface ComputedComponentA component’s layer tree for one set of property values, before overrides and layout: the layers a condition leaves out, and the layers with computed fields written into their model fields.
readonly nodes: ReadonlyMap<NodeId, SceneNode>源码Layers with at least one computed field, by stored ID; every other layer is as stored.
readonly leftOut: ReadonlySet<NodeId>源码Layers whose condition is false. Their sublayers are left out with them and are not listed.
readonly errors: readonly ComponentExpressionError[]源码Computed values these property values make invalid; each field shows its stored value.
源码function computedTextFitOperations( document: DesignDocument, componentIds: readonly ComponentId[] ): readonly DocumentOperation[]The node replacements that bring the stored sizes of
componentIdsup to date with the sizes their texts are drawn at, with no edit to follow: each component’s self-sizing computed texts, the auto layout frames around them, and every instance of the components (an instance with its own property values or text overrides included) with the frames around it. Empty when every stored size already fits.The editor calls it when the renderer has measured a text at another size than the estimate the stored sizes were derived from (
recordDrawnTextSize).
源码function confirmDrawnTextSize(document: DesignDocument, node: TextualNode): voidMarks the remembered size of a text as right for the font files in use: the renderer has just drawn the text at that size. Does nothing for a text with no remembered size, or with another one.
源码function documentWithVariantInstance( document: DesignDocument, instance: InstanceNode ): DesignDocumentdocumentwithinstanceadded to its nodes, so the resolver can read it.
自 0.26.0源码function drawnNodes(document: DesignDocument): readonly SceneNode[]Every node the renderer draws, for code that scans the document for the fonts, characters or assets its text uses: the stored nodes (page layers and component layers), then the layers of every stored instance as
resolveInstancederives them, with the instance’s overrides, property values and nested instances applied and the virtual ID asid. Text or a font that exists only in an override is found here and nowhere indocument.nodes. An instance that cannot be resolved (a missing component or a nesting cycle) adds no layers; the compiler reports that itself. The same document object gives the same array, and unchanged instances give the same layer objects, so per-node caches keyed by object stay warm.
源码function drawnTextSize( document: DesignDocument, node: TextualNode, paragraphs: readonly TextParagraph[] = node.paragraphs ): DrawnTextSize | undefinedThe size the renderer gave a text like this one in this document, when it has drawn one.
源码interface DrawnTextSizeThe size the renderer gave a text it drew.
readonly width: number源码readonly height: number源码
自 0.25.0源码function filledPropertyValues( component: ComponentDefinition, values: ComponentPropertyValues = {} ): readonly ComponentPropertyValue[]The instance’s values for
component’s properties with defaults filled in, in the component’s property order: the key of a computed result.
源码function forgetDrawnTextSizesOfEarlierFonts(documentId: DocumentId): numberForgets the sizes of a document that were recorded with earlier font files and that no draw has found right since (
setDrawnTextFontSet): text that is not drawn now, whose size with the files in use is unknown. Such a text is estimated again and corrected when it is next drawn. Call it once every text on screen is settled. Returns how many sizes were forgotten.
源码function getDrawnTextSizesVersion(): numberChanges whenever a drawn text size is recorded, changed or forgotten, in any document. Anything that keeps sizes derived from
getAutoSizedTextFrame(resolved instances, the component view) compares it to know they are out of date.
源码type GroupVariableBindings = Readonly< & Partial<Record<GroupVariableProperty, VariableId>> & { readonly width?: never; readonly height?: never } >A group’s variable bindings. A group’s size is always computed from its layers, so a group never binds
widthorheight.
源码type GroupVariableProperty = Exclude<VariableProperty, "width" | "height">The variable properties a group can bind: all but its size.
源码function hasComputedTextContent(node: SceneNode | undefined): booleanWhether the node is a text layer whose content is computed: bound to a component property, varied by a property, or written as an expression (all three are stored as its
charactersexpression).
自 0.23.0源码function isLayerInDocument(document: DesignDocument, id: NodeId): booleanTrue when
idnames a layer the document shows: a stored node that exists, or a virtual ID whose every path segment is a layer of the component shown by the instance above it (the outer instance, then each nested instance as swapped). A node moved out of a component, or deleted, leaves the virtual IDs through it unresolved.
自 0.24.0源码function isLayoutFieldInUse(node: SceneNode, field: string): booleanFalse for a layout field the frame’s current layout kind does not use:
gapon a grid or absolute frame,columnGapon a stack, any layout field on an absolute frame. True for every other field. A frame can keep an expression on any layout field (seecomputableFieldsOf), so it stays valid when the layout kind changes; the resolver applies, and the editor offers, only the fields in use.
源码const jsonCodecStats: { jsonPathAllocations: number; canonicalJsonCalls: number; }
源码const modelApplyStats: { documentDiffs: number; operationDeserializes: number; positionMapContainersVisited: number; }
源码function multiplyTransforms( left: TransformMatrix, right: TransformMatrix ): TransformMatrixComposes two affine transforms. The result applies
rightfirst, thenleft. Matrices use the[a, b, c, d, e, f]layout, wherex' = a*x + c*y + eandy' = b*x + d*y + f. In 3×3 form this is the matrix product , so .
源码function nodeIdsRenamedWithSuffix(nodeIds: readonly string[]): string[]The stored node IDs in
nodeIdswhose 0.23.0 rename needs a collision suffix, because their plain “_” form is already taken. Operation migration cannot see those suffixes, so a stored history whose root document has one is ambiguous.
源码function nodeLocalTransform(node: SceneNode): TransformMatrixThe transform from a layer’s own coordinates (the top-left of its frame at the origin) to its parent’s: its flips, then its rotation, both about the middle of its frame, then its position. A path carries its transform itself. A layer that is not rotated or flipped gives exactly its position, with no rounding.
源码function nodePageTransform( document: DesignDocument, id: NodeId, parents: ReadonlyMap< NodeId, NodeId > = buildParentMap(document.nodes), transforms = new Map<NodeId, TransformMatrix>() ): TransformMatrixThe transform from a layer’s own coordinates to canonical page coordinates: every ancestor’s position, rotation and flips, then the layer’s own. The structural root (a page’s root frame, or the root of a component) is the coordinate origin, so its own transform is left out. Pass
parents(frombuildParentMap) and atransformscache when calling this for many layers of one document.
自 0.23.0源码const OVERRIDE_FIELD_PROPERTIES: Readonly< Partial<Record<OverrideField, readonly VariableProperty[]>> >The variable properties each override field can bind (decision A). A property missing here (size, corner radius, gaps, padding) binds a field that is not overridable, so a binding for it is
unsupportedon a virtual ID.
自 0.23.0源码function overrideFieldForProperty(property: string): OverrideField | undefinedThe override field a variable property belongs to, or
undefinedwhen that property binds a field an instance cannot override.
源码function recordDrawnTextSize( document: DesignDocument, node: TextualNode, size: DrawnTextSize ): booleanRemembers the size the renderer gave an auto-sized text it drew, so every text of the same document with the same words, styles, font files and sizing takes that size from now on (
getAutoSizedTextFrame). The renderer is the authority for text sizes: it lays text out with the fonts it draws with, which the browser canvas often cannot measure (a Google Fonts family, an automatic fallback font).nodeis the text as it was drawn; its frame’s width is part of the key when only its height follows the text. Returns whether the size is new or differs from the one remembered, in which casedrawnTextSizesVersionchanges and sizes derived before it are out of date.
源码function resetJsonCodecStats(): void
源码function resetModelApplyStats(): void
源码function resetTextMeasurementStats(): void
自 0.26.0源码function resolvedShownComponents( document: DesignDocument, instanceId: NodeId ): (path: readonly NodeId[]) => ComponentId | undefinedA
shownComponentAtfor the stored instanceinstanceId: the component each nested instance shows once the instance resolves, so a component an instance swap property selects counts. The instance resolves on the first lookup. A path the resolved tree leaves out (a layer hidden by its condition), or an instance that does not resolve, gives undefined, and the stored component counts.
源码function setDrawnTextFontSet(documentId: DocumentId, name: string): booleanTells the memory which font files the renderer draws a document with.
namestands for the whole set: every file of every font asset that has arrived (a Google Fonts family arrives in parts) and the fallback fonts the renderer picks itself, none of which the document names. The same name twice changes nothing, so every surface that shows the document can say it.With another name, the sizes recorded so far are from other files and may be wrong. They are kept for now, so text on screen does not jump to the canvas estimate and back: each is either found right by the next draw (
confirmDrawnTextSize) or replaced (recordDrawnTextSize), and the ones no draw vouched for are dropped byforgetDrawnTextSizesOfEarlierFonts. Returns whether the name changed.
源码function splitCssFontFamilies(fontFamily: string): readonly string[]
源码function textLayoutKey( document: DesignDocument, node: Pick< TextualNode, "autoResize" | "wrap" | "frame" | "paragraphs" >, paragraphs: readonly TextParagraph[] = node.paragraphs ): stringNames everything in the document that decides the size of an auto-sized text: its words, the styles they resolve to in this document (so a theme or variable mode that changes a style changes the key), the font file each of their font assets stands for, the paragraph settings, how the box sizes itself, and its width when only its height follows the text. A list marker is named by the style the renderer draws it in (
resolveListMarkerStyle), which can come from the first run of its paragraph. Two texts of one document with the same key are laid out alike by the renderer (the order in which the fields of a style or a paragraph were written is not part of the key), as long as it draws with the same font files; the files that are not in the document (which parts of a Google Fonts family have arrived, the fallback fonts the renderer picks itself) are told apart bysetDrawnTextFontSet. The drawn sizes are kept by this key (recordDrawnTextSize), and anything else that remembers or counts something about one layout of a text uses it too, so a change of font, size, wrap width or sizing mode is never taken for the layout before it.
源码const textMeasurementStats: { layoutComputations: number; fontRequestTextRebuilds: number; resolvedStyleCopies: number; }
源码const VARIANT_VIEW_CAP: 64The most views “Show all variants” draws; above it the user picks which properties to vary.
源码interface VariantCombinationOne “Show all variants” view: its property values and label.
readonly values: ComponentPropertyValues源码The values that differ from the defaults; the defaults view has none.
readonly label: string源码The values that differ from the defaults (“size: large, disabled”), or “Component” for the defaults.
readonly key: string源码Stable text for the combination (“” for the defaults), for editor-only IDs.
自 0.27.0源码function variantCombinationOf( component: ComponentDefinition, values: ComponentPropertyValues ): VariantCombinationThe combination that
valuesname: the enum and boolean values that differ from the defaults (a value no option has counts as the default), with the label and keyvariantCombinationsgives the same view. Values of other kinds of property are left out; a view keeps their defaults.
源码function variantCombinations( component: ComponentDefinition, vary?: readonly ComponentPropertyId[] ): readonly VariantCombination[]The combinations of the varied properties’ values (every variant property when
varyis omitted), the first property changing slowest and each property’s default first, so the first combination is the defaults. Empty when there would be more thanVARIANT_VIEW_CAPviews.
源码function variantInstanceNode( document: DesignDocument, componentId: ComponentId, id: NodeId, name: string, values: ComponentPropertyValues ): InstanceNode | undefinedAn editor-only instance of
componentIdwithvalues, at the page origin with the component root’s size for those values (a computed fixed width or height included): what a variant view draws.
源码function variantLabel( component: ComponentDefinition, values: ComponentPropertyValues ): stringThe label of a view with these values: each value that differs from the default, in the component’s order. An enum reads “size: large”, a boolean that is on reads “disabled” and one that is off reads “showIcon: off”. “Component” when every value is the default.
源码function variantProperties( component: ComponentDefinition ): readonly VariantProperty[]The component’s enum and boolean properties, in the component’s order.
源码type VariantProperty = Extract< ComponentPropertyDefinition, { readonly kind: "enum" | "boolean" } >A property “Show all variants” can vary: an enum or a boolean.
源码function variantPropertyValues( property: VariantProperty ): readonly ComponentPropertyValue[]The values a variant property takes across the views, the default first: a boolean’s default then its opposite, an enum’s default option then the other options in their order.
源码function variantViewCount( component: ComponentDefinition, vary?: readonly ComponentPropertyId[] ): numberHow many views varying these properties (every variant property when omitted) gives.
源码function variantViewSize( document: DesignDocument, componentId: ComponentId, values: ComponentPropertyValues, options?: ResolveInstanceOptions ): { readonly width: number; readonly height: number } | undefinedThe natural size of the component with
values: the resolved root of an instance with those values (hugging axes take their content’s size).
自 0.26.0源码function withoutClashingBindings<T extends SceneNode>(node: T): TThe node without the variable bindings that clash with its expressions: a field holds a binding or an expression, never both, and the expression wins. The same node when nothing clashes.
@taco-slides/editor TypeScript
474 个导出中已记录 308 个 · 大纲
@taco-slides/editor 是交互式编辑中不依赖浏览器和渲染器的部分。它依赖文档模型(@taco-slides/model),但不依赖 React、DOM、Playwright、Skia 或原生渲染器。其中大部分是纯函数:接收文档、当前编辑器状态和一个输入事件,返回下一个状态以及对改动内容的描述。文档操作和历史记录由调用方负责。
原始指针输入和屏幕几何使用相对于交互表面的 CSS 像素。ViewportState.documentToScreen 把文档单位映射到这个空间。设备像素只来自 devicePixelRatio,从不作为指针输入接受。
本包还定义了编辑器与渲染器之间的边界:由共享测试场景驱动的 EditorDriver,以及负责回答命中测试和几何查询的 InteractiveRenderSession。渲染会话加载完成后,这些查询都是同步的,因此指针按下、移动和抬起看到的都是同一代保留场景。
文档、命令和历史记录的唯一可信来源始终是 TypeScript。渲染器接收一份已校验的文档、一个选定的页面以及随后的精确状态转换。它从不维护第二份历史记录,也从不自行修改文档。
输入事件
编辑器接受的每个输入都是一个 EditorInput:已经从平台规范化的指针、键盘、IME 组合输入、文本和剪贴板事件。assertEditorInput 在边界处检查单个输入。
源码type EditorInput = | EditorPointerInput | EditorKeyboardInput | EditorCompositionInput | EditorTextInput | EditorClipboardInput编辑器接受的所有输入事件。用
assertEditorInput检查单个事件。
源码interface EditorPointerInput从平台事件归一化而来的指针事件。鼠标、触控笔和触摸共用。
readonly kind: "pointer"源码readonly phase: "down" | "move" | "up" | "cancel" | "lost-capture"源码cancel和lost-capture会在没有up的情况下结束指针序列。updateBodyInteraction将两者都视为取消,不提交任何内容。readonly pointerId: number源码在一个指针的各个事件之间标识该指针。为非负整数。
readonly pointerType: EditorPointerType源码readonly position: Point源码相对于交互表面的位置,以 CSS 像素计。
在此事件中状态发生变化的按键,编号方式与 DOM
button字段相同(0 为主按键)。此事件之后仍被按住的按键的位掩码,与 DOM
buttons字段相同。readonly pressure: number源码压力,范围为 0 到 1。
readonly modifiers: EditorModifiers源码
源码type EditorPointerType = "mouse" | "pen" | "touch"
源码interface EditorModifiers指针或键盘事件期间按住的修饰键。在 macOS 上,
meta是 Command 键。readonly alt: boolean源码readonly control: boolean源码readonly meta: boolean源码readonly shift: boolean源码
源码interface EditorKeyboardInput一次按键按下或释放。
readonly kind: "keyboard"源码readonly phase: "down" | "up"源码readonly key: string源码产生的键值,与 DOM
KeyboardEvent.key相同(例如"a"或"ArrowLeft")。readonly code: string源码物理按键,与 DOM
KeyboardEvent.code相同(例如"KeyA")。readonly repeat: boolean源码按键被按住且平台重复触发时为 true。
readonly composing: boolean源码IME 组合输入进行中时为 true。
readonly modifiers: EditorModifiers源码
源码interface EditorCompositionInput一个 IME 组合输入事件。
text是到目前为止的完整组合文本,而不是相对于上一次更新的差异。readonly kind: "composition"源码readonly phase: "start" | "update" | "end" | "cancel"源码readonly text: string源码readonly selectionStart: number源码浏览器组合输入 API 使用的 UTF-16 偏移量。
readonly selectionEnd: number源码
源码interface EditorTextInput输入或删除的文本,仿照 DOM
beforeinput事件建模。readonly kind: "text"源码readonly inputType: string源码DOM 输入类型,例如
"insertText"或"deleteContentBackward"。readonly data: string | null源码插入的文本;对于不携带文本的输入类型(例如删除)为
null。
源码interface EditorClipboardInput一次复制、剪切或粘贴。粘贴时,
items保存剪贴板内容。readonly kind: "clipboard"源码readonly action: "copy" | "cut" | "paste"源码readonly items: readonly EditorClipboardItem[]源码
源码interface EditorClipboardItem一种剪贴板格式及其字节。一个项列表中每种 MIME 类型最多出现一次。
readonly mimeType: string源码readonly data: Uint8Array源码
源码function assertEditorInput(input: unknown): asserts input is EditorInput在 TypeScript 与渲染器的边界上校验输入。检查每种
EditorInput的结构:已知的阶段和动作、有限的指针位置、0 到 1 之间的压力值、非负整数指针 id、有序的组合输入选区,以及 MIME 类型唯一且带有字节数据的剪贴板项。富文本剪贴板项会被解码以进行检查。遇到第一个问题时抛出TypeError或RangeError。
富文本以 UTF-8 JSON 形式通过剪贴板传递,使用专属的 MIME 类型,并附带一个 text/plain 回退。
源码const EDITOR_RICH_TEXT_MIME_TYPE: "application/x-taco-slides-rich-text+json"EditorRichTextClipboardPayload的剪贴板 MIME 类型,以 UTF-8 JSON 存储。
源码interface EditorRichTextClipboardPayload规范的富文本剪贴板载荷;text/plain 仍是必需的回退格式。
readonly version: 1源码readonly paragraphs: readonly TextParagraph[]源码
源码function encodeEditorRichTextClipboardPayload( payload: EditorRichTextClipboardPayload ): Uint8Array将富文本剪贴板载荷编码为 UTF-8 JSON 字节。编码前会先校验,并以与
decodeEditorRichTextClipboardPayload相同的方式抛出TypeError。
源码function decodeEditorRichTextClipboardPayload( bytes: Uint8Array ): EditorRichTextClipboardPayload解码
EDITOR_RICH_TEXT_MIME_TYPE剪贴板项的字节。在以下情况抛出TypeError:字节不是 UTF-8 JSON、对象含有version和paragraphs之外的属性、version不为 1,或段落不是有效的文本节点段落。
源码interface Point二维点。其坐标空间取决于使用的位置。
readonly x: number源码readonly y: number源码
源码interface Size宽度和高度。其单位取决于使用的位置。
readonly width: number源码readonly height: number源码
视口与缩放
ViewportState 把文档放置在交互表面上。这些函数在文档单位、CSS 像素和设备像素之间进行转换。缩放辅助函数把请求的缩放模式转换为画布绘制所用的比例。
源码interface ViewportState文档在交互表面上的放置方式。用
createViewportState创建;用documentToScreenPoint及其他视口函数转换点。
源码interface ViewportInputcreateViewportState的平移和缩放设置。
源码function createViewportState(input: ViewportInput): ViewportState构建一个没有旋转的
ViewportState:文档点p映射到以 CSS 像素计的origin + p * zoom,因此documentToScreen为 ,屏幕点通过 映射回来。值非有限时抛出TypeError;尺寸为负,或缩放比例或设备像素比不为正数时抛出RangeError。
源码function assertViewportState(viewport: ViewportState): void检查
ViewportState是否可用:屏幕尺寸有限且非负,documentToScreen变换有限且可逆,设备像素比为正数。抛出TypeError或RangeError。
源码const documentToScreenPoint: (viewport: ViewportState, point: Point) => Point将点从文档单位转换为表面上的 CSS 像素。
源码const screenToDocumentPoint: (viewport: ViewportState, point: Point) => Point将点从绘制表面上的 CSS 像素转换为文档单位。当视口变换不可逆时抛出
RangeError。
源码const documentToScreenRect: (viewport: ViewportState, rect: Rect) => Rect将文档矩形转换为其变换后各角点的包围盒,以 CSS 像素计(见
transformRect)。
源码const screenToDocumentRect: (viewport: ViewportState, rect: Rect) => Rect将以 CSS 像素表示的矩形转换为其各角点变换后的包围盒,单位为文档单位(参见
transformRect)。
源码const screenToDevicePoint: (viewport: ViewportState, point: Point) => Point
源码const deviceToScreenPoint: (viewport: ViewportState, point: Point) => Point
源码const documentToDevicePoint: (viewport: ViewportState, point: Point) => Point将点从文档单位转换为设备像素。
源码const deviceToDocumentPoint: (viewport: ViewportState, point: Point) => Point将点从设备像素转换为文档单位。
源码function transformPoint(transform: TransformMatrix, point: Point): Point对点应用仿射变换。
源码function transformRect(transform: TransformMatrix, rect: Rect): Rect变换矩形的四个角点,并返回它们的轴对齐包围盒。存在旋转时,结果会比原矩形大。
源码function multiplyTransforms( left: TransformMatrix, right: TransformMatrix ): TransformMatrix译文已过期
Composes two affine transforms. The result applies
rightfirst, thenleft. Matrices use the[a, b, c, d, e, f]layout, wherex' = a*x + c*y + eandy' = b*x + d*y + f. In 3×3 form this is the matrix product , so .The arithmetic is the model’s (
multiplyTransformsthere), which the layer transforms shared by the page compiler and the editor are built on.
源码function invertTransform(transform: TransformMatrix): TransformMatrix求仿射变换(affine transformation)的逆。当行列式不是有限值或过于接近零时,抛出
RangeError。设 ,则:
源码type ZoomMode = | { readonly kind: "fit" } | { readonly kind: "ratio"; readonly ratio: number }用户请求的缩放:让内容适配舞台区域,或使用固定比例。
源码interface ZoomMetrics解析后的缩放。用
resolveZoomMetrics创建。readonly actualRatio: number源码画布绘制时使用的比例:每个文档单位对应的 CSS 像素数。
readonly minimumRatio: number源码允许的最小比例。目前始终为
MIN_ZOOM_RATIO。readonly fitRatio: number源码让内容适配舞台区域的比例。
源码function resolveZoomMetrics(mode: ZoomMode, fitRatio: number): ZoomMetrics画布针对某种缩放模式实际绘制时使用的缩放值。画布视口和缩放指示器都读取这同一个值,因此指示器不会显示画布未使用的比例。
fitRatio是让页面内容适配舞台区域的比例。
源码const initialZoomMetrics: ZoomMetrics初始缩放指标:100%,适配比例为 1。
源码function clampZoomRatio(ratio: number, minimumRatio = MIN_ZOOM_RATIO): number将比例限制在
minimumRatio和MAX_ZOOM_RATIO之间。非有限的比例会变为 1;如果minimumRatio更大,则变为该值。
源码function stepZoomRatio(ratio: number, direction: 1 | -1): number下一个缩放档位:放大(
direction为 1)时乘以 1.25,缩小时乘以 0.8,然后限制在范围内并舍入到两位小数:
源码function formatZoomPercent(ratio: number): string将比例格式化为整数百分比,例如
"125%"。
源码function sameZoomMetrics(left: ZoomMetrics, right: ZoomMetrics): boolean当两个
ZoomMetrics的全部三个字段都相等时为 true。
源码const MIN_ZOOM_RATIO: 0.02画布是无界的,因此缩放使用固定的上下限,而不是相对于页面的限制。
源码const MAX_ZOOM_RATIO: 64最大缩放比例,6400%。
编辑器驱动与快照
EditorDriver 把一个后端(SVG、Wasm 或原生)封装在统一的接口之后。测试向它发送输入,并读回一个 EditorSnapshot,其中包含文档、选区、当前手势、预览、历史记录和渲染出的帧。驱动通过其能力声明自己做不到的事,并以 UnsupportedEditorCapabilityError 拒绝相应的输入。
源码interface EditorDrivergetCapabilities(): Promise<EditorDriverCapabilities>源码reset( config: { readonly document: DesignDocument; readonly viewport: ViewportState; } ): Promise<void>源码setDocument(document: DesignDocument): Promise<void>源码setViewport(viewport: ViewportState): Promise<void>源码setTool(tool: EditorTool): Promise<void>源码sendInput(input: EditorInput): Promise<void>源码flush(): Promise<EditorSnapshot>源码getSnapshot(): Promise<EditorSnapshot>源码hitTest(screenPoint: Point): Promise<readonly EditorHit[]>源码getNodeGeometry(nodeId: NodeId): Promise<NodeGeometry | null>源码getTextGeometry(nodeId: NodeId): Promise<TextGeometry | null>源码hitTestText(query: TextHitQuery): Promise<TextHitResult | null>源码getVectorGeometry(nodeId: NodeId): Promise<VectorGeometry | null>源码hitTestVector(query: VectorHitQuery): Promise<VectorHitTestResult | null>源码getAccessibilitySnapshot(): Promise<AccessibilitySnapshotV1 | null>源码performAccessibilityAction( request: AccessibilityActionRequestV1 ): Promise<boolean>源码captureFrame(): Promise<RenderedEditorFrame>源码dispose(): Promise<void>源码
源码interface EditorDriverCapabilitiesreadonly pointerTypes: readonly EditorPointerType[]源码readonly keyboardRepeat: boolean源码readonly composition: boolean源码readonly clipboard: readonly EditorClipboardInput["action"][]源码readonly textEditing: boolean源码在文本编辑进行时公开选区和组合输入状态。
readonly textGeometry: boolean源码readonly textHitTesting: boolean源码readonly vectorGeometry: boolean源码readonly vectorHitTesting: boolean源码readonly vectorBooleanOperations: boolean源码readonly accessibility: boolean源码readonly frameCapture: boolean源码readonly variableDevicePixelRatio: boolean源码重置时能否以不同的设备像素比重新创建表面。
源码type EditorDriverCapability = | `pointer:${EditorPointerType}` | "keyboard-repeat" | "composition" | `clipboard:${EditorClipboardInput["action"]}` | "text-editing" | "text-geometry" | "text-hit-testing" | "text-navigation" | "vector-geometry" | "vector-hit-testing" | "vector-boolean-operations" | "accessibility" | "frame-capture" | "variable-device-pixel-ratio"
源码class UnsupportedEditorCapabilityError extends Error一种稳定的失败,用于驱动明确不提供的输入或观测。
readonly code: "unsupported-editor-capability"源码new (readonly capability: EditorDriverCapability, message: string)源码
源码interface EditorSnapshotreadonly document: DesignDocument源码readonly activePageId: PageId | null源码readonly selection: EditorSelectionState源码readonly hoveredNodeId: NodeId | null源码readonly textEditing: ActiveTextEditingState | null源码规范的文本选区,以及尚未提交的 IME 替换内容(如果有)。
readonly editingTextNodeId: NodeId | null源码用于兼容的标识;处于编辑状态时,它必须与
textEditing.nodeId一致。readonly vectorEditing: VectorEditingSnapshot | null源码已有路径的组成部分编辑,及其尚未提交的原生叠加层预览。
readonly editingCodeNodeId: NodeId | null源码readonly activeTool: EditorTool源码readonly viewport: ViewportState源码readonly gesture: EditorGestureState | null源码readonly previews: readonly EditorPreviewGeometry[]源码readonly lastHit: EditorHit | null源码readonly history: EditorHistoryState源码readonly accessibility: AccessibilitySnapshotV1 | null源码当前编辑器表面公开的、带版本号的确切语义状态。
readonly revisions: EditorRevisions源码
源码interface EditorSelectionStatereadonly pageIds: readonly PageId[]源码readonly nodeIds: readonly NodeId[]源码readonly primaryNodeId: NodeId | null源码
源码interface EditorHistoryStatereadonly canUndo: boolean源码readonly canRedo: boolean源码readonly headCommitId: string | null源码readonly commits: readonly CommitRecord[]源码
源码interface EditorRevisionsreadonly document: number源码readonly surface: number源码readonly frame: number源码readonly accessibility: number源码
源码type EditorTool = | "move" | "hand" | "scale" | "frame" | "rectangle" | "line" | "arrow" | "connector" | "ellipse" | "polygon" | "star" | "image" | "pen" | "pencil" | "text" | "code" | "text-path" | "comment"
源码type EditorGestureKind = | "draw" | "marquee" | "move" | "resize" | "connector-endpoint" | "rotate" | "scale" | "pan" | "text" | "vector"
源码type EditorGestureState = | ( & EditorGestureBase & { readonly kind: "draw" | "marquee" | "text" | "vector" }) | ( & EditorGestureBase & { readonly kind: "move"; readonly duplicate: boolean; readonly previewDelta: Point; }) | ( & EditorGestureBase & { readonly kind: "resize"; readonly handle: EditorResizeHandle }) | ( & EditorGestureBase & { readonly kind: "connector-endpoint"; readonly endpoint: "start" | "end"; }) | ( & EditorGestureBase & { readonly kind: "rotate"; readonly center: Point; readonly previewAngle: number; }) | ( & EditorGestureBase & { readonly kind: "scale"; readonly handle: EditorScaleHandle; readonly anchor: Point; readonly previewFactor: number; }) | (EditorGestureBase & { readonly kind: "pan" })
源码type EditorResizeHandle = | "north-west" | "north" | "north-east" | "east" | "south-east" | "south" | "south-west" | "west"
源码type EditorScaleHandle = | "north-west" | "north-east" | "south-east" | "south-west"
源码type EditorPreviewGeometry = | { readonly kind: "rect"; readonly nodeId?: NodeId; readonly rect: Rect } | { readonly kind: "line"; readonly nodeId?: NodeId; readonly start: Point; readonly end: Point; } | { readonly kind: "path"; readonly nodeId?: NodeId; readonly points: readonly Point[]; readonly closed: boolean; } | { readonly kind: "alignment-guide"; readonly orientation: "horizontal" | "vertical"; readonly start: Point; readonly end: Point; readonly movingAnchor: "start" | "center" | "end" | "baseline"; }
源码type EditorHit = | { readonly nodeId: NodeId; readonly part: "body"; readonly frameTitle?: true; } | { readonly nodeId: NodeId; readonly part: "resize-handle"; readonly handle: EditorResizeHandle; } | { readonly nodeId: NodeId; readonly part: "rotate-handle"; readonly corner: EditorScaleHandle; } | { readonly nodeId: NodeId; readonly part: "scale-handle"; readonly handle: EditorScaleHandle; } | { readonly nodeId: NodeId; readonly part: "connector-endpoint"; readonly endpoint: "start" | "end"; } | { readonly nodeId: NodeId; readonly part: "vector-anchor"; readonly vertexId: VectorVertexId; } | { readonly nodeId: NodeId; readonly part: "vector-handle"; readonly handleId: VectorHandleId; } | { readonly nodeId: NodeId; readonly part: "vector-segment"; readonly segmentId: VectorSegmentId; } | { readonly nodeId: NodeId; readonly part: "vector-region"; readonly regionId: VectorRegionId; }
源码interface RenderedEditorFramereadonly mimeType: "image/png"源码readonly width: number源码readonly height: number源码readonly density: number源码readonly data: Uint8Array源码
渲染会话边界
InteractiveRenderSession 是渲染器为编辑器实现的接口。它加载文档,应用每次文档状态转换,回答命中测试和几何查询,并绘制叠加了编辑器叠加层的帧。
源码interface InteractiveRenderSessionloadDocument(load: RenderDocumentLoad): Promise<void>源码替换规范文档,并为文档 store 的修订号建立精确的连续性起点。
原生,经由
InteractiveRetainedBackend.getSceneInfo:taco_render_session_get_scene_info原生,经由
InteractiveRetainedBackend.apply:taco_render_session_applyapplyDocumentUpdate(update: DocumentSceneUpdate): Promise<void>源码原生,经由
InteractiveRetainedBackend.getSceneInfo:taco_render_session_get_scene_info原生,经由
InteractiveRetainedBackend.apply:taco_render_session_applysetActivePage(pageId: PageId | null): Promise<void>源码原生,经由
InteractiveRetainedBackend.getSceneInfo:taco_render_session_get_scene_info原生,经由
InteractiveRetainedBackend.apply:taco_render_session_applysetViewport(viewport: ViewportState): Promise<void>源码hitTest(screenPoint: Point): readonly EditorHit[]源码原生,经由
InteractiveRetainedBackend.hitTest:taco_render_session_hit_testgetNodeGeometry(nodeId: NodeId): NodeGeometry | null源码原生,经由
InteractiveRetainedBackend.getNodeGeometry:taco_render_session_get_node_geometrygetSceneGeometrySnapshot(): SceneGeometrySnapshot源码原生,经由
InteractiveRetainedBackend.getSceneInfo:taco_render_session_get_scene_info原生,经由
InteractiveRetainedBackend.getGeometrySnapshot:taco_render_session_get_geometry_snapshotgetTextGeometry(nodeId: NodeId): TextGeometry | null源码原生,经由
InteractiveRetainedBackend.getSceneInfo:taco_render_session_get_scene_infohitTestText(query: TextHitQuery): TextHitResult | null源码原生,经由
InteractiveRetainedBackend.getSceneInfo:taco_render_session_get_scene_info原生,经由
InteractiveRetainedBackend.getSceneInfo:taco_render_session_get_scene_infogetVectorGeometry(nodeId: NodeId): VectorGeometry | null源码原生,经由
InteractiveRetainedBackend.getSceneInfo:taco_render_session_get_scene_infohitTestVector(query: VectorHitQuery): VectorHitTestResult | null源码原生,经由
InteractiveRetainedBackend.getSceneInfo:taco_render_session_get_scene_infobooleanVectorPaths(request: VectorBooleanPathRequest): VectorBooleanPathResult源码原生,经由
InteractiveRetainedBackend.getSceneInfo:taco_render_session_get_scene_infosetOverlays(overlays: EditorOverlayState): Promise<void>源码原生,经由
InteractiveRetainedBackend.setOverlays:taco_render_session_set_text_editing_overlay,taco_render_session_clear_text_editing_overlay,taco_render_session_set_vector_editing_overlay,taco_render_session_clear_vector_editing_overlay,taco_render_session_set_selection_chrome,taco_render_session_set_canvas_overlayrenderFrame(): Promise<RenderFrameReport>源码原生,经由
InteractiveRetainedBackend.getSceneInfo:taco_render_session_get_scene_infogetAccessibilitySnapshot(): Promise<AccessibilityNodeSnapshot | null>源码dispose(): Promise<void>源码
源码interface RenderDocumentLoad一次原子性的规范文档加载,及其精确解析后的资源输入。
readonly document: DesignDocument源码readonly rendererDocument?: DesignDocument源码仅供渲染器使用的投影,与规范文档原子性地配对。
readonly rendererNodeOwners?: RendererNodeOwners源码精确的渲染器节点归属关系,与渲染器投影原子性地配对。
readonly rendererQueryTargets?: RendererQueryTargets源码规范的公开查询 ID,与仅供渲染器使用的查询目标原子性地配对。
readonly commitId: CommitId源码readonly resourceSnapshot: RenderResourceSnapshot源码
源码interface DocumentSceneUpdatereadonly reason: TransitionReason源码readonly previousCommitId: CommitId源码readonly currentCommitId: CommitId源码readonly previousDocument: DesignDocument源码readonly document: DesignDocument源码readonly previousRendererDocument?: DesignDocument源码与
previousDocument一起提交的、仅供渲染器使用的确切投影。协调器仍然持有
previousDocument,将其作为编辑器的规范权威来源。投影可以用确定性的保留节点替换不受支持的规范节点,但必须保留文档的其他所有部分。省略时,规范文档同时也是渲染器的输入。readonly previousRendererNodeOwners?: RendererNodeOwners源码与
previousRendererDocument一起提交的、确切的渲染器节点归属映射。每个渲染器节点必须恰好出现一次,并直接解析到一个自身拥有的规范节点。协调器仅用它把渲染器查询的标识转换回编辑器的规范权威来源。
readonly previousRendererQueryTargets?: RendererQueryTargets源码与上一个投影一起提交的、确切的规范到渲染器的查询目标。
readonly rendererDocument?: DesignDocument源码与
document原子地配对的、仅供渲染器使用的投影。readonly rendererNodeOwners?: RendererNodeOwners源码与
rendererDocument原子地配对的、确切的渲染器节点归属映射。readonly rendererQueryTargets?: RendererQueryTargets源码规范的公开查询 ID,映射到它们对应的仅供渲染器使用的文本/矢量节点。
readonly operations: readonly DocumentOperation[]源码readonly changes: ChangeSet源码readonly rendererChanges?: ChangeSet源码上一个与当前渲染器投影之间的确切变更集。只要任一方使用了渲染器文档或归属映射,此项就是必需的。
readonly resourceSnapshot: RenderResourceSnapshot源码document所需的完整渲染器资源,从同一个不可变修订版本解析而来。
源码interface RenderResourcereadonly assetId: string源码readonly mimeType: string源码readonly bytes: Uint8Array源码readonly slice?: RenderFontSlice源码当此资源是某个来源为 “google-fonts” 的字体资源中的一个文件时设置。这类资源按 Unicode 覆盖范围拆分成许多文件,因此每个已加载的文件都会出现一次,各自带有不同的
slice.id;在尚未加载任何文件时,它可能一次也不出现。
源码interface RenderFontSlice按 Unicode 覆盖范围拆分出的字体资源中的一个文件。
readonly id: string源码在资源内唯一,由字母、数字、“.”、“_” 和 “-” 组成。
readonly unicodeRanges: readonly (readonly [number, number])[]源码该文件覆盖的码点范围,已排序、互不重叠且包含两端。
源码interface RenderResourceSnapshot某一规范文档修订版本的完整、不可变的渲染器资源输入。
readonly resources: readonly RenderResource[]源码
源码type RendererNodeOwners = Readonly<Record<string, NodeId>>不可变且完备的“渲染器节点到规范节点”的归属关系。
源码interface RendererQueryTargets为规范查询标识提供的可选、仅供渲染器使用的目标。
文本目标是规范代码节点完整的保留文本实体化结果。矢量目标保留规范的路径拓扑。每个目标都必须能从页面到达,并且与其归属节点共享完全相同的节点局部坐标空间,这样结果就能沿用规范的公开命名空间,而无需进行有损的坐标转换。
readonly text: Readonly<Record<string, NodeId>>源码readonly vector: Readonly<Record<string, NodeId>>源码
源码interface RenderFrameReportreadonly changedRegions: readonly Rect[]源码重新绘制的区域,单位为 CSS 像素,相对于渲染目标。
readonly sceneUpdateMs: number源码readonly layoutMs: number源码readonly paintMs: number源码readonly submitMs: number源码readonly paint?: RenderFramePaintStatistics源码在后端报告绘制统计信息时存在。
源码interface RenderFramePaintStatistics一帧绘制的内容,用于性能监测。
readonly fullPaint: boolean源码整个目标被重新绘制,而不是只绘制脏区域。
readonly nodesPainted: number源码readonly nodesConsidered: number源码本帧检查过的节点数,包括在绘制前被剔除的节点。
readonly targetWidth: number源码渲染目标的尺寸,单位为设备像素。
readonly targetHeight: number源码readonly retainedPayloadBytes: number源码渲染器持有的保留场景数据的字节数。
readonly decodedFontEntries: number源码readonly textLayoutEntries: number源码
叠加层是编辑器绘制在文档之上的内容:选区、悬停、手势预览、文本光标和文本选区、矢量编辑控制柄,以及吸附参考线和测量等画布线条。
源码interface EditorOverlayStatereadonly selectedNodeIds: readonly NodeId[]源码readonly hoveredNodeId: NodeId | null源码readonly gesture: EditorGestureState | null源码readonly previews: readonly EditorPreviewGeometry[]源码readonly decorations: readonly EditorNodeDecoration[]源码readonly nodePreviews: readonly EditorNodePreview[]源码readonly textEditing: | (ActiveTextEditingState & { readonly caretVisible: boolean }) | null源码由共享渲染器绘制的选区、光标和 IME 状态。
readonly vectorEditing: VectorEditingSnapshot | null源码已有路径的组成部分选区,以及完整的节点局部预览网络。
readonly hitRegions: readonly EditorOverlayHitRegion[]源码按最上层优先排列的命中区域。叠加层命中始终优先于保留场景主体的命中。
readonly selectionChrome?: EditorSelectionChrome | null源码选区轮廓和控制柄,供自行绘制它们的后端使用,与场景在同一帧中绘制。当宿主自己绘制选区框与控制柄时省略。
readonly canvasOverlay?: EditorCanvasOverlay | null源码吸附线、标尺参考线、按住 Option 拖动时的测量值以及像素网格,由后端与场景在同一帧中绘制。省略时保留后端当前的叠加层;
null清除它。
源码interface EditorCanvasOverlayreadonly anchorNodeId: NodeId | null源码叠加层所使用的局部坐标所属的节点;使用场景坐标时为
null。readonly devicePixelRatio: number源码readonly grid: | { readonly originX: number; readonly originY: number; readonly step: number; readonly rgba: number; } | null源码从原点起每隔
step个单位一条线,铺满整个画布。readonly lines: readonly EditorOverlayLine[]源码readonly marks: readonly EditorOverlayMark[]源码readonly titles?: readonly EditorOverlayTitle[]源码绘制在顶层画框上方的名称;缺省表示没有。
readonly rulers?: EditorOverlayRulers源码沿顶边和左边的标尺;缺省表示没有。
readonly boxes?: readonly EditorOverlayBox[]源码填充、斜线填充或描出轮廓的框(自动布局的间距和内边距);缺省表示没有。
readonly handles?: readonly EditorOverlayHandle[]源码带边框的刻度线(自动布局的间距控制柄);缺省表示没有。
readonly badges?: readonly EditorOverlayBadge[]源码显示数值的胶囊标签(拖动间距时的数值,最多 16 个);缺省表示没有。
源码interface EditorOverlayLinereadonly orientation: "vertical" | "horizontal"源码readonly side: EditorOverlayLineSide源码readonly position: number源码垂直线的 x,或水平线的 y。
readonly start: number | null源码线沿其长度方向的范围;
null表示贯穿整个画布。readonly end: number | null源码readonly rgba: number源码0xRRGGBBAA。
readonly dash?: { readonly dashCssPx: number; readonly gapCssPx: number }源码readonly scene?: boolean源码使用场景坐标,而不是叠加层锚点的局部坐标。
readonly anchorNodeId?: NodeId源码这条线改用其局部坐标的节点(替代叠加层的锚点),例如一个画框,其自身的参考线必须在移动或调整大小预览中跟随它。
readonly spansAnchorBox?: boolean源码沿锚点节点自身的盒子延伸(从 0 到其宽度或高度);忽略 start 和 end。
源码type EditorOverlayLineSide = "after" | "before" | "centered"宽度为一个 CSS 像素的叠加层线在其位置周围覆盖哪些设备像素:左边或上边以及坐标线使用 “after”,右边或下边使用 “before”,中心线使用 “centered”。
源码interface EditorOverlayMark以两条交叉线的像素为中心、经过抗锯齿处理的 x 形标记。
readonly x: number源码readonly y: number源码readonly xSide: EditorOverlayLineSide源码readonly ySide: EditorOverlayLineSide源码readonly halfSizeCssPx: number源码readonly rgba: number源码readonly scene?: boolean源码
源码interface EditorOverlayHitRegionreadonly hit: EditorHit源码readonly bounds: Rect源码
渲染器还根据同一个叠加层绘制其余的画布界面元素,使页面与这些元素始终保持一致:框(例如自动布局的内边距和间距区域)、控制柄(例如间距控制柄)、带简短文字的胶囊标签、沿顶边和左边的标尺,以及顶层画框上方的名称。
源码interface EditorOverlayBox位于其锚点局部坐标中的矩形(省略时使用叠加层的锚点),经锚点的完整变换映射,因此旋转画框的框会随之旋转。每种外观都是可选的:填充、斜线填充,以及框内一个 CSS 像素宽的轮廓。
readonly anchorNodeId?: NodeId源码readonly x: number源码readonly y: number源码readonly width: number源码readonly height: number源码readonly fillRgba?: number源码0xRRGGBBAA。
readonly hatchRgba?: number源码readonly outlineRgba?: number源码
源码interface EditorOverlayHandle两端为圆头、带边框的刻度线,以某个点为中心,沿锚点局部的 x 轴或 y 轴放置。
readonly anchorNodeId?: NodeId源码readonly x: number源码readonly y: number源码readonly axis: "x" | "y"源码readonly lengthCssPx: number源码readonly thicknessCssPx: number源码readonly rgba: number源码0xRRGGBBAA。
readonly borderRgba: number源码
源码interface EditorOverlayBadge带一行文字的圆角胶囊标签,其左上角相对某个点偏移若干 CSS 像素。
readonly anchorNodeId?: NodeId源码readonly x: number源码readonly y: number源码readonly offsetXCssPx: number源码readonly offsetYCssPx: number源码readonly fontSizeCssPx: number源码readonly text: string源码readonly backgroundRgba: number源码0xRRGGBBAA。
readonly textRgba: number源码
源码interface EditorOverlayRulers标尺,使用叠加层锚点的单位(页面坐标)。渲染器按正在绘制的这一帧中的页面布置刻度和数字。
readonly sizeCssPx: number源码readonly fontSizeCssPx: number源码readonly minimumMajorCssPx: number源码readonly backgroundRgba: number源码0xRRGGBBAA 颜色。
readonly borderRgba: number源码readonly inkRgba: number源码readonly selectionFillRgba: number源码readonly selectionInkRgba: number源码readonly selectionX: readonly { readonly start: number; readonly end: number }[]源码选区的范围:已排序且互不相接;长度为零的范围标记单个数值。
readonly selectionY: readonly { readonly start: number; readonly end: number }[]源码readonly labels: readonly { readonly axis: "x" | "y"; readonly position: number; readonly backgroundRgba: number; readonly textRgba: number; }[]源码以标签形式绘制在各自标尺上的参考线位置(最多 16 个)。
源码interface EditorOverlayTitle绘制在顶层画框上方的名称,位于画框在正在绘制的这一帧中的屏幕框的左上角,超出画框宽度的部分以省略号截断。
readonly anchorNodeId: NodeId源码readonly text: string源码readonly rgba: number源码0xRRGGBBAA。
readonly fontSizeCssPx: number源码readonly gapCssPx: number源码标题行框与画框顶边之间的距离。
源码interface EditorSelectionChromereadonly items: readonly EditorSelectionChromeItem[]源码readonly strokeRgba: number源码译文已过期
Default colours of items that give none, 0xRRGGBBAA.
readonly handleFillRgba: number源码readonly devicePixelRatio: number源码
源码interface EditorSelectionChromeItem一个轮廓或控制柄,在绘制该帧时根据其节点解析。
readonly nodeId: NodeId | null源码为 null 时,矩形使用场景坐标,而不是节点局部坐标。
readonly kind: "outline" | "square-handle" | "round-handle"源码readonly hover?: boolean源码readonly dashed?: boolean源码readonly x: number源码An outline’s rectangle. A handle’s centre is x and y, and its width and height are its finished size on screen in CSS pixels.
readonly y: number源码readonly width?: number源码readonly height?: number源码readonly angle?: number源码A handle’s turn on screen in radians, clockwise; 0 when omitted.
readonly strokeRgba?: number源码0xRRGGBBAA overrides of the chrome’s default colours.
readonly fillRgba?: number源码readonly offsetX?: number源码场景空间中的偏移量,用于保留场景中不存在的预览。
readonly offsetY?: number源码readonly sceneTransform?: TransformMatrix源码以场景为锚点的项从局部到场景的矩阵;省略时为单位矩阵。
readonly nodeTransform?: TransformMatrix源码Item-to-node matrix of a node-anchored item; identity when omitted.
源码interface EditorNodeDecorationreadonly nodeId: NodeId源码readonly role: "hover" | "selection"源码readonly primary: boolean源码readonly handles: "none" | "resize" | "rotate" | "scale" | "vector"源码
源码type EditorNodePreview = | { readonly kind: "subtree-transform"; readonly nodeId: NodeId; readonly transform: TransformMatrix; readonly mode: "replace" | "duplicate"; } | { readonly kind: "node-override"; readonly nodeId: NodeId; readonly documentBounds: Rect; }
场景与文本几何
渲染会话把它所绘制场景的几何信息发布为一个带有代号(generation)的 SceneGeometrySnapshot。文本几何、文本命中测试和光标导航都在节点局部坐标中进行。
源码interface SceneGeometrySnapshotreadonly generation: bigint源码保留场景的代次;它有意不作为编辑器历史 ID。
readonly sceneBounds: Rect源码readonly painterOrder: readonly NodeId[]源码从后到前的规范绘制顺序。
readonly nodes: readonly NodeGeometry[]源码readonly byId: ReadonlyMap<NodeId, NodeGeometry>源码
源码interface NodeGeometryreadonly nodeId: NodeId源码readonly localBounds: Rect源码readonly documentBounds: Rect源码readonly visibleDocumentBounds: Rect | null源码应用实际可见性和祖先裁剪之后的边界;完全隐藏时为
null。readonly screenBounds: Rect源码readonly visibleScreenBounds: Rect | null源码visibleDocumentBounds在屏幕空间中的形式。readonly localToDocument: TransformMatrix源码readonly localToScreen: TransformMatrix源码readonly painterOrder: number源码readonly effectivelyVisible: boolean源码readonly effectiveOpacity: number源码
源码function indexSceneGeometryNodes( nodes: readonly NodeGeometry[] ): ReadonlyMap<NodeId, NodeGeometry>
源码function withSceneGeometryIndex( snapshot: Omit<SceneGeometrySnapshot, "byId"> ): SceneGeometrySnapshot
源码interface TextGeometryreadonly nodeId: NodeId源码readonly generation: bigint源码保留场景的代次,用于在场景更新后拒绝该几何信息。
readonly coordinateSpace: "node-local"源码readonly carets: readonly TextCaretGeometry[]源码readonly selection: TextRangeGeometry | null源码readonly composition: TextRangeGeometry | null源码
源码interface TextCaretGeometryreadonly position: TextPosition源码readonly localBounds: Rect源码光标在被编辑节点局部坐标空间中的边界。
源码interface TextRangeGeometryreadonly range: TextRange源码readonly localRects: readonly Rect[]源码每个已整形的片段对应一个矩形,全部使用节点局部坐标。
源码interface TextHitQueryreadonly nodeId: NodeId源码readonly localPoint: Point源码查询位置,位于文本节点的局部坐标空间中。
源码interface TextHitResultreadonly nodeId: NodeId源码readonly generation: bigint源码readonly position: TextPosition源码readonly inside: boolean源码当结果是已排版文本之外最近的光标位置时为 false。
源码function assertTextHitQuery(value: unknown): asserts value is TextHitQuery检查一个值是否为带有节点 id 和有限局部坐标点的
TextHitQuery。在垂直移动之间保持不变;节点局部坐标系中的 x 坐标。
更新后的节点局部 x 坐标,供下一次垂直移动使用。
检查一个值是否为
TextNavigationQuery:操作必须已知,且如果给出了首选局部 x,它必须是有限值。
选区
这些函数决定单击、双击、框选或键盘命令会选中什么。普通单击会选中当前范围允许的最外层节点;编组和嵌套画框在被双击进入之前都作为一个整体对象。隐藏和锁定的节点及其内部节点永远不会被选中。
源码type SelectionMode = "replace" | "toggle" | "add"updateNodeSelection如何将新的节点 id 与当前选区合并。
源码function updateNodeSelection( current: readonly NodeId[], incoming: readonly NodeId[], mode: SelectionMode ): readonly NodeId[]将选区与传入的节点 id 合并。
replace返回去重后的传入 id;add追加尚未选中的 id;toggle移除每个已选中的传入 id,并追加每个尚未选中的 id。 顺序保持不变,因此最后一个 id 是主选区。
源码interface CanvasSelection一次按下所选中的节点,以及渲染器为此实际命中的节点。
readonly hitNodeId: NodeId源码readonly targetId: NodeId源码readonly frameTitle?: true源码按下的位置在画框的标题上,这里从不开始框选。
源码function frontmostCanvasSelection( document: DesignDocument, rootId: NodeId, hits: readonly EditorHit[], primarySelectedNodeId: NodeId | null, deepSelect = false ): CanvasSelection | null按顺序遍历
hits,返回第一个能被canvasSelectionTarget映射到节点的命中项,以及它选中的节点。对于 Cmd 或 Ctrl 点击,传入deepSelect,此时会选中最内层的节点。
源码function frontmostCanvasSelectionTarget( document: DesignDocument, rootId: NodeId, hits: readonly EditorHit[], primarySelectedNodeId: NodeId | null, deepSelect = false ): NodeId | null与
frontmostCanvasSelection类似,但只返回选中节点的 id。
源码function canvasSelectionTarget( document: DesignDocument, rootId: NodeId, hitNodeId: NodeId, primarySelectedNodeId: NodeId | null, deepSelect = false ): NodeId | null一次普通点击选中的节点:被命中节点的最外层祖先,且当前作用域尚未进入到它之内。深度选择会忽略作用域,改为选取指针下最内层的节点。
源码function descendantSelectionTarget( document: DesignDocument, rootId: NodeId, hitNodeId: NodeId, primarySelectedNodeId: NodeId | null ): NodeId | null双击选中的节点:恰好比当前向内深入一层。
源码function selectableBodyHits( document: DesignDocument, rootId: NodeId, hits: readonly EditorHit[] ): readonly Extract<EditorHit, { readonly part: "body" }>[]只保留落在可选节点上的主体命中项:节点本身以及其在
rootId之下的每个祖先都必须可见且未锁定。保持原有顺序。
源码function frameMarqueeTarget( document: DesignDocument, rootId: NodeId, selection: CanvasSelection, selectedNodeIds: readonly NodeId[], deepSelect = false ): NodeId | null拖动时应在其内部绘制选择框、而不是移动它的画框。规则是:画框必须先被选中,拖动才会移动它。因此,在一个未选中、且点击可以到达其子节点的画框的空白背景上按下,会开始一次框选,选中这些子节点。不拖动的点击仍然选中该画框。
点击能直接进入的画框都算在内:直接绘制在页面上的画框、当前选区所在的画框,以及深度选择(Cmd 或 Ctrl)下的任何画框。嵌套在另一个画框中的画框对点击的响应与编组一样,是一个整体对象,因此拖动它会移动它,与 Figma 一致。在画框内部的子节点上按下,会像以前一样选中并移动该子节点。
源码function marqueeSelectionNodeIds( document: DesignDocument, rootId: NodeId, geometry: SceneGeometrySnapshot, marquee: Rect, nested: boolean, scopeId: NodeId = rootId, selectionScopeId: NodeId | null = null ): readonly NodeId[]译文已过期
Returns intersecting selectable nodes in retained back-to-front painter order.
marqueeis in document units and is tested against each node’s visible document bounds fromgeometry.scopeIdis the container the marquee selects inside: the page root by default, or the frame a marquee started on. A plain marquee selects that container’s direct children; a nested one selects the deepest nodes in it.selectionScopeIdis the one layer the canvas selects within, if any.
源码function selectAllSelectionTargets( document: DesignDocument, rootId: NodeId, primarySelectedNodeId: NodeId | null ): readonly NodeId[]全选(Cmd+A)时选中的图层,与 Figma 一致:与主选中图层位于同一层级的所有图层,即其父画框或编组的子图层;若没有选中任何内容,则为页面上的所有顶层图层。 与画布点击和框选一样,隐藏和锁定的图层会被跳过。不在当前页面上的选区视为没有选区。
源码function topLevelSelectableNodeIds( document: DesignDocument, rootId: NodeId ): readonly NodeId[]页面根节点下可选中的直接子节点,按子节点顺序排列。 隐藏和锁定的节点会被排除。
源码function childSelectionTarget( document: DesignDocument, rootId: NodeId, nodeId: NodeId ): NodeId | null译文已过期
The child of a container that Enter selects, or
null: the first child in listed order (listedChildIds, front layer first) that can be selected, which is the first row the layers panel shows under the container. An instance, or a layer inside one, opens to its resolved layers. A node can be selected when it and every ancestor belowrootIdare visible and unlocked.
源码function parentSelectionTarget( document: DesignDocument, rootId: NodeId, nodeId: NodeId ): NodeId | null节点的父节点;当父节点是页面根节点
rootId时为null。
源码function siblingSelectionTarget( document: DesignDocument, rootId: NodeId, nodeId: NodeId, direction: 1 | -1 ): NodeId | null译文已过期
The sibling that Tab (
direction1) or Shift+Tab (-1) selects, following the layers as listed (listedChildIds, front layer first): 1 is the next row down the list (the layer behind) and -1 the row above (the layer in front), wrapping around at the ends. Null when there is no other selectable sibling.
源码function nodeSelectionPath( document: DesignDocument, rootId: NodeId, nodeId: NodeId ): readonly NodeId[]译文已过期
The ids from just below
rootIddown tonodeId, outermost first. Empty whennodeIdis the root or is not inside it. A component’s layers are on no page; isolation mode draws them in a component view beside the page (components design 5.5), so a path that ends at a component root counts as a path from the page root, with the component root as an artboard on it.
节点主体交互
updateBodyInteraction 把节点主体上的指针事件转换为选区变化、框选和移动。它从渲染会话读取命中测试和场景几何,但从不修改文档:完成的移动以 BodyMoveCompletion 的形式返回,由调用方提交。
源码function createBodyInteractionState( options: { readonly selectedNodeIds?: readonly NodeId[]; readonly hoveredNodeId?: NodeId | null; } = {} ): BodyInteractionState创建一个没有手势的
BodyInteractionState。最后一个选中的 id 成为主选中项。
源码function updateBodyInteraction( environment: BodyInteractionEnvironment, state: BodyInteractionState, input: EditorPointerInput ): BodyInteractionUpdate归约主体层级的指针输入,不访问 DOM,也不修改文档。 完成的移动只是描述性的;操作和历史记录由调用方负责。
源码interface BodyInteractionEnvironmentupdateBodyInteraction读取的文档、页面和渲染器状态。readonly document: DesignDocument源码readonly rootId: NodeId源码当前页面的根节点。
readonly viewport: ViewportState源码必须与
renderSession当前快照描述相同的屏幕几何。readonly renderSession: BodyRenderQueries源码readonly snapThresholdScreenPx?: number源码对象对齐距离,以 CSS 像素计。默认为 5。
readonly guideLines?: readonly BodyGuideLine[]源码移动操作可以吸附到的标尺参考线,与
viewport处于同一文档空间。“x” 参考线是位于该 x 处的垂直线;“y” 参考线是水平线。readonly moveRefusal?: (targetId: NodeId) => string | null源码Why a press on a node starts no move, or
nullto move it. Without it, a layer inside an instance (a virtual ID) keeps its position; isolation mode passes its own rule (components design 5.5).readonly autoLayoutDropAllowed?: (frameId: NodeId) => boolean源码Whether a move may drop into this auto-layout frame. Defaults to every frame; isolation mode allows only the open component’s frames (design 5.5).
readonly marqueeSelectable?: (nodeId: NodeId) => boolean源码Whether a marquee may preview and select this node. Defaults to every node; isolation mode rejects the page layers outside its level (design 5.5).
readonly selectionScopeId?: NodeId源码The one layer this canvas selects within, when it does not select the whole page: a press, the hover and a marquee answer inside it (
scopedSelectionTarget). The isolation split’s page pane passes the opened instance (components design 5.5).readonly minimumMarqueeScreenPx?: number源码框选矩形的两个维度都必须达到这个 CSS 像素尺寸。默认为 1。
readonly autoLayoutDropMarginScreenPx?: number源码自动布局画框周围可接受放置的额外距离,以 CSS 像素计。默认为 12。
源码type BodyRenderQueries = Pick< InteractiveRenderSession, "hitTest" | "getSceneGeometrySnapshot" >主体交互所需的两个渲染会话查询:命中测试和保留场景几何。
源码interface BodyInteractionStateupdateBodyInteraction的状态。用createBodyInteractionState创建。readonly selection: BodySelectionState源码readonly hoveredNodeId: NodeId | null源码在指针下点击会选中的节点,或
null。readonly gesture: BodyInteractionGesture | null源码正在进行的手势;两次手势之间为
null。
源码interface BodySelectionState主体交互所看到的选中节点。
readonly nodeIds: readonly NodeId[]源码无重复的选中节点 id,按选择顺序排列。
readonly primaryNodeId: NodeId | null源码nodeIds中的最后一个 id;未选中任何内容时为null。
源码interface BodyInteractionUpdate-
readonly state: BodyInteractionState源码readonly pointerCapture: "none" | "capture" | "release"源码调用方应如何处理指针捕获:手势开始时为
capture,手势结束或取消时为release。readonly completedMove: BodyMoveCompletion | null源码仅在结束一次非零位移移动的指针抬起时设置。
readonly refusedMove?: string源码Why a press that would have started a move did not: a layer inside an instance keeps the position its component gives it (components design 4.2). The caller shows the reason, so nothing fails silently.
源码interface BodyMoveCompletion一次已完成的移动,在指针抬起时返回一次。它只描述这次移动;由调用方把它转换为文档操作和历史记录。
readonly kind: "move"源码readonly nodeIds: readonly NodeId[]源码readonly documentDelta: Point源码规范的文档空间位移;命令和历史记录仍由调用方负责。
readonly duplicate: boolean源码readonly autoLayoutDrop: | Pick<BodyAutoLayoutDropTarget, "frameId" | "insertionIndex"> | null源码当移动在自动布局插入位置上释放时存在。对于普通移动,索引计算的是不含被移动节点的画框子节点;对于复制,它计算全部子节点,因为原节点仍然保留。
readonly sourceGeneration: bigint源码移动开始时所用的场景几何快照的代次。
源码type BodyInteractionGesture = BodyMarqueeGesture | BodyMoveGesture当前的主体手势:框选或移动。
源码interface BodyMarqueeGesture extends BodyGestureBase绘制选择矩形的拖动。从空白画布开始,或从
frameMarqueeTarget选中的画框的空白背景开始。readonly kind: "marquee"源码readonly geometry: SceneGeometrySnapshot源码在这次框选的整个生命周期内,保留快照固定不变。
readonly additive: boolean源码按下时按住了 Shift:框选结果会添加到开始时的选区中。
readonly nested: boolean源码按下时按住了 Cmd 或 Ctrl:框选会选中最深层的节点,而不是直接子节点(见
marqueeSelectionNodeIds)。readonly frameId: NodeId | null源码这次框选开始时所在的未选中画框;在空白画布上开始时为
null。框选会在该画框内部进行选择;如果点击始终没有变成拖动,则选中该画框本身。readonly dragging: boolean源码在画框上的按下仍处于点击距离之内时为 false。
readonly rect: Rect源码框选矩形,以文档单位计。
readonly previewNodeIds: readonly NodeId[]源码当前位于框选矩形内的节点,尚未与开始时的选区合并。
readonly previewSelection: BodySelectionState源码拖动时要显示的选区。指针抬起时它会成为真正的选区。
源码interface BodyMoveGesture extends BodyGestureBase移动选中节点的拖动。只有最外层的选中节点会移动;位于另一个选中节点内部的选中节点会随之一起移动。
readonly kind: "move"源码readonly geometry: SceneGeometrySnapshot源码对于与命中测试无关的移动策略(例如放置目标),保留快照固定不变。
readonly nodeIds: readonly NodeId[]源码readonly rawCurrentAtScreen: Point源码吸附之前的指针位置,以 CSS 像素计。
currentAtScreen保存吸附后的位置。readonly previewDelta: Point源码吸附之后,节点到目前为止移动的距离,以文档单位计。
readonly duplicate: boolean源码按住了 Alt(Option):释放时放置副本,并保留原节点。
readonly moved: boolean源码指针一旦离开按下的位置即为 true。
readonly dragged: boolean源码True once the pointer has traveled
DRAG_SCREEN_PXor more from the press point.readonly clickNarrowsToNodeId: NodeId | null源码The layer pressed inside a multiple selection, or
null. If the press ends without a drag, the selection narrows to this layer, as in Figma.readonly alignmentGuides: readonly Extract< EditorPreviewGeometry, { readonly kind: "alignment-guide" } >[]源码要绘制的吸附参考线,以文档单位计。
readonly initialScreenBounds: AlignmentRect源码按下时移动中节点的合并边界,以 CSS 像素计。吸附基于这些边界进行。
readonly alignmentTargets: readonly AlignmentTarget[]源码移动可以吸附到的其他节点的边界以及标尺参考线,以 CSS 像素计。
readonly duplicateSourceTargets: readonly AlignmentTarget[]源码作为吸附目标的移动中对象本身。它们仅在移动为复制时(按住 ⌥)才计入:此时原对象留在原位,因此副本可以吸附到它们上,与 Figma 一致。
readonly autoLayoutDrop: BodyAutoLayoutDropTarget | null源码指针下方的自动布局画框和插入位置,或
null。设置此项时关闭吸附。
源码interface BodyGuideLine移动操作可以吸附到的标尺参考线。
readonly axis: "x" | "y"源码readonly position: number源码参考线的 x 或 y,以文档单位计。
readonly frameId?: NodeId源码拥有该参考线的画框;页面参考线省略此项。与 Figma 一样,画框的参考线只吸附该画框内部的对象。它们从不吸附画框本身,因为画框移动时会带着这些参考线一起移动。
源码interface BodyAutoLayoutDropTarget位于移动中选区下方的自动布局画框,及其插入位置。
readonly frameId: NodeId源码readonly insertionIndex: number源码离指针最近的插入位置的子节点索引。
readonly activeSlot: number源码离指针最近的插入位置在
slots中的位置。要高亮某一个指示器时应使用它而不是insertionIndex,因为换行布局中的两个插入位置可能共用同一个索引。readonly slots: readonly BodyAutoLayoutInsertionSlot[]源码
源码interface BodyAutoLayoutInsertionSlot被拖动的节点可以插入自动布局画框的一个位置。
在换行的行或列中,每一行都有自己的插入位置,因此一行的末尾和下一行的开头是
index相同的两个插入位置:两者都把节点放到子节点顺序中的同一位置。readonly index: number源码节点插入后将占据的子节点索引。
readonly rect: Rect源码插入指示器在文档空间中的矩形,与渲染器无关。
这些函数读取手势进行期间需要绘制的内容。
源码function displayedBodySelection(state: BodyInteractionState): BodySelectionState框选期间渲染的选区;规范选区只在指针抬起时改变。
源码function bodyInteractionGesture( state: BodyInteractionState ): EditorGestureState | null当前手势,以与渲染器无关的
EditorGestureState表示,其中的点以文档单位计;或为null。
源码function bodyInteractionPreviews( state: BodyInteractionState ): readonly EditorPreviewGeometry[]当前手势的叠加层形状,以文档单位计:开始拖动后的框选矩形、自动布局插入位置,或移动时的吸附参考线。
源码function bodyMoveNodePreviews( state: BodyInteractionState ): readonly BodyMoveNodePreview[]移动过程中,每个移动中的节点对应一个
BodyMoveNodePreview;其他情况下为空。
源码interface BodyMoveNodePreview移动过程中如何绘制一个节点:偏移
documentDelta(文档单位),可以替代原节点绘制,也可以作为副本绘制在原节点旁边。readonly nodeId: NodeId源码readonly documentDelta: Point源码readonly mode: "replace" | "duplicate"源码
源码function bodyAutoLayoutDropPreview( state: BodyInteractionState ): BodyAutoLayoutDropTarget | null当前移动操作的自动布局放置目标,或
null。
源码function clearBodyInteractionHover( state: BodyInteractionState ): BodyInteractionState清除悬停节点。手势进行中时不做任何事。
手势进行中视图发生平移时(例如拖动到画布边缘),页面会在指针下方移动。这些函数把手势测得的内容移动相同的偏移,使手势继续进行而不会跳动。
源码function translateBodyInteractionGesture( state: BodyInteractionState, documentDelta: Point, viewport: ViewportState ): BodyInteractionState把当前手势在文档空间和屏幕空间中测得的一切移动
documentDelta,使页面在手势下方移动时手势能继续进行,例如在按住指针时视图发生平移。这样,移动会让其选区保持在指针下方,并让吸附目标留在它们所属的图层上。移动的预览偏移等偏移量不变。视口的缩放必须与手势开始时相同;缩放会改变视口并结束手势。
源码function holdBodyMoveAtPointerThroughPan( state: BodyInteractionState, documentDelta: Point, viewport: ViewportState ): BodyInteractionState类似
translateBodyInteractionGesture,用于指针静止时发生的平移:页面移动documentDelta,指针在屏幕上保持不动。进行中的移动让其图层保持在指针下方,因此其预览偏移减少documentDelta,这正是在同一位置的下一个指针采样在吸附前会测得的值。下一个采样会重新测量这次移动并进行吸附。其他手势的平移方式与translateBodyInteractionGesture相同。
源码function translateSceneGeometry( snapshot: SceneGeometrySnapshot, documentDelta: Point, viewport: ViewportState ): SceneGeometrySnapshot对快照中的每个节点及其场景包围盒执行
translateNodeGeometry。
源码function translateNodeGeometry( geometry: NodeGeometry, documentDelta: Point, viewport: ViewportState ): NodeGeometry把一个节点的几何在文档空间中移动
documentDelta,并在屏幕上移动对应的屏幕偏移。用于页面在手势下方移动时(例如视图平移),使平移前测得的几何仍能描述节点当前被绘制的位置。
源码function translateRect(rect: Rect, delta: Point): Rect把矩形在其自身空间中移动一个偏移。
源码function documentDeltaToScreenDelta( viewport: ViewportState, documentDelta: Point ): Point在
viewport下与文档偏移对应的屏幕偏移:视口的缩放和旋转会生效,平移则不会。
绘制、调整大小、缩放与旋转
其他指针手势的几何计算:绘制形状、拖动调整大小的控制柄、旋转和缩放。这些函数在传入点所在的任意空间中工作。
源码function rectangleFromPoints(start: Point, current: Point): Rect两个角点之间的矩形,无论拖动方向如何,其宽度和高度都不为负。点不是有限值时抛出
TypeError。
源码function combineRects(rects: readonly Rect[]): Rect | null能容纳列表中每个矩形的最小矩形;列表为空时为
null。
源码function boundsForTransformedRect(rect: Rect, transform: TransformMatrix): Rect矩形经过变换后的轴对齐边界。与
transformRect相同。
源码function constrainLineEndpoint( start: Point, current: Point, constrained: boolean ): Point当
constrained(按住 Shift)时,将从start绘制的直线的终点吸附到最接近的 45 度倍数方向,并保持其长度。否则原样返回current。
源码function constrainBoxEndpoint( start: Point, current: Point, constrained: boolean ): Point当
constrained(按住 Shift)时,移动被拖动的角点,使从start绘制的盒子成为正方形,边长取较长的一边。否则原样返回current。
源码interface ResizeHandleDirection调整大小控制柄的拉动方向:-1 表示西或北,1 表示东或南, 0 表示该控制柄不改变的轴。
readonly x: -1 | 0 | 1源码readonly y: -1 | 0 | 1源码
源码function directionForResizeHandle( handle: EditorResizeHandle ): ResizeHandleDirection调整大小控制柄名称对应的
ResizeHandleDirection。
源码function rotationFromPointerPoints( options: { readonly initialRotation: number; readonly center: Point; readonly start: Point; readonly current: Point; readonly snapIncrement?: number; } ): number旋转拖动过程中的旋转角度(单位为度):
initialRotation加上指针自start以来绕center转过的角度,再用normalizeRotationDegrees折算范围。提供snapIncrement时,结果会舍入为它的倍数(例如按住 Shift 时为 15)。所有点必须位于同一空间。吸附增量不为正数时抛出RangeError。 其中 取各点相对于center的偏移:吸附时,, 其中 =
snapIncrement。
源码function rotatePointAround(point: Point, center: Point, degrees: number): Point将点绕中心旋转
degrees度。在画布这样 y 轴向下的空间中,正角度表示顺时针旋转。输入不是有限值时抛出TypeError。 设 ,中心为 ,则:
源码function normalizeRotationDegrees(degrees: number): number将角度折算到 -180(含)到 180(不含)度的范围内。 角度不是有限值时抛出
TypeError。
调整编组大小时,会缩放其内容的位置和尺寸。缩放工具还会缩放描边宽度、圆角半径、效果和字号。
源码function resizeGroup( document: DesignDocument, groupId: NodeId, frame: Rect ): readonly SceneNode[]通过缩放所有后代,将编组调整为
frame的大小,与在 Figma 中对编组进行普通调整大小的效果相同。位置、尺寸和矢量几何会被缩放;描边宽度、圆角半径、效果和字号不会被缩放(这是缩放工具的用途)。调用方负责选择frame,使锚定的边保持不动。返回该编组,后面依次跟着每个发生变化的后代;当编组无法调整大小时,返回空列表。
源码function uniformScaleFactorFromPointer( options: { readonly anchor: Point; readonly start: Point; readonly current: Point; readonly minimumFactor: number; } ): number缩放拖动过程中的等比缩放系数。它将指针相对于
anchor的偏移投影到起始偏移上,因此 1 表示没有变化,2 表示与锚点的距离变为两倍。结果永远不会小于minimumFactor。当start位于锚点上时返回 1。当minimumFactor不为正数时抛出RangeError。设 =start−anchor, =current−anchor,则:
源码type ScaleCorner = "north-west" | "north-east" | "south-east" | "south-west"
源码type ScaleOrigin = ScaleCorner | "center"缩放时保持不动的点:被拖动控制柄的对角,或在按住 Option/Alt 时取图层的中心。
源码function scaleAnchor(corner: ScaleOrigin, frame: Pick<Rect, "width" | "height">)
源码function scaleSubtree( document: DesignDocument, rootId: NodeId, factor: number, corner: ScaleOrigin ): readonly SceneNode[]
A multi-selection moves as one box, as in Figma. selectionBoxBounds is the box around several sibling layers; resizeNodesInBox, rotateNodesAbout and scaleNodesAbout resize, rotate and scale them together. A connector is not turned or stretched: its ends move (connectorWithMovedEnds) and the page compiler places an attached end on its layer again.
源码function selectionBoxBounds(nodes: readonly SceneNode[]): Rect | nullThe bounding box of several sibling layers in their shared parent’s coordinates: the smallest upright box around each layer’s rotated bounds, as Figma draws one box around a multi-selection.
源码function resizeNodesInBox( document: DesignDocument, nodeIds: readonly NodeId[], from: Rect, to: Rect, boxAngle = 0 ): readonly SceneNode[]Resizes several sibling layers together, like resizing a multi-selection’s bounding box in Figma: the box
frombecomesto(both in the layers’ shared parent coordinates), and every layer’s position and size scale with it by the same rules as a group resize (resizeGroup). A rotated layer keeps its rotation and takes the size whose bounds are its old bounds scaled with the box, so the layers fillto(scaleLayerInParentdescribes when that needs a skew and what happens then); text that grew with its content gets a fixed size; a frame’s box scales and its children follow by their constraints (constrainChildren), as when the frame itself is resized. Stroke widths, radii, effects and font sizes do not change.boxAngleis the box’s turn in degrees (clockwise, screen y down) when it is not upright, as after rotating the selection:fromandtoare then in the box’s own coordinates, the parent’s turned byboxAngleabout its origin, and the layers scale along the box’s sides.Returns every changed node, each selected layer followed by its changed descendants, or an empty list when a layer is missing or locked.
源码function rotateNodesAbout( nodes: readonly SceneNode[], degrees: number, center: Point ): readonly SceneNode[]Turns sibling layers by
degrees(clockwise, screen y down) aroundcenterin their parent’s coordinates, as rotating a multi-selection does in Figma: each layer’s center moves aroundcenterand its own rotation grows by the same angle. A path’s transform turns as a whole.An upright connector is not turned: its two ends move around
center(connectorWithMovedEnds), so a free end turns with the selection like a line’s end, and an attached end is placed on its layer again by the page compiler, which cannot attach a turned connector.
源码function scaleNodesAbout( document: DesignDocument, nodeIds: readonly NodeId[], factor: number, anchor: { readonly x: number; readonly y: number } ): readonly SceneNode[]Scales several sibling layers together by
factoraboutanchorin their shared parent’s coordinates, as the scale tool (K) scales a multi-selection: every layer’s position moves away from the anchor byfactor, and each layer scales asscaleSubtreescales one, strokes, radii, effects and text included. Returns every changed node, or an empty list when a layer is missing or locked orfactoris not positive.
源码function connectorWithMovedEnds( node: ConnectorNode, move: (point: Point) => Point ): ConnectorNodeAn upright connector whose two ends are moved by
move(from and to points in its parent’s coordinates); its frame becomes the box around the moved ends. The web app’s store then refits the frame to the line the renderer draws (apps/web/src/store/connectorFrames.ts), which places an attached end on its layer’s edge whatever point is stored for it.
对齐、吸附与测量
对象吸附把移动中的框的边缘、中心和文本基线与附近的目标对齐,并报告需要绘制的参考线。距离测量给出按住 Option 拖动副本离开原对象时,以及按住 Option 悬停时显示的红色距离。
源码function snapObjectBounds( initialBounds: AlignmentRect, rawDeltaX: number, rawDeltaY: number, targets: readonly AlignmentTarget[], threshold: number, movingBaselines: readonly number[] = [] ): ObjectSnapResult
源码interface ObjectSnapResultreadonly deltaX: number源码readonly deltaY: number源码readonly guides: readonly AlignmentGuide[]源码
源码interface AlignmentRectreadonly left: number源码readonly top: number源码readonly right: number源码readonly bottom: number源码
源码interface AlignmentTargetreadonly id: string源码readonly bounds: AlignmentRect源码readonly baselines?: readonly number[]源码readonly line?: "x" | "y"源码使目标成为一条单独的线,例如标尺参考线。“x” 线位于
bounds.left,只提供水平位置;“y” 线位于bounds.top,只提供垂直位置。移动边界的任一边或中心都可以落在这条线上;为它显示的匹配线只跨越移动边界,因为参考线本身已经可见。
源码type AlignmentAnchor = "start" | "center" | "end" | "baseline"盒子用于对齐的点:左边/上边、中心、右边/下边,或文本基线。
源码interface AlignmentGuidereadonly orientation: "horizontal" | "vertical"源码readonly position: number源码readonly start: number源码readonly end: number源码readonly movingAnchor: AlignmentAnchor源码移动中的盒子在这条参考线上的锚点。叠加层用它把参考线画在与移动中选区轮廓相同的设备像素上,而渲染器会把选区轮廓画在盒子内部:位于左边或上边的参考线覆盖该线之后的像素,位于右边或下边的参考线覆盖该线之前的像素。
源码function measureDistances( reference: Rect, moving: Rect ): readonly DistanceMeasurement[]从
reference到moving的测量结果,两者都是位于同一坐标空间中的轴对齐矩形。距离为零的项会被省略,因此对齐的边不会产生测量。
源码interface DistanceMeasurementreadonly axis: MeasurementAxis源码“x” 测量水平距离,绘制为一条水平线。
readonly start: number源码线段在被测量轴上的起点和终点;
start < end。readonly end: number源码readonly position: number源码线段在另一条轴上的坐标。
readonly value: number源码end - start,即标签显示的数值。readonly kind: "gap" | "offset" | "inset"源码这是哪一种距离,用于标签和测试。
readonly extension: MeasurementExtension | null源码
源码type MeasurementAxis = "x" | "y"按住 ⌥ 将副本从原对象拖开时显示的红色距离测量,参照 Figma 的 Option 拖动测量和 ⌥ 悬停测量。
每条测量都是某一轴上的一条直线,连接参照对象(原对象)的一条边与移动对象(副本)的一条边:
- 当两个对象在某一轴上分开时,测量跨越两者之间的间隙。
- 当两者在该轴上重叠或相接、但在另一轴上分开时,测量跨越移动对象超出参照对象那一侧的两条边之间的偏移。
- 当两者在两个轴上都重叠时,会在每对对应的边之间显示四条内嵌测量。
测量线穿过参照对象的中心(两个对象在两个轴上都重叠时,则穿过重叠区域的中心)。当移动对象未延伸到这条线时,会用一条虚线延长移动对象的边,使测量有一个落点。
所有数值的单位与输入矩形相同(页面单位)。
源码interface MeasurementExtensionreadonly position: number源码移动对象的边在被测量轴上的坐标。
readonly start: number源码在另一轴上的跨度,从移动对象延伸到测量线。
readonly end: number源码
源码function formatMeasurementValue(value: number): string测量标签显示的数字:最多两位小数且不带末尾的零,与 Figma 显示距离的方式一致(“84”“12.5”“0.33”)。
富文本编辑
文本位置相对于段落,以 UTF-16 码元计数,并为可以绘制在两处的位置携带一个亲和性(affinity)。选区保留其锚点和焦点,因此方向得以保留。
源码interface TextPosition相对于段落的文本位置。偏移量始终以 UTF-16 码元计数。
readonly paragraphIndex: number源码readonly utf16Offset: number源码readonly affinity: TextAffinity源码
源码type TextAffinity = "upstream" | "downstream"当同一偏移量可以绘制在两个位置时(例如换行处或双向文本片段的边缘),文本位置属于边界的哪一侧。
源码interface TextRange锚点(anchor)和焦点(focus)保留选区方向,而不是将范围规范化。
readonly anchor: TextPosition源码readonly focus: TextPosition源码
源码interface TextCompositionState替换规范文档中某一范围的临时输入法(IME)文本。
readonly replacementRange: TextRange源码组合输入开始时所替换的规范范围。
readonly displayRange: TextRange源码当前已发布的组合输入预览所占用的范围。
readonly text: string源码readonly selectionStart: number源码文本中的 UTF-16 偏移量,与浏览器的组合输入 API 一致。
readonly selectionEnd: number源码
源码interface ActiveTextEditingState正在编辑的文本节点、它当前的选区,以及正在进行的 IME 组合输入(如果有)。
readonly nodeId: NodeId源码readonly selection: TextRange源码readonly composition: TextCompositionState | null源码
源码function assertTextPosition( value: unknown, label = "Text position" ): asserts value is TextPosition检查一个值是否为
TextPosition:段落索引和 UTF-16 偏移量为非负整数,且亲和性(affinity)为已知值。抛出TypeError或RangeError。它不会针对任何文档检查该位置。
源码function assertTextRange( value: unknown, label = "Text range" ): asserts value is TextRange检查一个值是否为
TextRange,且其锚点和焦点都能通过assertTextPosition。
源码function assertActiveTextEditingState( value: unknown, label = "Active text editing state" ): asserts value is ActiveTextEditingState检查一个值是否为
ActiveTextEditingState。如果存在组合输入,它必须有有效的范围,且其选区必须有序、非负,并且不超过以 UTF-16 码元计的组合文本长度。
reduceRichTextEditing 是文本编辑的纯状态转换。它从不测量文本、分派文档操作或记录历史,而是返回效果:选区变化、交由渲染器回答的导航查询、事务中的段落编辑,以及剪贴板写入。
源码function createRichTextEditingState( input: { readonly nodeId: NodeId; readonly paragraphs: readonly TextParagraph[]; readonly selection: TextRange; readonly layoutGeneration: bigint; } ): RichTextEditingState
源码function reduceRichTextEditing( state: RichTextEditingState, action: RichTextEditingAction ): RichTextEditingTransition纯粹的富文本状态转换。控制器从不测量文本、选择字素簇导航停靠点、派发文档操作,也不记录历史。
源码interface RichTextEditingState不可变的编辑器状态。它包含规范段落,但不拥有文档 store 或历史栈;由调用方应用返回的副作用。
readonly nodeId: NodeId源码readonly paragraphs: readonly TextParagraph[]源码readonly selection: TextRange源码readonly layoutGeneration: bigint | null源码与段落完全对应的代次;编辑之后为
null。readonly lastLayoutGeneration: bigint源码已同步的最高代次,在
layoutGeneration为null期间保留。readonly composition: RichTextCompositionSession | null源码readonly pointerSelection: RichTextPointerSelectionState | null源码readonly pendingRunFormat: RichTextPendingRunFormat | null源码完整的已编写文本片段(run)样式,用于之后在折叠光标处插入文本。
readonly preferredLocalX: number | undefined源码readonly nextRequestId: number源码readonly nextTransactionId: number源码
源码type RichTextEditingAction = | RichTextPointerAction | { readonly kind: "layout-synchronized"; readonly generation: bigint } | { readonly kind: "navigation-intent"; readonly operation: TextNavigationOperation; readonly extend: boolean; } | { readonly kind: "navigation-result"; readonly requestId: number; readonly result: TextNavigationResult | null; } | { readonly kind: "beforeinput"; readonly input: EditorTextInput } | { readonly kind: "composition"; readonly input: EditorCompositionInput } | { readonly kind: "clipboard"; readonly input: EditorClipboardInput } | { readonly kind: "keyboard"; readonly input: EditorKeyboardInput; readonly platform: RichTextKeyboardPlatform; } | { readonly kind: "format-runs"; readonly expectedSelection: TextRange; readonly expectedLayoutGeneration: bigint; readonly patch: RichTextRunFormatPatch; } | { readonly kind: "format-paragraphs"; readonly expectedSelection: TextRange; readonly expectedLayoutGeneration: bigint; readonly patch: RichTextParagraphFormatPatch; }
源码interface RichTextEditingTransitionreadonly state: RichTextEditingState源码readonly effects: readonly RichTextEditingEffect[]源码
源码type RichTextEditingEffect = | { readonly kind: "selection-change"; readonly nodeId: NodeId; readonly selection: TextRange; } | { readonly kind: "navigation-request"; readonly requestId: number; readonly query: TextNavigationQuery; } | { readonly kind: "transaction"; readonly boundary: RichTextTransactionBoundary; readonly transactionId: number; readonly intent: RichTextEditIntent; } | { readonly kind: "paragraph-edit"; readonly transactionId: number; readonly intent: RichTextEditIntent; readonly stage: RichTextParagraphEditStage; readonly nodeId: NodeId; readonly paragraphs: readonly TextParagraph[]; readonly selection: TextRange; readonly composition: TextCompositionState | null; } | { readonly kind: "rejected-intent"; readonly inputType: string; readonly reason: string; } | { readonly kind: "clipboard-write"; readonly action: "copy" | "cut"; readonly items: readonly { readonly mimeType: string; readonly data: Uint8Array; }[]; }
源码type RichTextEditIntent = | "insert-text" | "insert-paragraph" | "insert-line-break" | "paste-rich" | "paste-plain" | "delete-grapheme-backward" | "delete-grapheme-forward" | "delete-word-backward" | "delete-word-forward" | "delete-line-backward" | "delete-line-forward" | "delete-paragraph-backward" | "delete-paragraph-forward" | "delete-selection" | "format-runs" | "format-paragraphs" | "composition"
源码type RichTextPointerAction = | { readonly kind: "pointer"; readonly phase: "down"; readonly pointerId: number; readonly hit: TextHitResult; readonly extend: boolean; readonly clickCount?: number; } | { readonly kind: "pointer"; readonly phase: "move" | "up"; readonly pointerId: number; readonly hit: TextHitResult; } | { readonly kind: "pointer"; readonly phase: "cancel" | "lost-capture"; readonly pointerId: number; }
源码interface RichTextPointerSelectionStatereadonly pointerId: number源码readonly anchor: TextPosition源码readonly unit?: TextRange源码双击或三击选中的单词或段落。随后拖动时,它会保持选中,并从其远端边缘开始扩展选区,与浏览器行为一致。
readonly baselineSelection: TextRange源码readonly baselinePendingRunFormat: RichTextPendingRunFormat | null源码
源码function pointerUnitRange( paragraphs: readonly TextParagraph[], position: TextPosition, unit: "word" | "paragraph" ): TextRange双击或三击时选中的单词或段落。与浏览器一样,在单词之间双击会选中所落在的空格或标点。
源码interface RichTextCompositionSession extends TextCompositionStatereadonly transactionId: number源码readonly baselineParagraphs: readonly TextParagraph[]源码readonly baselineSelection: TextRange源码readonly previewApplied: boolean源码段落预览是否已发布给宿主。
源码type RichTextKeyboardPlatform = "macos" | "windows-linux"
源码type RichTextTransactionBoundary = "begin" | "commit" | "cancel"
源码type RichTextParagraphEditStage = | "canonical" | "composition-preview" | "composition-commit" | "composition-restore"
源码function activeTextEditingState( state: RichTextEditingState ): ActiveTextEditingState将控制器状态转换为渲染器叠加层的约定格式。
格式编辑会修改选区中的文本片段和段落。汇总函数报告工具栏应为某个选区显示的格式。
源码interface RichTextRunFormatPatchreadonly styleId?: RichTextFieldEdit<TextStyleId>源码readonly overrides?: { readonly [Key in keyof RichTextRunOverrides]?: RichTextFieldEdit< Exclude<RichTextRunOverrides[Key], undefined> > }源码readonly openTypeFeatureEdits?: RichTextTaggedValueEdits<boolean | number>源码逐个合并标签,不会替换无关的已编写特性值。
readonly fontVariationEdits?: RichTextTaggedValueEdits<number>源码逐个合并轴,不会替换无关的已编写可变字体值。
源码interface RichTextParagraphFormatPatch段落字段使用同样的显式 set/remove 编辑约定。
readonly direction?: RichTextFieldEdit<NonNullable<TextParagraph["direction"]>>源码readonly align?: RichTextFieldEdit<NonNullable<TextParagraph["align"]>>源码readonly spacingBefore?: RichTextFieldEdit<number>源码readonly spacingAfter?: RichTextFieldEdit<number>源码readonly indent?: RichTextFieldEdit<NonNullable<TextParagraph["indent"]>>源码readonly list?: RichTextFieldEdit<NonNullable<TextParagraph["list"]>>源码readonly indentFields?: RichTextIndentFieldEdits源码逐项合并缩进值;remove 会将该值恢复为零。
readonly listFields?: RichTextListFieldEdits源码合并列表控制项,同时保留未改动的标记。
readonly listMarkerFields?: RichTextListMarkerFieldEdits源码合并标记控制项,但不会隐式创建列表。
源码interface RichTextIndentFieldEditsreadonly left?: RichTextFieldEdit<number>源码readonly right?: RichTextFieldEdit<number>源码readonly firstLine?: RichTextFieldEdit<number>源码
源码interface RichTextListFieldEditsreadonly kind?: RichTextFieldEdit<"ordered" | "unordered">源码移除 kind 会清除列表;更改它会保留标记的编写内容。
readonly level?: RichTextFieldEdit<number>源码移除 level 会恢复为第 0 级。
readonly start?: RichTextFieldEdit<number>源码移除 start 会恢复自动编号。
源码interface RichTextListMarkerFieldEditsreadonly text?: RichTextFieldEdit<NonNullable<TextListMarker["text"]>>源码移除 text 会恢复渲染器自动生成的标记文本。
readonly styleId?: RichTextFieldEdit<NonNullable<TextListMarker["styleId"]>>源码移除
styleId会恢复从第一个文本片段继承共享样式。readonly overrides?: RichTextFieldEdit<NonNullable<TextListMarker["overrides"]>>源码移除 overrides 会恢复从第一个文本片段继承直接格式。
readonly gap?: RichTextFieldEdit<NonNullable<TextListMarker["gap"]>>源码移除 gap 会恢复渲染器根据字体自动计算的间距。
源码type RichTextFieldEdit<Value> = | { readonly kind: "set"; readonly value: Value } | { readonly kind: "remove" }省略表示字段保持不变;remove 表示恢复继承。
源码type RichTextTaggedValueEdits< Value > = Readonly<Record<string, RichTextFieldEdit<Value>>>
源码type RichTextRunOverrides = NonNullable<TextRun["overrides"]>
源码type RichTextPendingRunFormat = Readonly<Pick<TextRun, "styleId" | "overrides">>
源码function selectedRichTextRunFormats( state: RichTextEditingState ): readonly RichTextPendingRunFormat[]列举与当前选区相交的、不可变的已编写文本片段格式。
源码function aggregateRichTextSelectionFormatting( state: RichTextEditingState ): RichTextSelectionFormatting返回选区中文档里记录的格式,不查询 DOM 的编辑状态。
源码interface RichTextSelectionFormattingreadonly run: { readonly styleId: RichTextAggregatedValue<TextStyleId | undefined>; readonly overrides: RichTextAggregatedRunOverrides; readonly openTypeFeaturesByTag: Readonly< Record<string, RichTextAggregatedValue<boolean | number | undefined>> >; readonly fontVariationsByTag: Readonly< Record<string, RichTextAggregatedValue<number | undefined>> >; }源码readonly paragraph: { readonly direction: RichTextAggregatedValue<TextParagraph["direction"]>; readonly align: RichTextAggregatedValue<TextParagraph["align"]>; readonly spacingBefore: RichTextAggregatedValue<number | undefined>; readonly spacingAfter: RichTextAggregatedValue<number | undefined>; readonly indent: RichTextAggregatedValue<TextParagraph["indent"]>; readonly list: RichTextAggregatedValue<TextParagraph["list"]>; readonly indentFields: { readonly left: RichTextAggregatedValue<number | undefined>; readonly right: RichTextAggregatedValue<number | undefined>; readonly firstLine: RichTextAggregatedValue<number | undefined>; }; readonly listFields: { readonly kind: RichTextAggregatedValue< "ordered" | "unordered" | undefined >; readonly level: RichTextAggregatedValue<number | undefined>; readonly start: RichTextAggregatedValue<number | undefined>; }; readonly listMarkerFields: { readonly text: RichTextAggregatedValue<TextListMarker["text"]>; readonly styleId: RichTextAggregatedValue<TextListMarker["styleId"]>; readonly overrides: RichTextAggregatedValue<TextListMarker["overrides"]>; readonly gap: RichTextAggregatedValue<TextListMarker["gap"]>; }; }源码
源码type RichTextAggregatedValue<Value> = | { readonly kind: "uniform"; readonly value: Value } | { readonly kind: "mixed" }
源码type RichTextAggregatedRunOverrides = { readonly [Key in keyof RichTextRunOverrides]-: RichTextAggregatedValue< RichTextRunOverrides[Key] | undefined > }
矢量编辑
矢量编辑作用于矢量网络:顶点、顶点之间的线段,以及由线段环构成的区域。渲染器以节点局部坐标报告网络的几何信息,并对其进行命中测试。
源码interface VectorGeometryreadonly nodeId: NodeId源码readonly generation: bigint源码readonly vertices: readonly VectorVertexGeometry[]源码readonly handles: readonly VectorCubicHandleGeometry[]源码readonly segments: readonly VectorSegmentGeometry[]源码readonly regions: readonly VectorRegionGeometry[]源码
源码interface VectorVertexGeometryreadonly id: string源码readonly kind: "vertex"源码readonly localPoint: Point源码readonly screenPoint: Point源码
源码interface VectorCubicHandleGeometryreadonly id: string源码readonly kind: "cubic-handle"源码readonly segmentId: string源码readonly vertexId: string源码readonly endpoint: "start" | "end"源码readonly localPoint: Point源码readonly screenPoint: Point源码
源码type VectorSegmentGeometry = | VectorLineSegmentGeometry | VectorCubicSegmentGeometry | VectorArcSegmentGeometry
源码interface VectorLineSegmentGeometry extends VectorSegmentGeometryBasereadonly kind: "line"源码
源码interface VectorCubicSegmentGeometry extends VectorSegmentGeometryBasereadonly kind: "cubic"源码readonly startHandleId: string源码readonly endHandleId: string源码
源码interface VectorArcSegmentGeometry extends VectorSegmentGeometryBasereadonly kind: "elliptical-arc"源码readonly radiusX: number源码readonly radiusY: number源码readonly xAxisRotation: number源码readonly largeArc: boolean源码readonly sweep: boolean源码
源码interface VectorRegionGeometryreadonly id: string源码readonly kind: "region"源码readonly windingRule: "nonzero" | "evenodd"源码readonly localBounds: Rect源码readonly screenBounds: Rect源码
源码interface VectorHitQueryreadonly nodeId: NodeId源码readonly screenPoint: Point源码readonly toleranceCssPx: number源码
源码type VectorQueryHit = & { readonly id: string; readonly priority: number; readonly authoredOrder: number; readonly distanceCssPx: number; } & ( | { readonly kind: "vertex" } | { readonly kind: "cubic-handle"; readonly endpoint: "start" | "end" } | { readonly kind: "segment" } | { readonly kind: "region" })
源码interface VectorHitTestResultreadonly nodeId: NodeId源码readonly generation: bigint源码readonly hits: readonly VectorQueryHit[]源码
拓扑函数返回应用了一处改动的新网络。当改动无法完成时,它们会抛出带错误码的 VectorTopologyError:例如元素缺失、id 重复、参数错误或不安全的区域编辑。
源码class VectorTopologyError extends Errorreadonly code: VectorTopologyErrorCode源码readonly componentId: string | null源码new ( code: VectorTopologyErrorCode, message: string, componentId: string | null = null )源码
源码type VectorTopologyErrorCode = | "DUPLICATE_ID" | "INVALID_PARAMETER" | "MISSING_HANDLE" | "MISSING_LOOP" | "MISSING_REGION" | "MISSING_SEGMENT" | "MISSING_VERTEX" | "UNSAFE_REGION_EDIT" | "UNSUPPORTED_SEGMENT"
源码function addVectorVertex( network: VectorNetwork, vertex: VectorVertex ): VectorNetwork添加一个由调用方标识的自由锚点,不改变已有拓扑。
源码function addVectorSegment( network: VectorNetwork, segment: VectorSegment ): VectorNetwork使用调用方提供的 ID,在已有锚点之间添加一条直线边或三次曲线边。
源码function updateVectorVertices( network: VectorNetwork, updates: readonly VectorVertexUpdate[] ): VectorNetwork移动一个或多个共享顶点,而不改变相对于端点的控制柄。
源码interface VectorVertexUpdatereadonly vertexId: VectorVertexId源码readonly x: number源码readonly y: number源码
源码function updateVectorHandle( network: VectorNetwork, update: VectorHandleUpdate ): VectorNetwork原子性地更新一个控制柄,并应用其可选的切线约束。
源码interface VectorHandleUpdatereadonly handleId: VectorHandleId源码readonly dx: number源码readonly dy: number源码
源码function setVectorTangentConstraint( network: VectorNetwork, update: VectorTangentConstraintUpdate ): VectorNetwork将同一顶点上的两个控制柄耦合在一起,并替换任一控制柄原先所属的配对。
源码interface VectorTangentConstraintUpdatereadonly vertexId: VectorVertexId源码readonly handleIds: readonly [VectorHandleId, VectorHandleId]源码readonly drivenHandleId: VectorHandleId源码被驱动的控制柄保持其位置;与之配对的控制柄会与它对齐。
readonly mode: VectorTangentConstraint["mode"]源码
源码function removeVectorTangentConstraints( network: VectorNetwork, handleIds: readonly VectorHandleId[] ): VectorNetwork移除所有涉及所给控制柄之一的切线对。
源码function deleteVectorVertices( network: VectorNetwork, vertexIds: readonly VectorVertexId[] ): VectorNetwork删除锚点、所有与之相连的边、受影响的填充环以及切线对。
源码function deleteVectorSegments( network: VectorNetwork, segmentIds: readonly VectorSegmentId[], options: DeleteVectorComponentsOptions = {} ): VectorNetwork删除边以及依赖这些边的所有填充环。
源码function deleteVectorRegions( network: VectorNetwork, regionIds: readonly VectorRegionId[] ): VectorNetwork删除可独立绘制的区域,不改变它们共享的拓扑。
源码interface DeleteVectorComponentsOptionsreadonly deleteOrphanVertices?: boolean源码删除线段时默认保留自由锚点。
源码function addVectorRegion( network: VectorNetwork, region: VectorRegion ): VectorNetwork在一条已有的连通链上添加一个可独立绘制的区域。
源码function openVectorRegionLoop( network: VectorNetwork, target: VectorRegionLoopTarget, segmentId: VectorSegmentId ): VectorNetwork通过移除一条独占边,打开一个在网络中闭合的填充轮廓。剩余的链通过
implicitClose保持相同的填充;共享的填充边会被拒绝,因为移除它会悄无声息地破坏其他区域。
源码function closeVectorRegionLoop( network: VectorNetwork, target: VectorRegionLoopTarget, segment: VectorSegment ): VectorNetwork用一条由调用方标识的直线或三次曲线,闭合一个隐式填充的开放轮廓。提供的边可以以任一方向跨越开放缺口。
源码interface VectorRegionLoopTargetreadonly regionId: VectorRegionId源码readonly loopIndex: number源码
源码function joinVectorVertices( network: VectorNetwork, sourceVertexId: VectorVertexId, targetVertexId: VectorVertexId, options: JoinVectorVerticesOptions = {} ): VectorNetwork将一个共享锚点合并到另一个锚点,并重新连接所有相关的拓扑结构。
源码interface JoinVectorVerticesOptionsreadonly position?: { readonly x: number; readonly y: number }源码默认为保留下来的目标顶点的位置。
源码function convertVectorLineToCubic( network: VectorNetwork, segmentId: VectorSegmentId, ids: VectorLineToCubicIds ): VectorNetwork将直线转换为三次曲线,同时保留其线段 ID 和区域引用。
源码interface VectorLineToCubicIdsreadonly startHandleId: VectorHandleId源码readonly endHandleId: VectorHandleId源码
源码function convertVectorCubicToLine( network: VectorNetwork, segmentId: VectorSegmentId ): VectorNetwork将三次曲线转换为直线,并移除引用其控制柄的约束。
源码function splitVectorSegment( network: VectorNetwork, segmentId: VectorSegmentId, amount: number, ids: VectorSplitIds ): VectorNetwork在 0<t<1 处拆分直线或三次曲线。原线段保留其 ID,并覆盖前半部分;原有端点控制柄的 ID 仍留在其编写时所在的端点上。
源码interface VectorSplitIds
源码type VectorEditableSegment = Extract<VectorSegment, { kind: "line" | "cubic" }>
reduceVectorEditing 保存单条路径的元素选区、拖动状态和预览网络。它向调用方返回效果:指针捕获、选区变化,以及带有原因的 commit-network 请求。
源码function createVectorEditingState( options: { readonly nodeId: NodeId; readonly network: VectorNetwork; readonly selection?: VectorEditingSelection; } ): VectorEditingState
源码function reduceVectorEditing( state: VectorEditingState, action: VectorEditingAction ): VectorEditingResult
源码interface VectorEditingStatereadonly nodeId: NodeId源码readonly network: VectorNetwork源码readonly previewNetwork: VectorNetwork源码readonly selection: VectorEditingSelection源码readonly gesture: VectorEditingGesture | null源码
源码type VectorEditingAction = | { readonly type: "select"; readonly hit: VectorComponentHit | null; readonly modifiers: EditorModifiers; } | { readonly type: "drag-start"; readonly hit: VectorComponentHit; readonly pointerId: number; readonly position: Point; readonly modifiers: EditorModifiers; readonly bend?: { readonly ids: VectorEditIdAllocator; readonly threshold: number; }; readonly breakThreshold?: number; readonly distanceSpace?: TransformMatrix; } | { readonly type: "point-box-start"; readonly pointerId: number; readonly position: Point; readonly box: VectorPointBox; readonly hit: VectorPointBoxHit; readonly localToBox: TransformMatrix; readonly boxToLocal: TransformMatrix; readonly modifiers: EditorModifiers; } | { readonly type: "drag-move"; readonly pointerId: number; readonly position: Point; readonly modifiers?: EditorModifiers; } | { readonly type: "drag-end" | "drag-cancel" | "lost-capture"; readonly pointerId: number; } | { readonly type: "commit-topology"; readonly network: VectorNetwork; readonly reason: VectorEditingCommitReason; readonly selection?: VectorEditingSelection; } | { readonly type: "external-synchronize"; readonly network: VectorNetwork }
源码interface VectorEditingResultreadonly state: VectorEditingState源码readonly effects: readonly VectorEditingEffect[]源码
源码type VectorEditingEffect = | { readonly type: "capture-pointer"; readonly pointerId: number } | { readonly type: "release-pointer"; readonly pointerId: number } | { readonly type: "selection-changed"; readonly selection: VectorEditingSelection; } | { readonly type: "commit-network"; readonly nodeId: NodeId; readonly network: VectorNetwork; readonly reason: VectorEditingCommitReason; }
源码type VectorEditingCommitReason = | "move-vertices" | "move-handle" | "move-segment" | "add-segment" | "convert-segment" | "split-segment" | "join-segments" | "delete-components" | "open-path" | "close-path" | "tangent-constraint" | "vertex-corner-radius" | "boolean-operation" | "add-point" | "bend" | "cut" | "region-fill"
源码interface VectorEditingSelectionreadonly vertexIds: readonly VectorVertexId[]源码readonly handleIds: readonly VectorHandleId[]源码readonly segmentIds: readonly VectorSegmentId[]源码readonly regionIds: readonly VectorRegionId[]源码readonly primary: VectorComponentSelection | null源码
源码interface VectorEditingGesturereadonly pointerId: number源码readonly component: Extract< VectorComponentSelection, { readonly kind: "vertex" | "handle" | "segment" } >源码readonly startedAt: Point源码readonly currentAt: Point源码readonly sourceNetwork: VectorNetwork源码readonly draggedVertexIds: readonly VectorVertexId[]源码readonly collapseOnClick?: boolean源码A plain press on a component that was already selected among others: if it ends without moving, it selects just that component, as in Figma.
readonly baseNetwork?: VectorNetwork源码The network a handle drag edits, when it isn’t
sourceNetwork: an Alt drag on a handle first drops the handle’s mirroring pair.readonly breakThreshold?: number源码How far the pointer must go before an Alt drag applies
baseNetwork; a press that never gets that far changes nothing. In network units, or in the units ofdistanceSpacewhen that is set.readonly distanceSpace?: TransformMatrix源码A matrix from network coordinates to the space this gesture measures its thresholds in, such as the screen. Without it they are in network units.
readonly breakStarted?: boolean源码Set once the pointer has gone past
breakThreshold, and stays set.readonly bend?: VectorBendGesture源码A Bend tool drag, which shapes handles instead of moving points.
readonly pointBox?: VectorPointBoxGesture源码A drag of the box around several selected points, which scales or rotates them.
源码type VectorComponentHit = Extract< EditorHit, { readonly part: | "vector-anchor" | "vector-handle" | "vector-segment" | "vector-region"; } >
源码type VectorComponentSelection = | { readonly kind: "vertex"; readonly id: VectorVertexId } | { readonly kind: "handle"; readonly id: VectorHandleId } | { readonly kind: "segment"; readonly id: VectorSegmentId } | { readonly kind: "region"; readonly id: VectorRegionId }
源码function vectorComponentHitFromQueryHit( nodeId: NodeId, network: VectorNetwork, hit: VectorQueryHit ): VectorComponentHit | null将不带品牌类型(branded type)的渲染器查询命中映射回对应的规范记录。 ID 会有意在其组成部分类型内进行校验,因为 ABI 允许顶点、控制柄、线段和区域使用相同的字符串。
updateVectorInteraction 把指针输入接入矢量编辑。它只在指针按下时进行命中测试;拖动中的后续点都经过在那次按下时固定的变换。
源码function createVectorInteractionState( environment: VectorInteractionEnvironment, selection?: VectorEditingSelection ): VectorInteractionState | null仅当场景、矢量几何和节点变换都描述同一个保留代次时,才开启组成部分的编辑。
源码function updateVectorInteraction( environment: VectorInteractionEnvironment, state: VectorInteractionState, input: EditorPointerInput ): VectorInteractionResult归约针对现有路径组成部分的输入。只有指针按下时才会执行矢量命中查询;一次手势中,之后的每个点都使用该手势冻结的逆变换。
源码function invalidateVectorInteraction( state: VectorInteractionState, reason: VectorInteractionInvalidationReason ): VectorInteractionResult
源码interface VectorInteractionEnvironmentreadonly nodeId: NodeId源码readonly network: VectorNetwork源码当前由
nodeId拥有的确切规范网络对象。readonly viewport: ViewportState源码当前安装在
renderSession上的确切视口对象。readonly renderSession: VectorInteractionRenderQueries源码readonly hitToleranceCssPx?: number源码原生组成部分命中半径,单位为 CSS 像素。默认为 6。
readonly editTool?: VectorEditToolContext源码The vector edit mode tool, when it isn’t the Move tool: Pen adds a point where it presses a segment, Bend shapes handles from a point or segment, and Cut breaks the path at a point or segment.
idsnames what they add.readonly pointBox?: boolean源码Offer the box around several selected points (the Move tool does): a press on one of its handles or rotate zones scales or rotates the points.
源码type VectorInteractionRenderQueries = Pick< InteractiveRenderSession, "getSceneGeometrySnapshot" | "getVectorGeometry" | "hitTestVector" >
源码interface VectorInteractionStatereadonly editing: VectorEditingState源码readonly binding: VectorInteractionBinding源码readonly status: "ready" | "awaiting-commit" | "invalidated"源码
源码interface VectorInteractionBindingreadonly generation: bigint源码readonly expectedNetwork: VectorNetwork源码readonly viewport: ViewportState源码readonly renderSession: VectorInteractionRenderQueries源码readonly nodeGeometry: NodeGeometry源码readonly screenToLocal: TransformMatrix源码
源码type VectorInteractionInvalidationReason = | "node-changed" | "network-changed" | "viewport-changed" | "render-session-changed" | "scene-generation-changed" | "node-geometry-changed" | "vector-query-unavailable" | "coordinate-conversion-failed"
源码interface VectorInteractionResultreadonly state: VectorInteractionState源码readonly effects: readonly VectorInteractionEffect[]源码
源码type VectorInteractionEffect = | { readonly type: "capture-pointer"; readonly pointerId: number } | { readonly type: "release-pointer"; readonly pointerId: number } | { readonly type: "selection-changed"; readonly selection: VectorEditingSelection; } | { readonly type: "commit-network"; readonly nodeId: NodeId; readonly expectedNetwork: VectorNetwork; readonly network: VectorNetwork; readonly reason: Extract< VectorEditingEffect, { readonly type: "commit-network" } >["reason"]; readonly generation: bigint; } | { readonly type: "editing-invalidated"; readonly reason: VectorInteractionInvalidationReason; }
源码function vectorInteractionLocalPoint( state: VectorInteractionState, screenPoint: Point ): Point | null通过交互中冻结的精确仿射逆变换转换一个屏幕点。
源码function vectorEditingSnapshot( state: VectorInteractionState ): VectorEditingSnapshot | null一旦冻结的渲染器/规范权威状态失效,就返回
null。
源码interface VectorEditingSnapshot单个现有路径的组成部分编辑器的状态,与渲染器无关。source network 是授权之后提交的那个确切的规范对象,而 network 是由叠加层绘制的临时预览。
readonly nodeId: NodeId源码readonly generation: bigint源码readonly coordinateSpace: "node-local"源码readonly status: "ready" | "awaiting-commit"源码readonly sourceNetwork: VectorNetwork源码readonly network: VectorNetwork源码readonly selection: VectorEditingSelectionSnapshot源码readonly gesture: VectorEditingGestureSnapshot | null源码readonly pendingHandle?: PenPendingHandle | null源码The handle the Pen is pulling out of a point, or left there for the next segment: drawn as chrome, because no segment of
networkowns it yet. Its point is innetwork. Absent or null when there is none.readonly viewport: ViewportState源码与此保留场景代次一同冻结的确切视口对象。
readonly localToDocument: TransformMatrix源码readonly localToScreen: TransformMatrix源码readonly screenToLocal: TransformMatrix源码
源码interface VectorEditingSelectionSnapshotreadonly vertexIds: readonly VectorVertexId[]源码readonly handleIds: readonly VectorHandleId[]源码readonly segmentIds: readonly VectorSegmentId[]源码readonly regionIds: readonly VectorRegionId[]源码readonly primary: VectorEditingComponentSnapshot | null源码
源码interface VectorEditingGestureSnapshotreadonly pointerId: number源码readonly component: Extract< VectorEditingComponentSnapshot, { readonly kind: "vertex" | "handle" | "segment" } >源码readonly startedAt: Point源码手势开始时冻结的节点局部指针坐标。
readonly currentAt: Point源码预览所使用的最新节点局部指针坐标。
源码type VectorEditingComponentSnapshot = | { readonly kind: "vertex"; readonly id: VectorVertexId } | { readonly kind: "handle"; readonly id: VectorHandleId } | { readonly kind: "segment"; readonly id: VectorSegmentId } | { readonly kind: "region"; readonly id: VectorRegionId }
布尔运算(联集、交集、差集、排除)通过 InteractiveRenderSession.booleanVectorPaths 向渲染器请求。
源码type VectorBooleanOperation = | "union" | "intersection" | "difference" | "exclusion"
源码interface VectorBooleanPathRequest一次基于保留场景的布尔运算请求,结果 ID 的分配权归调用方所有。
readonly primaryNodeId: NodeId源码readonly secondaryNodeId: NodeId源码readonly operation: VectorBooleanOperation源码readonly resultIdNamespace: string源码
源码interface VectorBooleanPathResult由某一个确切的保留场景代次生成的、位于主对象局部空间中的规范几何。
readonly generation: bigint源码readonly primaryNodeId: NodeId源码readonly secondaryNodeId: NodeId源码readonly operation: VectorBooleanOperation源码readonly vectorNetwork: VectorNetwork源码
无障碍
createAccessibilitySnapshotV1 根据一份文档、一个页面和一代场景几何构建屏幕阅读器看到的语义树。子节点遵循文档中的子节点顺序,而不是绘制顺序。边界是以 CSS 像素表示的、经过裁剪的屏幕边界。它返回的每个对象都是冻结的。
源码interface AccessibilitySnapshotV1readonly version: typeof ACCESSIBILITY_SNAPSHOT_VERSION源码readonly documentId: DocumentId源码readonly pageId: PageId源码readonly generation: bigint源码保留场景的代次,而不是编辑器历史的修订号。
readonly focusOwner: AccessibilityFocusOwnerV1源码readonly root: AccessibilityNodeSnapshotV1源码
源码function createAccessibilitySnapshotV1( input: AccessibilitySnapshotInputV1 ): AccessibilitySnapshotV1为一个当前页面构建与渲染器无关的 v1 语义镜像。它只读取、从不修改规范文档、几何或叠加层。
源码interface AccessibilitySnapshotInputV1readonly document: DesignDocument源码readonly activePageId: PageId源码readonly geometry: SceneGeometrySnapshot源码readonly overlay: AccessibilityOverlayStateV1源码
源码interface AccessibilityNodeSnapshotV1readonly id: NodeId源码readonly role: AccessibilityRoleV1源码readonly name: string源码readonly description: string | null源码readonly value: string | null源码readonly screenBounds: Rect源码可见的、经裁剪的边界,单位为 CSS 像素,相对于编辑器表面。
readonly focused: boolean源码readonly selected: boolean源码readonly editing: boolean源码readonly readOnly: boolean源码readonly actions: readonly AccessibilityActionV1[]源码readonly textSelection: AccessibilityTextSelectionV1 | null源码readonly children: readonly AccessibilityNodeSnapshotV1[]源码
源码type AccessibilityRoleV1 = typeof ACCESSIBILITY_ROLES_V1[number]
源码const ACCESSIBILITY_ROLES_V1: readonly [ "document", "group", "text", "textbox", "code", "image", "video", "shape", "connector" ]
源码type AccessibilityActionV1 = typeof ACCESSIBILITY_ACTIONS_V1[number]
源码const ACCESSIBILITY_ACTIONS_V1: readonly [ "focus", "select", "toggle-selection", "edit" ]
源码type AccessibilityFocusOwnerV1 = typeof ACCESSIBILITY_FOCUS_OWNERS_V1[number]
源码const ACCESSIBILITY_FOCUS_OWNERS_V1: readonly [ "none", "react-shell", "canvas", "accessibility-mirror", "text-input" ]
源码type AccessibilityEditStateV1 = | { readonly kind: "text"; readonly nodeId: NodeId; readonly selection: AccessibilityTextSelectionV1; } | { readonly kind: "code"; readonly nodeId: NodeId }
源码interface AccessibilityOverlayStateV1由 UI 持有的状态,叠加在某一个确切的保留场景代次之上。
readonly focusOwner: AccessibilityFocusOwnerV1源码readonly focusedNodeId: NodeId | null源码readonly selectedNodeIds: readonly NodeId[]源码readonly edit: AccessibilityEditStateV1 | null源码readonly pageLayersHidden?: boolean源码True when the scene draws none of the page’s own layers, only the open component’s view (the isolation split’s component pane). The mirror then lists the component’s layers alone, and no page layer needs geometry.
源码interface AccessibilityTextPositionV1相对于段落的 UTF-16 位置,与渲染器布局无关。
readonly paragraphIndex: number源码readonly utf16Offset: number源码readonly affinity: AccessibilityTextAffinityV1源码
源码interface AccessibilityTextSelectionV1锚点(anchor)和焦点(focus)保留选区的方向。
readonly anchor: AccessibilityTextPositionV1源码readonly focus: AccessibilityTextPositionV1源码
源码type AccessibilityTextAffinityV1 = typeof ACCESSIBILITY_TEXT_AFFINITIES_V1[number]
源码const ACCESSIBILITY_TEXT_AFFINITIES_V1: readonly ["upstream", "downstream"]
源码const ACCESSIBILITY_SNAPSHOT_VERSION: 1
源码class AccessibilitySnapshotErrorV1 extends Errornew (readonly code: AccessibilitySnapshotErrorCodeV1, message: string)源码
源码type AccessibilitySnapshotErrorCodeV1 = | "invalid-active-page" | "invalid-document-tree" | "invalid-geometry" | "invalid-overlay"
resolveAccessibilityActionAuthorityV1 对照动作请求所来自的快照检查该请求。针对其他文档或页面、旧代号、缺失节点或节点不提供的动作的请求,会在任何改动发生之前被拒绝。
源码function resolveAccessibilityActionAuthorityV1( snapshot: AccessibilitySnapshotV1, request: AccessibilityActionRequestV1 ): AccessibilityActionAuthorityV1只负责解析权限。在本函数确认确切的代次和所声明的节点操作之后,路由和修改仍由调用方负责。
源码interface AccessibilityActionRequestV1readonly documentId: DocumentId源码readonly pageId: PageId源码readonly generation: bigint源码readonly nodeId: NodeId源码readonly action: AccessibilityActionV1源码
源码interface AccessibilityActionAuthorityV1readonly version: typeof ACCESSIBILITY_SNAPSHOT_VERSION源码readonly documentId: DocumentId源码readonly pageId: PageId源码readonly generation: bigint源码readonly nodeId: NodeId源码readonly action: AccessibilityActionV1源码readonly node: AccessibilityNodeSnapshotV1源码
源码class AccessibilityActionAuthorityErrorV1 extends Errornew (readonly code: AccessibilityActionAuthorityErrorCodeV1, message: string)源码
源码type AccessibilityActionAuthorityErrorCodeV1 = | "invalid-request" | "context-mismatch" | "stale-generation" | "node-not-found" | "action-not-advertised"
源码interface AccessibilityNodeSnapshotreadonly id: string源码readonly role: string源码readonly name: string源码readonly value?: string源码readonly bounds?: Rect源码readonly focused: boolean源码readonly selected: boolean源码readonly actions: readonly string[]源码readonly children: readonly AccessibilityNodeSnapshot[]源码
测试场景
共享场景对每个 EditorDriver 运行相同的编辑检查。每个场景都声明自己需要的能力。富文本、矢量和无障碍场景集彼此独立,后端可以在支持时再采用它们。
源码interface EditorScenarioreadonly name: string源码readonly requirements?: EditorScenarioRequirements源码run(driver: EditorDriver): Promise<void>源码
源码interface EditorScenarioRequirementsreadonly pointerTypes?: readonly EditorPointerType[]源码readonly keyboardRepeat?: boolean源码readonly composition?: boolean源码readonly clipboard?: readonly EditorClipboardInput["action"][]源码readonly textEditing?: boolean源码readonly textGeometry?: boolean源码readonly textHitTesting?: boolean源码readonly vectorGeometry?: boolean源码readonly vectorHitTesting?: boolean源码readonly vectorBooleanOperations?: boolean源码readonly accessibility?: boolean源码readonly frameCapture?: boolean源码readonly variableDevicePixelRatio?: boolean源码
源码function runEditorScenarios( driver: EditorDriver, scenarios: readonly EditorScenario[] ): Promise<void>
源码function assertEditorDriverCapabilities( actual: EditorDriverCapabilities, required: EditorScenarioRequirements ): void
源码const standardEditorScenarios: readonly EditorScenario[]所有后端共享的、与后端无关且信号价值高的编辑工作流。
源码const richTextEditorScenarios: readonly EditorScenario[]富文本一致性场景单独存放,直到某个后端明确报告具备所有必需的能力。任何声称支持、却未提供权威的文本整形、导航和输入法(IME)行为的后端,都无法通过这些场景。
源码const vectorEditorScenarios: readonly EditorScenario[]针对现有路径的一致性工作流,适用于提供权威矢量查询的后端。
源码const vectorBooleanEditorScenarios: readonly EditorScenario[]仅限原生实现的布尔运算工作流,由所有声明具备该能力的后端共享。
源码const accessibilityEditorDriverScenariosV1: readonly EditorScenario[]与后端无关的无障碍验收场景,适用于第 1 版 EditorDriver。
源码function runAccessibilityEditorDriverScenariosV1( driver: EditorDriver ): Promise<void>检查能力后,运行共享的无障碍 v1
EditorDriver场景。
无障碍预言(oracle)场景无需驱动,直接检查 createAccessibilitySnapshotV1 和 resolveAccessibilityActionAuthorityV1,或其替代实现。
源码const accessibilityOracleScenariosV1: readonly AccessibilityOracleScenarioV1[]
源码function runAccessibilityOracleScenariosV1( adapter: AccessibilityOracleAdapterV1 = defaultAccessibilityOracleAdapterV1 ): void运行时不查询也不声明任何当前的
EditorDriver能力。
源码interface AccessibilityOracleAdapterV1createSnapshot(input: AccessibilitySnapshotInputV1): AccessibilitySnapshotV1源码resolveAction( snapshot: AccessibilitySnapshotV1, request: AccessibilityActionRequestV1 ): AccessibilityActionAuthorityV1源码
源码interface AccessibilityOracleScenarioV1readonly name: string源码run(adapter: AccessibilityOracleAdapterV1): void源码
源码const defaultAccessibilityOracleAdapterV1: AccessibilityOracleAdapterV1
其他导出
尚未归入上述章节的导出,按字母顺序排列。
源码function abandonVectorSubPath( network: VectorNetwork, vertexId: VectorVertexId, startedVertexId: VectorVertexId | null ): VectorNetwork | nullThe network without a sub-path that was started and never drawn: the point is removed when it is the one a Pen click started (
startedVertexId), no segment touches it and the network has other points. Returns null when there is nothing to remove. A point without segments that was not started this way stays, because it is the user’s own: for example the end left behind when its segments were deleted. The only point of a network stays too (a layer keeps at least the point it was created with).
源码function addPenSegment( network: VectorNetwork, shape: PenSegmentShape ): VectorNetworkAdds the segment a Pen press makes between two points of the network.
- Plain click from a point without a remembered handle: a straight line.
- Otherwise a cubic. It leaves the start along the remembered handle, or along a third of the straight way to the end when there is none. It arrives at the end along the mirror of the drag, or with no handle after a plain click.
When the remembered handle still mirrors the handle of the segment that arrived at the start point, the two are paired (angle and length), so the point stays smooth when either handle is moved later.
源码function bendVectorSegment( prepared: VectorPreparedSegmentBend, delta: Point ): VectorNetworkA Bend drag on a segment: moves both handles so the point taken hold of at
tmoves bydelta, the handle nearer to it moving more. Handles paired with a neighbouring segment’s handle keep their pair in step; a pair made of the segment’s own two handles is dropped.
源码function bendVectorVertex( prepared: VectorPreparedVertex, vertexId: VectorVertexId, heldEnd: number, drag: Point ): VectorNetworkA Bend drag from a point: the held segment end’s handle follows the pointer (
drag, from the point) and the other end’s handle mirrors it in angle and length. A point joining more than two segment ends is unchanged.
源码function compareVectorTangentConstraints( left: VectorTangentConstraint, right: VectorTangentConstraint ): numberOrders tangent constraints the way the document schema requires.
源码function constrainVectorCutLineEnd(start: Point, end: Point): PointThe end of a cut line held to 45 degree steps from its start, as Shift does: the nearest of the eight directions, at the pointer’s distance along it. Both points are in screen coordinates.
源码function convertVectorArcToCubics( network: VectorNetwork, segmentId: VectorSegmentId, ids: VectorEditIdAllocator ): VectorArcConversionReplaces an elliptical arc with the cubic pieces that trace it, joined by new vertices whose two handles keep the same angle. An arc SVG draws as a straight line becomes a line. Fill loops run through the pieces in order.
源码function cornerVectorVertex( network: VectorNetwork, vertexId: VectorVertexId ): VectorNetworkMakes a point a corner: every handle at it goes to zero length and its handle pairs are dropped. A cubic left with no handles becomes a line.
源码function createStandardAccessibilityEditorDriverDocumentV1(): DesignDocument用于共享
EditorDriver验收的、资源完整的规范文档。它复用已签入仓库的标准富文本字体,因此渲染不依赖宿主字体或无效的占位资源。原生代码节点的编译仍是生产环境 Wasm 运行所需的构建产物。
源码function createStandardAccessibilityScenarioDocumentV1(): DesignDocument由各个语义参照(semantic oracle)实现共享的规范文档。
源码function createStandardAccessibilityScenarioGeometryV1(): SceneGeometrySnapshot几何数据有意使用与规范子节点树不同的顺序。
源码function createStandardAccessibilityScenarioInputV1(): AccessibilitySnapshotInputV1
源码function createStandardEditorScenarioDocument( kind: StandardEditorScenarioDocument ): DesignDocument由每个交互式渲染后端共享的规范模型文档。
源码function createStandardVectorBooleanScenarioDocument( kind: StandardVectorBooleanScenarioDocument ): DesignDocument
源码function createStandardVectorScenarioDocument( kind: StandardVectorScenarioDocument ): DesignDocument由每个具备相应能力的交互式后端使用的、包含已有路径的规范文档。
源码const CROSSING_TOLERANCE: 0.000001The share of the edges’ size below which two points count as one.
源码type Cubic = readonly [Point, Point, Point, Point]A cubic Bézier curve as its four control points.
源码function cubicLineCrossings( cubic: Cubic, from: Point, to: Point ): readonly number[]The positions
tin [0, 1] where a cubic crosses the straight cut line fromfromtoto, in order. A crossing is where the curve passes from one side of the line to the other within the line’s length, so a curve that only touches the line (a tangent) is not cut. A curve that starts or ends on the line is crossed there (t = 0 or 1). A curve lying along the line is not crossed.
源码function cutVectorNetworkAlongLine( network: VectorNetwork, from: Point, to: Point, ids: VectorEditIdAllocator ): VectorCutCuts the network along the straight line from
fromtoto(network coordinates): each segment the line crosses gets a point at every crossing and breaks there, and each point the line passes through breaks as a Cut click on it does. Fill loops through a break become open loops, as with the click. Returns the network unchanged, with no points, when the line crosses nothing.
源码function cutVectorSegment( network: VectorNetwork, segmentId: VectorSegmentId, t: number, ids: VectorEditIdAllocator ): VectorCutCuts a segment at position
t(seeVectorSegmentPoint.t): a point goes in there without changing the shape, and the path breaks at it into two ends.
源码function deleteAndHealVectorVertices( network: VectorNetwork, vertexIds: readonly VectorVertexId[], allocate: VectorHealIdAllocator ): VectorNetworkDeletes the given anchors one after another, healing each as described above. Anchors an earlier heal already removed are skipped.
源码function detachVectorVertex( network: VectorNetwork, vertexId: VectorVertexId, ids: VectorEditIdAllocator ): VectorCutGives every segment end at a vertex a vertex of its own at the same place; the first segment end keeps the original. Handle pairs at the vertex are dropped, since their handles no longer meet. A vertex with at most one segment end is left as it is.
源码function doubleClickSelectionAction( document: DesignDocument, rootId: NodeId, hitNodeId: NodeId, primarySelectedNodeId: NodeId | null, mode: InstanceSelectionMode ): DoubleClickSelectionAction | nullThe action of a double click on
hitNodeId. With the instance as one object ("instance"), a double click on an instance, or on any layer of one, enters isolation for the outermost instance’s component; once the selection is inside that instance it acts as in a group (design question 1). Like a group ("group"), and outside instances, a double click selects one level deeper, and edits the hit layer once it is the selected one.
源码type DoubleClickSelectionAction = | { readonly kind: "select"; readonly nodeId: NodeId } | { readonly kind: "edit"; readonly nodeId: NodeId } | { readonly kind: "isolate"; readonly instanceId: NodeId }What a double click with the move tool does (components design 5.5).
源码function findUnstoredVectorFaces( network: VectorNetwork ): readonly VectorRegionLoop[]The faces of a network (
findVectorFaces) that no region is stored for yet.
源码function findVectorAreas(network: VectorNetwork): readonly VectorArea[]The areas a network encloses when every crossing (
findVectorCrossings) is treated as a corner: a five-point star drawn in one stroke is six, its middle and five tips; a figure of eight is two; two overlapping loops are three. An area that has a separate loop lying inside it keeps its whole inside. An area no larger than the crossing tolerance times the length of its outline is left out; for a long strip that is a width of twice the tolerance.These are the areas a fill can be seen in. A region cannot store one of them when its boundary runs along a piece of a segment, so
findVectorFacescovers them with loops of whole segments.
源码function findVectorCrossings(network: VectorNetwork): readonly VectorCrossing[]Every place where two segments of a network meet away from a point they share: they cross, one ends on the other or touches it, or they run along each other (the two ends of the shared stretch are given). A curve that crosses itself counts. Segments that meet at a point of the network they both use are joined there, and that is no crossing.
Lines are intersected exactly. Curves are intersected as the straight pieces their outline is drawn with (24 per cubic piece), so a crossing with a curve is found to within that flattening, and
atis measured along those pieces. Places no further apart, in a straight line, than a millionth of the network’s size count as one (CROSSING_TOLERANCE).The network is not changed: no point is added at a crossing.
源码function findVectorFaces(network: VectorNetwork): readonly VectorRegionLoop[]The areas a network encloses: the bounded faces of the network read as a planar graph, in network order of their first segment. A closed Pen path is one face; a square with a diagonal is two; a loop inside another, not joined to it, is a face of its own next to the outer one, which keeps its whole inside. Open ends, dangling branches and connectors between loops bound nothing and are left out.
Each face is given as the loop a region for it stores: every segment once, from the face’s first segment.
In a connected part whose segments cross or touch away from a shared point the areas are bounded by pieces of segments, which a loop cannot name. Such a part gives loops of whole segments that cover its areas when filled by winding (the nonzero rule): a closed path that crosses itself gives one loop, the path itself, which fills everything it winds around. These loops may cross themselves and lie over each other. An area that no loop of whole segments winds around is not covered: one enclosed by a path that is not closed, or one a closed path circles as often one way as the other.
findVectorAreasgives the areas themselves.
源码function frontFirst<Layer>(storedOrder: readonly Layer[]): readonly Layer[]The order the layers of one parent are listed in: the front layer first and the back layer last, as Figma does. A parent stores its layers the other way round, back layer first (the order they are drawn in), and that stored order is not changed by the listing.
This one rule holds for every parent: a page, a frame with or without auto layout, a group, an instance and a layer inside one. A mask needs no rule of its own: it is stored before the layers it hides parts of, so it is listed below them.
Everything that lists layers or walks them by keyboard asks here, so the orders cannot disagree: the layers panel’s rows, its Shift-click range, the context menu’s “Select layer” list, Enter, Tab and Shift+Tab on the canvas (
childSelectionTarget,siblingSelectionTarget), and the tree a screen reader hears (createAccessibilitySnapshotV1), whosearia-posinsetcounts from the front layer.
源码function hitVectorPointBox( box: VectorPointBox, point: Point ): VectorPointBoxHit | nullWhat a press at
point(box space) takes hold of: the nearest resize handle within reach, else a rotate zone, which is the ring just outside a corner and outside the box. Null for anywhere else.
源码function insertVectorPoint( network: VectorNetwork, segmentId: VectorSegmentId, t: number, ids: VectorEditIdAllocator ): VectorPointInsertionAdds a point on a segment at position
t(seeVectorSegmentPoint.t) without changing the shape, as Figma’s Pen tool does when it clicks a path in edit mode. A cubic’s new point has its two handles at the same angle.
源码function instanceLayerChildren( document: DesignDocument, id: NodeId ): readonly NodeId[]The resolved children of an instance (its component root’s layers) or of a layer inside one, in paint order; empty for anything else.
源码function instanceLayerParent( document: DesignDocument, id: NodeId ): NodeId | undefinedThe parent of a layer inside an instance: the instance’s own ID for a first-level layer.
undefinedfor a stored ID or one that does not resolve.
源码function instanceLayerPath( document: DesignDocument, id: NodeId ): readonly NodeId[] | undefinedThe virtual IDs from the instance’s first-level layer down to a virtual ID, outermost first. Empty for a stored ID;
undefinedfor a virtual ID that does not resolve.
源码function instanceLayerResolveStats(): InstanceResolveCache["stats"]How many instances and component views this module resolved anew (
misses) and took from its cache (hits). Tests read it to check that a pass over a document resolves each of them once.
源码type InstanceSelectionMode = "instance" | "group"The “Selecting inside instances” preference (components design 5.5).
源码function invertVectorTransform( transform: TransformMatrix ): TransformMatrix | nullInverts every finite, nonsingular affine transform with a representable inverse, or returns null. Vector edit mode uses this one rule wherever it inverts a path transform, so a transform that opens the mode (such as a tiny 1e-12 scale) never fails later in a nudge or a typed X/Y position.
源码function isInSelectionScope( document: DesignDocument, rootId: NodeId, scopeId: NodeId, nodeId: NodeId ): booleanTrue for the scope layer and every layer inside it. A pointer on a canvas that selects within the scope acts only on these: a layer of a container around the scope is not under it, though that container stands for the scope when a rule answers with it (
scopedSelectionTarget).
源码function isInstanceLayer(document: DesignDocument, id: NodeId): booleanTrue when
idis a stored instance or a nested instance layer selected as a whole.
源码function lassoVectorSelection( network: VectorNetwork, before: VectorEditingSelection, contents: VectorLassoContents, mode: VectorLassoMode ): VectorEditingSelectionThe selection after a lasso. “replace” selects just what the lasso holds; “add” (Shift) keeps what was selected before and adds to it; “subtract” (Option or Alt) takes the points the lasso holds out of what was selected before, and with them every selected segment that ends at one of them. Handles and regions selected before an “add” or “subtract” lasso are kept.
源码function listedChildIds( document: DesignDocument, parentId: NodeId ): readonly NodeId[]The layers a parent holds, in listed order (
frontFirst): the children of a stored frame, group or page root, or the resolved layers of an instance or of a layer inside one. Empty for anything else.
源码function marqueeVectorSelection( network: VectorNetwork, before: VectorEditingSelection, insideVertexIds: readonly VectorVertexId[], additive: boolean ): VectorEditingSelectionThe selection after a marquee: the anchors inside it, added to the anchors selected before the drag when Shift is held. Handles, segments and regions selected before an additive marquee are kept.
源码function mergeDeletedFaceRegions( before: VectorNetwork, after: VectorNetwork ): VectorNetworkKeeps a fill over faces that a delete has merged. Deleting a segment that two faces share drops the regions of both, since each used the segment; the face they become gets one region here:
- with the fills of the largest of the merged faces, when that one had a region (also when that region was emptied: the merged face is then empty);
- otherwise with the fills of the largest merged face whose region was filled;
- and none when no merged face had a region, or only emptied ones beside a larger face without one.
The region keeps the ID and the place in the order of the one it follows.
beforeis the network just before the delete removed points and segments,afterthe one after it. Every regionbeforehas andafterlacks counts as dropped by that removal, so a region the user deleted on purpose must be gone frombeforetoo, or it could come back over the merged face.
源码function nearestPointOnVectorSegment( network: VectorNetwork, segmentId: VectorSegmentId, target: Point, distanceSpace?: TransformMatrix ): VectorSegmentPointThe point on a segment nearest to
target, in network coordinates.“Nearest” is measured in network units unless
distanceSpaceis given: a matrix from network coordinates to the space to measure in. Pass the path’s local-to-screen matrix to find the point nearest on screen, which is a different point when the path is stretched unevenly or skewed.
源码function nudgeVectorVertices( network: VectorNetwork, vertexIds: readonly VectorVertexId[], localDelta: Point ): VectorNetworkMoves the given anchors by one local-space offset in one network edit.
源码function paintVectorTarget( network: VectorNetwork, target: VectorPaintTarget, regionId: VectorRegionId, layerShowsFill: boolean ): VectorPaintResultA Paint click on a target, decided by what is on screen. A region never gets a colour of its own from Paint: it either takes the layer’s fills (
fillsomitted) or has none (fills: []), so the Fill panel, which edits the layer’s fills, always changes what is painted.- A target that shows a fill loses it:
fills: []. Fills of its own (an imported SVG, an older document) are dropped with it; undo brings them back, Paint does not. - A target that shows none is filled: it takes the layer’s fills. That holds for a region emptied before and for one whose own fills do not show, which are dropped. A loop without a region gets its region first, named
regionId: the same region a shape turned into a path stores for its outline (nonzero, one loop, each segment once), so later edits treat it as they treat any stored region. - When the layer shows no fill (
layerShowsFillfalse, seevectorFillsShow), filling asks for one on the layer (layerNeedsFill). Every other region that took the layer’s fills, and so showed nothing, is set tofills: [], so the click changes nothing else on screen.
Only the layer’s fills count for
layerShowsFill, not its opacity or visibility. On a hidden layer, or one at 0% opacity, nothing is seen whatever Paint does; a click there still switches the stored fill as it would on a layer that shows, and the result is seen once the layer is shown again.- A target that shows a fill loses it:
源码const PEN_ANGLE_STEP_DEGREES: 45Shift holds the Pen to multiples of this angle, as in Figma.
源码function penArmedVertexId( network: VectorNetwork, selection: VectorEditingSelection ): VectorVertexId | nullThe point the Pen draws from, or null for none. It is the primary component when that is a point, however many other components are selected with it; otherwise the only selected point, whatever else (a segment, a handle, a region) is selected or primary. A point the network does not have is never armed. Every Pen path asks here, so a click on empty canvas, on a point and on a segment, the cursor badge and Escape all agree on the source.
源码function pendingPenOutgoingHandle( network: VectorNetwork, selection: VectorEditingSelection, handle: PenOutgoingHandle | null ): PenOutgoingHandle | nullThe remembered outgoing handle while it still applies: its point is the one the Pen draws from (
penArmedVertexId). Null once another point is armed, the path in progress is ended, or the point is gone (for example by undo).
源码function pendingVectorSubPath( network: VectorNetwork, startedVertexId: VectorVertexId | null ): VectorVertexId | nullThe started sub-path that still waits for its first segment:
startedVertexIdwhile the network has that point with no segment at it, otherwise null. A caller that remembers which point a Pen click started passes every network it comes to hold through this, so the point stops counting as a started sub-path once it is drawn from or removed, and never counts again after that.
源码interface PenHandleOffsetA curve handle as an offset from its point.
readonly dx: number源码readonly dy: number源码
源码interface PenOutgoingHandle extends PenHandleOffsetThe handle a Pen drag pulled out of a point for the segment that is drawn from it next. A point stores no handle of its own (handles belong to segments), so the handle is remembered here until that segment exists.
readonly vertexId: VectorVertexId源码readonly mirrorHandleId: VectorHandleId | null源码The handle of the segment that arrived at the point in the same drag: the exact mirror of this one. Null for the first point of a sub-path, which no segment arrives at.
源码interface PenPendingHandle extends PenHandleOffsetA handle the canvas draws although no segment owns it yet: the one a Pen drag is pulling out of a point, or the one it left there for the next segment.
mirroredalso draws its exact mirror about the point, for a point no segment touches (the first point of a sub-path); where a segment arrives in the same drag, that segment’s own handle is the mirror.readonly vertexId: VectorVertexId源码readonly mirrored: boolean源码
源码interface PenSegmentShapereadonly id: VectorSegmentId源码readonly start: VectorVertexId源码readonly end: VectorVertexId源码readonly startHandleId: VectorHandleId源码readonly endHandleId: VectorHandleId源码readonly outgoing: PenOutgoingHandle | null源码The handle remembered at the start point, or null when the point has none.
readonly drag: PenHandleOffset | null源码How far the pointer was dragged from the end point, or null for a plain click. The pointer holds the handle that leaves the end point, so the segment arrives along its mirror.
源码function placeVectorVerticesOnAxis( network: VectorNetwork, localToParent: TransformMatrix, vertexIds: readonly VectorVertexId[], axis: "x" | "y", value: number ): VectorNetworkPlaces every given anchor at
valueon one parent-space axis, keeping its other coordinate, as typing into the X or Y field does with points selected.
源码function pointInVectorLasso(outline: readonly Point[], point: Point): booleanWhether
pointlies inside the closed outline throughoutline(the last point joins the first). A point on the outline counts as inside. An outline that crosses itself encloses everything it winds around (the nonzero rule), so no pocket of a looping drag is left out.
源码function pointInVectorPolygons( polygons: readonly (readonly Point[])[], windingRule: VectorRegion["windingRule"], point: Point ): booleanWhether a point is inside polygons filled with the given winding rule.
源码function prepareVectorSegmentBend( network: VectorNetwork, segmentId: VectorSegmentId, t: number, ids: VectorEditIdAllocator ): VectorPreparedSegmentBendTurns the segment under the pointer into a cubic without changing the shape: a line gets handles a third of the way along, and an arc becomes cubic pieces, of which the one at
tis kept with its own position.
源码function prepareVectorVertexHandles( network: VectorNetwork, vertexId: VectorVertexId, ids: VectorEditIdAllocator ): VectorPreparedVertexTurns the segments at a vertex into cubics without changing the shape: a line gets two zero handles, and an arc becomes its cubic pieces.
源码const reboundVectorScenarioViewport: ViewportState
源码function resetRichTextEditStats(): void
源码function resolvedComponentLayersOf( document: DesignDocument, componentId: ComponentId ): ReadonlyMap<NodeId, ResolvedLayer> | undefinedThe layers of a component’s own view (
resolveComponent: the component with every property at its default), by their stored IDs.undefinedwhen the component cannot be resolved (a nesting cycle, a missing nested component); it is drawn from its stored nodes then.The component is resolved once and its layers are listed once, however many of its layers are asked for: the resolved view comes from this module’s cache, which gives the same view again for a later document whose component, theme and assets are unchanged.
源码function resolvedInstanceOf( document: DesignDocument, instanceId: NodeId ): ResolvedInstance | undefinedThe resolved tree of an instance, or
undefinedwheninstanceIdis not an instance or fails to resolve.
源码function resolvedLayerOf( document: DesignDocument, id: NodeId ): ResolvedLayer | undefinedThe resolved layer an ID names: the root layer for an instance ID, the layer for a virtual ID,
undefinedfor any other stored ID or an ID that does not resolve.
源码const richTextEditStats: { runTextConcats: number; formattingKeySorts: number }
源码function scopedSelectionTarget( document: DesignDocument, rootId: NodeId, scopeId: NodeId | null, nodeId: NodeId | null ): NodeId | nullWhat a selection rule’s answer becomes on a canvas that selects only within one layer, the scope: the isolation split’s page pane selects the opened instance and the layers inside it (components design 5.5), at any depth of nesting. The rules above answer from the page root, so their answer is brought into the scope here:
- the scope layer, or a layer inside it, is itself;
- a container the scope layer is inside (the instance or frame around a nested instance) stands for the scope layer, as a click on a layer of a closed group selects the group: the scope is as far out as it reaches;
- any other layer is outside the scope, and the answer is
null.
With no scope (
null) every answer is itself.
源码function scopedSelectionTargets( document: DesignDocument, rootId: NodeId, scopeId: NodeId | null, nodeIds: readonly NodeId[] ): readonly NodeId[]scopedSelectionTargetfor several answers: each layer once, in order, the ones outside the scope left out.
源码function selectAllVectorVertices(network: VectorNetwork): VectorEditingSelectionSelects every anchor of the network, as Cmd+A does in Figma’s vector edit mode.
源码function setVectorVertexMirroring( network: VectorNetwork, vertexIds: readonly VectorVertexId[], mirroring: VectorMirroring, ids: VectorEditIdAllocator ): VectorNetworkSets the mirroring of the given points. A mirrored mode snaps at once: the longer handle stays and the other turns to face it (and, mirroring length, takes its length). A point with no handles yet becomes smooth. Points that cannot mirror are skipped.
源码function smoothVectorVertex( network: VectorNetwork, vertexId: VectorVertexId, ids: VectorEditIdAllocator, mode: VectorTangentConstraint["mode"] = "angle-and-length" ): VectorNetworkMakes a corner point smooth: its two handles lie along the line between its two neighbours, each a third of the shorter neighbouring segment long, and mirror each other with
mode. Only a point joining exactly two segment ends can be smooth; any other is returned unchanged.
源码function snapPenOffsetToAngle(offset: PenHandleOffset): PenHandleOffsetSnaps an offset to the nearest of the eight directions that are multiples of 45 degrees: the result is the point of that direction’s line nearest to the offset, so it stays as close to the pointer as the direction allows. Horizontal and vertical results have an exact zero in the other axis, and diagonal results have equal lengths in both. A zero offset stays zero.
The offset is in the axes the angle is measured in. For the Pen these are the canvas axes (
snapPenPointToAngle), whatever the layer’s own rotation.
源码function snapPenPointToAngle( anchor: Point, point: Point, localToCanvas: TransformMatrix ): PointMoves
pointso that the line fromanchorto it runs at a multiple of 45 degrees in canvas axes. Both points are in the path’s local units;localToCanvasmaps those to the canvas (the document or the screen: the two differ only by zoom and scroll, which keep angles). A rotated, flipped or nested layer is therefore snapped as the user sees it, not along its own axes.The transform is inverted by the rule vector edit mode opens a path with (
invertVectorTransform), so every transform the mode accepts snaps here, however small or large its scale. ThrowsRangeErrorfor a transform that rule refuses, which opens no vector edit mode.pointis returned as it is when the snapped place cannot be stored as numbers: the offset is too large or too small on the canvas to have a direction, or the result leaves the number range. This is the rule a nudge or a typed position follows on such a path (updateFiniteVertices).
源码function splitCubic(controls: Cubic, t: number): readonly [Cubic, Cubic]Splits a cubic at
twith de Casteljau’s construction; both halves trace it exactly.
源码const standardAccessibilityEditorDriverCodeV1: "const shared = 1;"
源码const standardAccessibilityEditorDriverIdsV1: Readonly< { document: DocumentId; replacementDocument: DocumentId; page: PageId; root: NodeId; text: NodeId; code: NodeId; shape: NodeId; } >共享的
EditorDriver无障碍验收场景所使用的稳定 ID。
源码const standardAccessibilityEditorDriverTextV1: "Shared accessibility text"
源码const standardAccessibilityScenarioIdsV1: Readonly< { frame: NodeId; text: NodeId; code: NodeId; image: NodeId; shape: NodeId; hidden: NodeId; clipped: NodeId; transparent: NodeId; lockedGroup: NodeId; lockedChild: NodeId; imageAsset: AssetId; } >
源码type StandardEditorScenarioDocument = | "blank" | "text-blank" | "rectangle" | "nested" | "snapping" | "aspect-resize" | "rotation" | "connector" | "group-scale" | "auto-layout" | "hit-order" | "hit-policy" | "rich-text"
源码const standardEditorScenarioIds: { readonly document: DocumentId; readonly page: PageId; readonly root: NodeId; readonly rectangle: NodeId; readonly target: NodeId; readonly container: NodeId; readonly child: NodeId; readonly connector: NodeId; readonly autoLayout: NodeId; readonly autoFirst: NodeId; readonly autoSecond: NodeId; readonly back: NodeId; readonly front: NodeId; readonly locked: NodeId; readonly hidden: NodeId; readonly text: NodeId; }
源码const standardEditorScenarioViewport: ViewportStateSVG 驱动所支持的固定 DPR 子集。
源码const standardRichTextFontAssetIds: { readonly latin: AssetId; readonly hebrew: AssetId; readonly japanese: AssetId; readonly korean: AssetId; readonly emoji: AssetId; }
源码const standardRichTextSamples: { readonly emojiFamily: "👨👩👧👦"; readonly combiningAcute: "é"; readonly deadKeyComposed: "é"; readonly hebrew: "אבג"; readonly bidi: "abc אבג"; readonly japanese: "日本語"; readonly korean: "한글"; readonly listMarker: "・"; }
源码type StandardVectorBooleanScenarioDocument = | "editable" | "explicit-primary-fill" | "three-paths" | "non-path" | "locked-secondary" | "disjoint" | "text-editing"
源码const standardVectorBooleanScenarioIds: { readonly primary: NodeId; readonly secondary: NodeId; readonly third: NodeId; readonly nonPath: NodeId; }
源码const standardVectorBooleanScenarioViewport: ViewportState
源码type StandardVectorScenarioDocument = "editable" | "covered"
源码const standardVectorScenarioIds: { readonly pathA: NodeId; readonly pathB: NodeId; readonly cover: NodeId; readonly a0: VectorVertexId; readonly a1: VectorVertexId; readonly a2: VectorVertexId; readonly a3: VectorVertexId; readonly aStartHandle: VectorHandleId; readonly aEndHandle: VectorHandleId; readonly a0a1: VectorSegmentId; readonly a1a2: VectorSegmentId; readonly a2a3: VectorSegmentId; readonly a3a0: VectorSegmentId; readonly aRegion: VectorRegionId; readonly b0: VectorVertexId; readonly b1: VectorVertexId; readonly b2: VectorVertexId; readonly b0b1: VectorSegmentId; readonly b1b2: VectorSegmentId; readonly b2b0: VectorSegmentId; readonly bRegion: VectorRegionId; }
源码const standardVectorScenarioViewport: ViewportState
源码function startCountingVectorWork(): voidStarts a count of comparisons at zero. For tests only.
源码function startVectorSubPath( network: VectorNetwork, position: Point, vertexId: VectorVertexId ): VectorNetworkStarts a new, separate sub-path in the network: one point at
positionthat no segment touches yet. This is what a Pen click on empty canvas does in vector edit mode when no point is armed to draw from. The caller arms the new point, so the next click draws the first segment of the sub-path, which stays part of the same layer.
源码function stopCountingVectorWork(): numberEnds the count a test started and returns it; the checks count nothing again. For tests only.
源码function storeClosedLoopRegions( before: VectorNetwork, after: VectorNetwork, regionId: () => VectorRegionId ): VectorNetworkStores regions for the faces (
findVectorFaces) an edit has just made: the faces ofafterthatbeforedid not have.- A face in space that was open before, or lying apart inside a face that is still there, gets a new region that takes the layer’s fills, so an enclosed area fills as soon as the layer has a fill, as in Figma, and on a layer without fills it paints nothing.
- Faces that divide a face
beforehad take over that face’s region: the region is replaced, at its place in the order, by one region per new face with the same fills (its own, the layer’s, or none) and winding rule. The first keeps the region’s ID. When the divided face had no region nothing is stored, and Paint offers the new faces.
Faces that were there before the edit with no region (paths saved before closing made regions) are left as they are, and so is every region that is not stored for a single face (several loops, or an open chain closed for filling).
In a part whose segments cross, a loop can fill several areas and lie over other loops, so its name alone does not say that it is new. There, an edit never changes what an area showed before it:
- A loop gets a new region only when no area it fills could be filled before: none lay in a face
beforehad, and none is in a stored region. A loop that reaches both a new area and one the user already had (a long diagonal across a ladder of cells, a segment across a filled loop) gets none, and neither does a second new loop that lies over the first. Paint offers what is left without a region (findUnstoredVectorFaces). - Loops take over a region only when together they fill exactly what the region filled, each area once. Otherwise the region stays on its loop, which still fills what it filled.
源码function toggleVectorRegionFill( network: VectorNetwork, regionId: VectorRegionId ): VectorNetworkSwitches a region between filled and not filled. A filled region (one that takes the layer’s fills, or has its own) becomes
fills: []; a region that is not filled goes back to taking the layer’s fills.
源码function toggleVectorVertexSmooth( network: VectorNetwork, vertexId: VectorVertexId, ids: VectorEditIdAllocator ): VectorNetworkA Bend click on a point: a point with handles becomes a corner, a corner becomes smooth.
源码function transformVector(transform: TransformMatrix, vector: Point): PointMaps a direction through the linear part of an affine transform (no translation).
源码function transformVectorVertices( network: VectorNetwork, vertexIds: readonly VectorVertexId[], matrix: TransformMatrix ): VectorNetworkMoves the given points through
matrix(network coordinates) and carries the rest of the geometry that lives in the same coordinates:- A Bézier handle attached to a moved point is turned and scaled by the matrix’s linear part, so the curve keeps its shape relative to its point. A handle pair that mirrored before still mirrors: a linear map keeps opposite offsets opposite and equal lengths equal.
- An elliptical arc with both end points moved is mapped exactly (see
transformEllipticalArc). With one end point moved it keeps its radii, rotation and flags and is drawn again between its end points, which is what dragging or nudging that point does. - A point’s corner radius stays as it is, as it does when the whole layer is resized (
scaleVectorNetwork).
Returns the network unchanged for the identity, and when a result would leave the representable number range.
源码const VECTOR_HIT_TOLERANCE_CSS_PX: 6How far, in CSS pixels, a point, handle or segment of the open path reaches. Every hit test against the open path uses it, so hover and press agree.
源码const VECTOR_POINT_BOX_HANDLE_REACH: 10How far from a handle’s centre a press still takes it, in box units (CSS pixels). It is more than the 6 pixels a point is grabbed within, so a handle with a point right under it (a corner of the box often is one of the selected points) can still be taken from just beside the point.
源码const VECTOR_POINT_BOX_ROTATE_REACH: 26How far outside a corner a press still rotates, in box units (CSS pixels).
源码interface VectorArcConversionThe result of turning an elliptical arc into cubic pieces.
readonly network: VectorNetwork源码readonly segmentIds: readonly VectorSegmentId[]源码The pieces in order from the arc’s start to its end; the first keeps the arc’s ID.
源码interface VectorAreaOne area a network encloses, with every crossing treated as a corner.
readonly outline: readonly Point[]源码The boundary as a closed polygon in network coordinates, curves flattened.
readonly area: number源码
源码type VectorBendGesture = & { readonly threshold: number; readonly moved: boolean; readonly ids: VectorEditIdAllocator; } & ( | { readonly kind: "vertex"; readonly vertexId: VectorVertexId; readonly prepared: VectorPreparedVertex; readonly heldEnd: number | null; } | { readonly kind: "segment"; readonly prepared: VectorPreparedSegmentBend; })A Bend drag from a point or on a segment. Until the pointer has moved
threshold(network units, or the gesture’sdistanceSpace) it is a click: on a point, that toggles the point between corner and smooth when the press ends.
源码function vectorBendHeldEnd( prepared: VectorPreparedVertex, vertexId: VectorVertexId, drag: Point, distanceSpace?: TransformMatrix ): numberWhich segment end a drag from a point holds: the one whose segment leads most nearly the way the pointer went. The other end’s handle mirrors it.
Both directions are compared as
distanceSpacedraws them (seevectorDistance): pass the path’s local-to-screen matrix so the choice matches what the user sees when the path is stretched unevenly or skewed.
源码interface VectorCrossingOne place where two segments of a network meet away from a point they share.
readonly point: Point源码Where, in network coordinates.
readonly first: { readonly segmentId: VectorSegment["id"]; readonly at: number }源码The two segments and how far along each the place is: 0 at the segment’s start, 1 at its end. A segment that crosses itself is named twice.
readonly second: { readonly segmentId: VectorSegment["id"]; readonly at: number; }源码
源码interface VectorCutThe cut network and the points left where the cut was made.
readonly network: VectorNetwork源码readonly vertexIds: readonly VectorVertexId[]源码
源码type VectorCutLineCrossing = | { readonly kind: "segment"; readonly segmentId: VectorSegmentId; readonly t: number; } | { readonly kind: "vertex"; readonly vertexId: VectorVertexId }One place the cut line crosses the network.
源码function vectorCutLineCrossings( network: VectorNetwork, from: Point, to: Point ): readonly VectorCutLineCrossing[]Every place the straight line from
fromtoto(network coordinates) crosses the network: positions inside segments (seeVectorSegmentPoint.t), and the points it passes through, each listed once.
源码interface VectorEditIdAllocatorSupplies fresh, unused IDs for the parts an edit creates.
readonly vertexId: () => VectorVertexId源码readonly segmentId: () => VectorSegmentId源码readonly handleId: () => VectorHandleId源码
源码function vectorEditTargetVertexIds( network: VectorNetwork, selection: VectorEditingSelection ): readonly VectorVertexId[]Anchors moved by a nudge or a position edit: selected anchors and the ends of selected segments.
源码interface VectorEditToolContextreadonly tool: "pen" | "bend" | "cut"源码readonly ids: VectorEditIdAllocator源码readonly regionId?: () => VectorRegionId源码Names a region the Pen stores when a click connects the path in progress to a segment and that encloses or divides an area. Without it such a click only adds the point.
源码function vectorFillsShow(fills: readonly Paint[] | undefined): booleanWhether a list of fills would put pixels on screen: one of its paints shows (
vectorPaintShows). The one test behind every Paint decision: a region’s own fills, the layer’s fills, the cursor and the hover stripes.
源码function vectorHatchLines( polygons: readonly (readonly Point[])[], windingRule: VectorRegion["windingRule"], spacing: number, maximumLines = 400 ): readonly (readonly [Point, Point])[]Diagonal stripes over the inside of polygons, for marking a hovered region: straight pieces running up to the right,
spacingapart, clipped to the area the winding rule fills. In whatever space the polygons are in (pass screen coordinates for stripes that are even on screen). When the area would take more thanmaximumLinesstripes they are spread wider.
源码type VectorHealIdAllocator = () => VectorHealSegmentIdsSupplies fresh, unused IDs for each edge the heal creates.
源码interface VectorHealSegmentIdsDelete and heal for vector networks, after Figma’s “Delete and Heal” (https://www.figma.com/blog/delete-and-heal-for-vector-networks/): removing an anchor joins its neighbours instead of leaving a gap.
- An anchor with an odd number of edges loses all of them, as a plain delete.
- An anchor with an even number of edges has them sorted by angle, and each edge is paired with its opposite; every pair becomes one new edge between the two far ends. A pair whose far ends are the same anchor is removed.
- The new edge’s curve is fitted to the two old edges with fixed end tangents (one pass of Schneider’s least-squares fit), so the shape keeps its course. Elliptical arcs are fitted against their true curve, as cubic pieces.
- A kept outer handle whose length the fit changed loses the length part of an
angle-and-lengthconstraint, as splitting a segment does. - Fill loops that ran through the anchor along a healed pair are rewired to the new edge; loops that ran through any other way are removed.
readonly segmentId: VectorSegmentId源码readonly startHandleId: VectorHandleId源码readonly endHandleId: VectorHandleId源码
源码function vectorInteractionPointBox( state: VectorInteractionState ): VectorPointBox | nullThe box around the selected points, upright on screen, or null when fewer than two points are selected or they share one place.
源码function vectorLassoContents( network: VectorNetwork, localToScreen: TransformMatrix, outline: readonly Point[] ): VectorLassoContentsThe points inside a lasso drawn on screen, and the segments whose two end points are both inside.
localToScreenmaps the network to the space the outline was drawn in.
源码interface VectorLassoContentsThe points and segments a lasso outline takes in.
readonly vertexIds: readonly VectorVertexId[]源码readonly segmentIds: readonly VectorSegmentId[]源码
源码type VectorLassoMode = "replace" | "add" | "subtract"How a lasso changes the selection that was there before the drag.
源码type VectorMirroring = "none" | VectorTangentConstraint["mode"]Figma’s handle mirroring setting for a point (“No mirroring”, “Mirror angle”, “Mirror angle and length”;
VectorVertex.handleMirroringin its plugin API). Our model keeps it as a tangent constraint pairing the two handles at the point, so the setting reads and writes that pair.
源码interface VectorPaintResultWhat a Paint click changes: the network, and whether the layer itself must be given a fill.
readonly network: VectorNetwork源码readonly layerNeedsFill: boolean源码The click fills a target on a layer that shows no fill. The target takes the layer’s fills, so the caller adds a fill that shows to the layer’s own fills, in the same undo step as the network.
源码function vectorPaintShows(paint: Paint): booleanWhether one paint would put pixels on screen: it is not hidden, its opacity is above zero, and what it paints is not fully transparent.
- A solid paint needs a colour with some alpha.
- A gradient needs at least one stop with some alpha.
- An image paint counts whenever it is not hidden and has opacity. Its pixels are not looked at, and an asset that is missing is not a paint that shows nothing: the renderer refuses the document (
MEDIA_ASSET_REQUIRED).
Blend modes are not looked at: none of them paints nothing by itself; what one shows depends on what lies under it. The layer’s own opacity and visibility are not looked at either, see
VectorPaintFillRule.
源码type VectorPaintTarget = | { readonly kind: "region"; readonly region: VectorRegion } | { readonly kind: "loop"; readonly loop: VectorRegionLoop }What a Paint click acts on: a stored region, or a face (
findVectorFaces) that has none yet.
源码function vectorPaintTargetAtPoint( network: VectorNetwork, point: Point ): VectorPaintTarget | nullWhat a Paint click at
point(network coordinates) acts on, or null when the point is in no paintable area. Of several areas holding the point, the smallest is taken, so a loop inside another is reached by pointing inside it; of equal ones, the frontmost.
源码function vectorPaintTargetKey(target: VectorPaintTarget): stringA name for a paint target that lasts while the network keeps its IDs.
源码function vectorPaintTargets( network: VectorNetwork ): readonly VectorPaintTarget[]Every paint target of a network: its regions from back to front, then its faces without a region.
源码function vectorPaintTargetShape( target: VectorPaintTarget ): Pick<VectorRegion, "loops" | "windingRule">The loops and winding rule a paint target fills with.
源码function vectorPaintTargetShowsFill( target: VectorPaintTarget, layerShowsFill: boolean ): booleanWhether a paint target shows a fill on screen now. A region that takes the layer’s fills shows one only when the layer has one; a region with fills of its own when one of them shows (
vectorFillsShow); a loop without a region never.
源码function vectorPointBox( network: VectorNetwork, vertexIds: readonly VectorVertexId[], localToBox: TransformMatrix ): VectorPointBox | nullThe box around the given points, or null when fewer than two of them exist or they all sit at one place. A box with no width offers only its top and bottom handles, and one with no height only its left and right handles; either still rotates from its two ends.
源码interface VectorPointBoxreadonly vertexIds: readonly VectorVertexId[]源码The selected points the box surrounds, in network order.
readonly bounds: Rect源码The box in box space. Its width or its height may be zero, not both.
readonly resizeHandles: readonly { readonly handle: VectorPointBoxHandle; readonly center: Point; }[]源码The handles on offer: all eight, or the two that scale a box with no width or no height.
readonly rotateCorners: readonly { readonly corner: VectorPointBoxCorner; readonly center: Point; }[]源码The corners with a rotate zone outside them: four, or the two ends of a flat box.
源码type VectorPointBoxCorner = "nw" | "ne" | "se" | "sw"A corner of the box that points can be rotated from.
源码interface VectorPointBoxGestureA drag of a handle or rotate zone of the box around the selected points. The box is fixed as the press found it;
transformis what the drag applies to it so far, in the box’s own space.readonly box: VectorPointBox源码readonly hit: VectorPointBoxHit源码readonly localToBox: TransformMatrix源码From network coordinates to the box’s space (the screen), and back.
readonly boxToLocal: TransformMatrix源码readonly modifiers: VectorPointTransformModifiers源码readonly transform: TransformMatrix源码
源码type VectorPointBoxHandle = "nw" | "n" | "ne" | "e" | "se" | "s" | "sw" | "w"A resize handle, named by the compass side of the box it sits on.
源码type VectorPointBoxHit = | { readonly kind: "resize"; readonly handle: VectorPointBoxHandle } | { readonly kind: "rotate"; readonly corner: VectorPointBoxCorner }
源码function vectorPointBoxHitDirection( box: VectorPointBox, hit: VectorPointBoxHit ): numberThe direction a handle’s cursor runs along (resize) or faces (rotate), in degrees clockwise from the positive x axis of box space.
源码function vectorPointBoxLocalTransform( boxTransform: TransformMatrix, localToBox: TransformMatrix, boxToLocal: TransformMatrix ): TransformMatrixThe network-space matrix for a box-space one: into the box’s space, through the matrix, and back. An unchanged box gives exactly the identity.
源码function vectorPointBoxPress( state: VectorInteractionState, screenPoint: Point, part: VectorComponentHit["part"] | null ): VectorPointBoxPress | nullWhat a press at
screenPointtakes of the box around the selected points, given the part of the path under the press (part, null for none).Points and Bézier handles stay grabbable: a press within reach of one takes it, not the box. A resize handle wins over a segment under it. A rotate zone, which lies outside the box, gives way to any part of the path.
源码interface VectorPointBoxPressA press on the box around the selected points: the box and the part pressed.
readonly box: VectorPointBox源码readonly hit: VectorPointBoxHit源码
源码function vectorPointBoxTransform( box: Pick<VectorPointBox, "bounds">, hit: VectorPointBoxHit, start: Point, current: Point, modifiers: VectorPointTransformModifiers ): TransformMatrixThe box-space matrix a drag of
hitfromstarttocurrentapplies.A resize scales about the opposite handle, or about the box’s centre with Alt. With Shift it keeps the proportions: a corner uses the larger of its two factors for both axes, and an edge scales the other axis by the same factor about that axis’s middle. An axis the box has no extent on is never scaled. A rotate turns about the box’s centre by the angle the pointer has swept around it, in 15 degree steps with Shift.
源码interface VectorPointInsertionWhere a point went in: the vertex now at that place.
readonly network: VectorNetwork源码readonly vertexId: VectorVertexId源码
源码interface VectorPointTransformModifiersThe modifier keys a point box drag reads.
readonly shift: boolean源码readonly alt: boolean源码
源码interface VectorPreparedSegmentBendA segment ready to bend: a cubic, and where on it the pointer took hold.
readonly network: VectorNetwork源码readonly segmentId: VectorSegmentId源码readonly t: number源码
源码interface VectorPreparedVertexA network whose segments at a vertex are all cubics, ready for handle edits.
readonly network: VectorNetwork源码readonly ends: readonly VectorVertexHandleEnd[]源码
源码function vectorRegionAtPoint( network: VectorNetwork, point: Point ): VectorRegion | nullThe region whose area holds
point(network coordinates): the frontmost one, since regions paint from back to front. Null outside every region.
源码function vectorRegionIsFilled(region: VectorRegion): booleanWhether a region paints: it takes the layer’s fills, or has fills of its own.
源码function vectorRegionOutlines( network: VectorNetwork, region: Pick<VectorRegion, "loops"> ): readonly (readonly Point[])[]A region’s loops as closed polygons in network coordinates, with curves flattened. A loop that fills as an open chain closes straight back to its start, as the renderer fills it.
源码function vectorSegmentCubics( network: VectorNetwork, segment: VectorSegment ): readonly Cubic[]The segment as cubic pieces from its start to its end: one piece for a line or cubic, up to four for an elliptical arc (one quarter turn each).
源码interface VectorSegmentPointWhere on a segment a point is nearest.
readonly t: number源码Position along the segment, 0 at its start and 1 at its end. For an arc it runs evenly over its cubic pieces: piece
iofncovers[i / n, (i + 1) / n].readonly point: Point源码readonly distance: number源码In network units, or in the units of the space the search measured in.
源码interface VectorVertexHandleEndOne segment end at a vertex, and where its segment leads.
readonly segmentId: VectorSegmentId源码readonly endpoint: "startHandle" | "endHandle"源码readonly handleId: VectorHandleId源码readonly far: VectorVertexId源码The vertex at the other end of the segment.
源码function vectorVertexHasHandles( network: VectorNetwork, vertexId: VectorVertexId ): booleanTrue when any segment end at the vertex has a handle of non-zero length.
源码function vectorVertexIdsInScreenRect( network: VectorNetwork, localToScreen: TransformMatrix, rect: Rect ): readonly VectorVertexId[]The anchors whose screen position lies inside
rect(edges included).
源码function vectorVertexIsUnconnected( network: VectorNetwork, vertexId: VectorVertexId ): booleanWhether no segment starts or ends at the point. False for a point the network does not have.
源码function vectorVertexMirroring( network: VectorNetwork, vertexId: VectorVertexId ): VectorMirroring | nullA point’s mirroring, or null when it has none to set: only a point joining exactly two segment ends has a pair of handles to mirror.
源码function vectorVertexParentPositions( network: VectorNetwork, localToParent: TransformMatrix, vertexIds: readonly VectorVertexId[] ): readonly Point[]The parent-space positions of the given anchors, in network order.
源码function vectorVertexSelection( network: VectorNetwork, vertexIds: Iterable<VectorVertexId>, primary?: VectorVertexId ): VectorEditingSelectionA selection of anchors only, in network order, with the last one primary.
@taco-slides/render-core TypeScript
270 个导出中已记录 196 个 · 大纲
@taco-slides/render-core 是 Kimi Design 渲染器的 TypeScript 部分。它把 DesignDocument 的一个页面转换为保留场景:由渲染器在帧与帧之间保留的一组节点、Paint 和字体。首个页面之后,每次文档改动都会变成一个小的变更批次,只更新发生变化的节点。
渲染器本身是基于 Skia 的 C++ 代码,编译为 WebAssembly(Wasm)。TypeScript 与 C++ 共享两份契约。第一份是变更批次的小端序字节格式,由 RenderChangeBatchEncoder 写入,并在 PROTOCOL.md 中描述。第二份是稳定的 C ABI(render_core.h 中的 taco_render_* 函数),由 PortableWasmRenderCoreSession 调用。该会话把每个输入复制到 Wasm 内存中,调用一个 C 函数,严格检查结果并把它复制回来,因此不会有 Wasm 内存泄露给调用方。
编辑器并不直接使用该会话。它与 InteractiveRenderSessionCoordinator 通信;后者持有文档,用 ActivePageCompilerSession 编译当前页面,并驱动一个由 Web 应用基于 WebGPU 实现的保留后端。
标记为 Native 的条目链接到它们最终调用的 C 函数,C++ 条目也会反向链接回来。类型或常量上的 Native 链接表示 C 端读写相同的字节或值,而不是一次调用。
当前版本
TypeScript 与 C++ 共享的字节格式,以及两端当前使用的版本号,在构建本页时从源码读取。如果 TypeScript 与 C++ 的值不一致,构建会失败。
| 场景 wire 格式 | 24 | RENDER_CORE_WIRE_VERSION 与 TACO_RENDER_WIRE_VERSION;参见wire 格式历史 |
|---|---|---|
| 矢量网络 wire 格式 | 5 | RENDER_CORE_VECTOR_NETWORK_WIRE_VERSION 与 TACO_RENDER_VECTOR_NETWORK_WIRE_VERSION |
| 画布叠加层字节布局 | 4 | encodeCanvasOverlay 写入的版本,由 taco_render_session_set_canvas_overlay 读取 |
交互会话
InteractiveRenderSessionCoordinator 是编辑器眼中的渲染器。它保存一份文档和一个当前页面,逐个执行改动,并针对最近一次提交的场景回答几何、命中和文本查询。底层工作交给 InteractiveRetainedBackend 完成。对于渲染器通过另一个节点绘制的节点(例如作为文本节点绘制的代码块),其上的文本编辑叠加层(光标、选区和输入法组合)绘制在那个节点上,因此代码块可以像文本一样就地编辑。
源码class InteractiveRenderSessionCoordinator implements InteractiveRenderSession与后端无关的所有者,持有一个规范文档和一个保留的活动页面。变更按顺序串行执行;同步查询只能观察到已提交的状态。
编辑器通过
InteractiveRenderSession接口与此类交互。它用ActivePageCompilerSession编译活动页面,把变更批次发送给InteractiveRetainedBackend,并将渲染器结果映射回文档节点 ID。变更方法(
loadDocument、applyDocumentUpdate、setActivePage、setViewport、setOverlays、renderFrame)按调用顺序逐个执行。变更失败时,之前的已提交状态保持不变。有变更待处理时,同步查询会抛出InteractiveRenderSessionBusyError;请先 awaitwhenQueryable。调用dispose之后,查询和变更都会抛出InteractiveRenderSessionDisposedError。new (options: InteractiveRenderSessionCoordinatorOptions)源码创建一个尚未加载文档的协调器。
async whenQueryable(): Promise<void>源码等待排队中的变更以及任何后端特有的同步查询屏障完成。
async exportDocument( document: DesignDocument, pageId: PageId, options: RenderDocumentExportOptions ): Promise<RenderExportResult>源码使用此协调器已持有的资源,对
document进行冷编译,并导出一个页面或其中的一个节点。请传入渲染器文档本身,不要包含外围的编辑器工作区。视频节点会被排除:一次性的导出会话没有解码后的视频帧。async outlineDocumentStrokes( document: DesignDocument, pageId: PageId, strokes: readonly StrokeOutlineRequest[], budget?: StrokeOutlineBudget, now: () => number = () => performance.now() ): Promise<readonly StrokeOutlineResult[]>源码Outlines strokes of layers on one page of a document: each requested stroke as a vector network of the area it paints, in its node’s local coordinates (see
RenderStrokeOutlineSnapshot). The page is compiled apart from the live scene with the resources this coordinator already holds and outlined in a throwaway session, so the result is the stroke the document describes, whatever the canvas is showing. Pass the renderer document without any editor workspace around it. There is one answer per request, in order; a stroke that cannot be outlined is answered with the reason (seeStrokeOutlineResult). Abudgetis shared by every call of one command: the outline that would take the command past its bytes rejects the call withStrokeOutlineBudgetError, a step that would start after its time is used up rejects it withStrokeOutlineTimeError, and no answer of the call is kept.Compiling the page is the first step, and it runs on the calling thread like the others: with no time left it is not started, and the time it takes (measured with
now, in milliseconds) is counted down in the budget. A compile cannot be interrupted, so one that takes longer than the time left runs to its end; the call is then rejected withStrokeOutlineTimeErrorand the backend is not asked, so no outlining is added to it.async loadDocument(load: RenderDocumentLoad): Promise<void>源码替换整个文档。如果新文档中仍有当前活动页面,则保留该页面;否则场景会被清空,直到
setActivePage选定一个页面。原生,经由
InteractiveRetainedBackend.getSceneInfo:taco_render_session_get_scene_info原生,经由
InteractiveRetainedBackend.apply:taco_render_session_applyasync applyDocumentUpdate(update: DocumentSceneUpdate): Promise<void>源码应用一次已提交的文档变更。该更新必须以此协调器持有的文档和提交为起点,否则会被以
InteractiveRenderTransitionError拒绝。活动页面在可能时以增量批次发送,否则整体重新加载。原生,经由
InteractiveRetainedBackend.getSceneInfo:taco_render_session_get_scene_info原生,经由
InteractiveRetainedBackend.apply:taco_render_session_applyasync setActivePage(pageId: PageId | null): Promise<void>源码编译并显示另一个页面;传入
null时显示空场景。原生,经由
InteractiveRetainedBackend.getSceneInfo:taco_render_session_get_scene_info原生,经由
InteractiveRetainedBackend.apply:taco_render_session_applyasync setViewport(viewport: ViewportState): Promise<void>源码将新的视口(平移、缩放、画布尺寸)传给后端。
hitTest(screenPoint: Point): readonly EditorHit[]源码在屏幕上某点执行命中测试:先检查叠加层的命中区域,再检查可选中的文档节点,结果按最上层优先排列。
原生,经由
InteractiveRetainedBackend.hitTest:taco_render_session_hit_testhitTestIncludingLocked(screenPoint: Point): readonly EditorHit[]源码The layers painted at a screen point, topmost first, with the layers
hitTestleaves out because a click cannot select them: a locked layer and the layers inside one. Overlay hit regions are not included. The canvas menu’s “Select layer” lists from these hits, since it is how a locked layer is selected on the canvas.原生,经由
InteractiveRetainedBackend.hitTest:taco_render_session_hit_testgetNodeGeometry(nodeId: NodeId): NodeGeometry | null源码某个文档节点的已提交几何信息;若该节点不在场景中,则为
null。原生,经由
InteractiveRetainedBackend.getNodeGeometry:taco_render_session_get_node_geometrygetSceneInfo(): RenderSceneInfo源码后端的场景尺寸、计数和代次。
原生,经由
InteractiveRetainedBackend.getSceneInfo:taco_render_session_get_scene_infogetSceneGeometrySnapshot(): SceneGeometrySnapshot源码已提交场景中每个节点的几何信息,按从后到前的顺序排列。结果会被缓存,直到代次、视口或文档发生变化。
原生,经由
InteractiveRetainedBackend.getSceneInfo:taco_render_session_get_scene_info原生,经由
InteractiveRetainedBackend.getGeometrySnapshot:taco_render_session_get_geometry_snapshotgetTextGeometry(nodeId: NodeId): TextGeometry | null源码文本节点的光标和选区几何信息,来自后端的文本布局。
原生,经由
InteractiveRetainedBackend.getSceneInfo:taco_render_session_get_scene_infohitTestText(queryInput: TextHitQuery): TextHitResult | null源码文本节点中某点下方的文本位置。
原生,经由
InteractiveRetainedBackend.getSceneInfo:taco_render_session_get_scene_info将文本位置移动一个光标步长,例如一个单词或一行。
原生,经由
InteractiveRetainedBackend.getSceneInfo:taco_render_session_get_scene_infogetTextLayoutMetrics(nodeId: NodeId): InteractiveTextLayoutMetrics | null源码文本节点的行度量信息和建议的自动尺寸。
原生,经由
InteractiveRetainedBackend.getSceneInfo:taco_render_session_get_scene_infogetFontMetadata(fontResourceId: string): RenderFontMetadataSnapshot | null源码-
原生,经由
InteractiveRetainedBackend.getSceneInfo:taco_render_session_get_scene_info getVectorGeometry(nodeId: NodeId): VectorGeometry | null源码矢量节点的顶点、控制柄、线段和区域。
原生,经由
InteractiveRetainedBackend.getSceneInfo:taco_render_session_get_scene_infohitTestVector(queryInput: VectorHitQuery): VectorHitTestResult | null源码屏幕上某点下方的矢量顶点、控制柄、线段或区域。
原生,经由
InteractiveRetainedBackend.getSceneInfo:taco_render_session_get_scene_infobooleanVectorPaths(request: VectorBooleanPathRequest): VectorBooleanPathResult源码用布尔运算合并两个节点的路径,并检查结果是否为有效且带命名空间的矢量网络。
原生,经由
InteractiveRetainedBackend.getSceneInfo:taco_render_session_get_scene_infogetDocumentRevision(): | { readonly document: DesignDocument; readonly commitId: CommitId } | null源码会话当前持有的规范文档和提交;加载第一个文档之前为
null。文档刚发生改动时,应用可能比会话领先一个版本;调用方可以把它与自己的版本比较,以便等待会话跟上,而不是去询问会话尚未拥有的节点。createAccessibilityBindingV1( overlay: AccessibilityOverlayStateV1 ): InteractiveAccessibilityBindingV1 | null源码根据 TypeScript 拥有的规范状态和以原生端为准的几何信息,创建 v1 语义镜像。不会使用任何后端无障碍查询。
resolveAccessibilityActionRouteV1( binding: InteractiveAccessibilityBindingV1, request: AccessibilityActionRequestV1 ): InteractiveAccessibilityActionRouteV1源码将语义操作解析为一个封闭的 UI 命令,不调用回调,也不改变规范状态、选区、焦点或渲染器状态。
原生,经由
InteractiveRetainedBackend.getSceneInfo:taco_render_session_get_scene_infoasync setOverlays(overlays: EditorOverlayState): Promise<void>源码替换编辑叠加层:选区框与控制柄、画布叠加层,以及文本或矢量编辑叠加层。之后任何使代次递增的场景变更都会清除它们。
原生,经由
InteractiveRetainedBackend.setOverlays:taco_render_session_set_text_editing_overlay,taco_render_session_clear_text_editing_overlay,taco_render_session_set_vector_editing_overlay,taco_render_session_clear_vector_editing_overlay,taco_render_session_set_selection_chrome,taco_render_session_set_canvas_overlayasync renderFrame(): Promise<EditorRenderFrameReport>源码在之前所有变更都完成后绘制一帧。
原生,经由
InteractiveRetainedBackend.getSceneInfo:taco_render_session_get_scene_infoasync getAccessibilitySnapshot(): Promise<AccessibilityNodeSnapshot | null>源码向后端请求当前视口的无障碍树。
dispose(): Promise<void>源码等待待处理的变更完成,然后释放后端和所有缓存状态。再次调用会返回同一个 promise;失败后可以重试。
源码interface InteractiveRenderSessionCoordinatorOptionsInteractiveRenderSessionCoordinator的选项。readonly backend: InteractiveRetainedBackend源码持有并绘制场景的保留后端。
readonly viewport: ViewportState源码初始视口。后端会在第一次叠加层更新或第一帧之前收到它;使用“workspace”策略时,要等到有页面处于活动状态后才会收到。
readonly hitToleranceScreenPx?: number源码几何主体命中的扩展范围,单位为 CSS 像素。默认为 4。
readonly rendererProjectionPolicy?: "nodes-only" | "workspace"源码允许编辑器在受保护的页面根节点外围替换为一个更大的工作区根节点。
readonly userLanguage?: string源码readonly resolveInstance?: InstanceResolver源码See
CompilePageOptions.resolveInstance; the canvas and export both use it.
源码interface InteractiveRetainedBackend高层编辑器协调器使用的底层保留后端。
apply必须具有事务性:当它抛出异常或 reject 时,其已提交的保留场景和代次保持不变。成功的代次变更会原子地使后端的临时叠加层失效。其他所有异步 setter 同样只在 fulfill 时才发布结果,在 reject 时保持之前的状态不变。几何信息和命中结果使用世界(规范文档)坐标。dispose可以安全重试。Web 应用用
WasmInteractiveRetainedBackend实现它:该实现将保留场景存放在PortableWasmRenderCoreSession中,并用 WebGPU 绘制。下方的 Native 行列出了该实现通过会话调用的 C 函数。readonly capabilities: InteractiveRetainedBackendCapabilities源码此后端实现了哪些可选方法。
apply(batch: Uint8Array): RenderUpdateReport | Promise<RenderUpdateReport>源码将一个来自
RenderChangeBatchEncoder的变更批次应用到保留场景,并报告新的代次。applyWithStaticImageFrames?( batch: Uint8Array, imageAssets: readonly ImageAsset[] ): RenderUpdateReport | Promise<RenderUpdateReport>源码原子地应用一个场景批次,以及候选场景所需的完整静态图片资源集合。被拒绝时,两者都不得发布。
applyWithMediaFrames?( batch: Uint8Array, imageAssets: readonly ImageAsset[], videoAssets: readonly VideoAsset[] ): RenderUpdateReport | Promise<RenderUpdateReport>源码原子地应用一个场景批次以及两个确切的媒体资源集合。
updatePendingVideoFrames?(): RenderUpdateReport | Promise<RenderUpdateReport>源码发布由后端拥有的待处理视频节拍(tick),而不改变场景标识。
getSceneInfo(): RenderSceneInfo源码场景尺寸、计数、代次和摘要。
getNodeGeometry(nodeId: string): RenderNodeGeometry | undefined源码某个保留节点的边界和变换;若场景中没有该节点,则为
undefined。getGeometrySnapshot(): RenderGeometrySnapshot源码每个保留节点的几何信息,按从后到前的顺序排列。
hitTest( worldX: number, worldY: number, worldTolerance: number ): readonly RenderHit[]源码按最上层优先排列的保留主体命中结果。
whenQueryable?(): Promise<void>源码当同步查询可以安全进入后端运行时时 resolve。
setViewport(viewport: ViewportState): void | Promise<void>源码为新视口调整渲染目标的尺寸。
setOverlays(overlays: EditorOverlayState): void | Promise<void>源码替换绘制在场景之上的编辑叠加层:文本或矢量编辑叠加层、选区框与控制柄,以及画布叠加层(吸附线、参考线、测量标注和像素网格)。
原生:
taco_render_session_set_text_editing_overlay,taco_render_session_clear_text_editing_overlay,taco_render_session_set_vector_editing_overlay,taco_render_session_clear_vector_editing_overlay,taco_render_session_set_selection_chrome,taco_render_session_set_canvas_overlayrenderFrame(): EditorRenderFrameReport | Promise<EditorRenderFrameReport>源码为当前视口绘制已提交的场景和叠加层。
getTextGeometry?(nodeId: NodeId, viewport: ViewportState): TextGeometry | null源码文本节点的光标、选区和输入法组合(composition)几何信息。
原生:
taco_render_session_get_text_carets,taco_render_session_get_text_range_rectshitTestText?(query: TextHitQuery): TextHitResult | null源码文本节点中某点下方的文本位置。
将文本位置移动一个光标步长,例如一个单词或一行。
getTextLayoutMetrics?(nodeId: NodeId): RenderTextLayoutMetrics | undefined源码文本节点的行度量信息和建议的自动尺寸。
getFontMetadata?(fontResourceId: string): RenderFontMetadataSnapshot | undefined源码getVectorGeometry?( nodeId: NodeId, viewport: ViewportState ): VectorGeometry | null源码矢量节点的顶点、控制柄、线段和区域。
hitTestVector?( query: VectorHitQuery, viewport: ViewportState ): VectorHitTestResult | null源码屏幕上某点下方的矢量顶点、控制柄、线段或区域。
booleanVectorPaths?(request: VectorBooleanPathRequest): VectorBooleanPathResult源码用布尔运算合并两条矢量路径。
exportCompiledScene?( request: RenderCompiledExportRequest ): Promise<RenderExportResult>源码通过一次性会话导出单独编译的页面,从而使实时场景、其视口及其编辑叠加层都不会进入导出文件。
原生:
taco_render_session_create,taco_render_session_apply_with_static_image_frames,taco_render_session_apply,taco_render_session_exportoutlineCompiledStrokes?( request: RenderCompiledStrokeOutlineRequest ): Promise<readonly StrokeOutlineResult[]>源码Outlines strokes of a separately compiled page through a throwaway session: one answer per request, in order. A stroke the renderer cannot outline (the page does not draw its node, the node has no such stroke, the geometry does not resolve) is answered with the reason and does not stop the others.
原生:
taco_render_session_create,taco_render_session_apply,taco_render_session_outline_strokegetAccessibilitySnapshot?( viewport: ViewportState ): AccessibilityNodeSnapshot | null | Promise<AccessibilityNodeSnapshot | null>源码dispose(): void | Promise<void>源码释放后端。失败后可以安全地再次调用。
源码interface InteractiveRetainedBackendCapabilities某个后端实现了
InteractiveRetainedBackend中的哪些可选部分。协调器在调用可选方法之前会检查这些标志。readonly staticImageFrames: boolean源码原子地提交一个保留场景批次及其确切的已解码静态图片集合。
readonly videoFrames: boolean源码支持原子地安装混合场景,以及同一代次内的视频节拍。
readonly textGeometry: boolean源码readonly textHitTesting: boolean源码readonly textLayoutMetrics: boolean源码readonly fontMetadata: boolean源码readonly vectorGeometry: boolean源码readonly vectorHitTesting: boolean源码readonly vectorBooleanOperations: boolean源码readonly accessibility: boolean源码
源码type InteractiveRenderAdvancedCapability = | "text-geometry" | "text-hit-testing" | "text-navigation" | "text-layout-metrics" | "font-metadata" | "vector-geometry" | "vector-hit-testing" | "vector-boolean-operations" | "accessibility"保留后端可能不具备的可选查询或功能。当编辑器调用后端不支持的方法时,协调器会以此名称抛出
InteractiveRenderCapabilityError。
源码interface InteractiveTextLayoutMetrics extends RenderTextLayoutMetrics单个文本节点的文本布局度量信息,以其文档节点 ID 标识。
readonly nodeId: NodeId源码
源码type VectorBooleanOperation = | "union" | "intersection" | "difference" | "exclusion"对两条矢量路径执行的布尔运算。
源码interface VectorBooleanPathRequest合并两个节点的路径。结果中每个顶点、线段和区域的 ID 都以
resultIdNamespace加一个冒号开头。readonly primaryNodeId: NodeId源码readonly secondaryNodeId: NodeId源码readonly operation: VectorBooleanOperation源码readonly resultIdNamespace: string源码
源码interface VectorBooleanPathResult布尔运算针对某个场景代生成的矢量网络。
readonly generation: bigint源码readonly primaryNodeId: NodeId源码readonly secondaryNodeId: NodeId源码readonly operation: VectorBooleanOperation源码readonly vectorNetwork: VectorNetwork源码
源码interface StrokeOutlineRequestOne stroke to outline: the node, the stroke’s index in the node’s strokes (
VisualStyle.strokes, or 0 for a connector’s one stroke), and the prefix of every ID in the result.readonly nodeId: NodeId源码readonly strokeIndex: number源码readonly resultIdNamespace: string源码
源码type StrokeOutlineResult = | { readonly outlined: true; readonly vectorNetwork: VectorNetwork } | { readonly outlined: false; readonly reason: string }The answer to one
StrokeOutlineRequest: the stroke as a vector network of the area it paints, in its node’s local coordinates (a network without regions when the stroke paints nothing), or the reason the renderer could not outline it.
源码interface RenderCompiledStrokeOutlineRequestA cold page batch and the strokes to outline in it.
readonly batch: Uint8Array源码readonly strokes: readonly StrokeOutlineRequest[]源码readonly budget?: StrokeOutlineBudget源码What the command these strokes belong to may still keep, and how long the renderer may still work on it. Every outline is charged to it as it arrives; the one that does not fit is not decoded and fails the whole request with
StrokeOutlineBudgetError. Every step is timed, and none is started once the time is used up: the request then fails withStrokeOutlineTimeError.
源码class InteractiveRenderCapabilityError extends Error后端未实现的高级编辑器接口所产生的结构化失败。
readonly capability: InteractiveRenderAdvancedCapability源码new (capability: InteractiveRenderAdvancedCapability)源码
源码class InteractiveRenderTransitionError extends Error被拒绝的文档 store 转换;渲染器和编译器状态都不会前进。
readonly code: InteractiveRenderTransitionErrorCode源码readonly expectedCommitId: CommitId | null源码readonly actualCommitId: CommitId | null源码new ( code: InteractiveRenderTransitionErrorCode, message: string, commitIds: { readonly expected: CommitId | null; readonly actual: CommitId | null; } = { expected: null, actual: null } )源码
源码type InteractiveRenderTransitionErrorCode = | "DOCUMENT_NOT_LOADED" | "PREVIOUS_DOCUMENT_IDENTITY_MISMATCH" | "PREVIOUS_RENDERER_DOCUMENT_IDENTITY_MISMATCH" | "PREVIOUS_RENDERER_NODE_OWNERS_IDENTITY_MISMATCH" | "PREVIOUS_RENDERER_QUERY_TARGETS_IDENTITY_MISMATCH" | "INVALID_RENDERER_DOCUMENT_PROJECTION" | "INVALID_RENDERER_NODE_OWNERS" | "INVALID_RENDERER_QUERY_TARGETS" | "RENDERER_CHANGES_REQUIRED" | "INVALID_RENDERER_CHANGES" | "PREVIOUS_COMMIT_MISMATCH"InteractiveRenderSessionCoordinator.applyDocumentUpdate(或其他文档变更)被拒绝的原因。大多数代码表示该更新基于的文档、渲染器文档或提交与协调器持有的不同。
源码class InteractiveRenderSessionDisposedError extends Error确定性的“释放后使用”失败。
new ()源码
源码class InteractiveRenderSessionBusyError extends Error当排队中的变更尚未完成时,同步场景查询不可用。
new ()源码
源码class InteractiveRenderQueryBusyError extends Error在原生运行时让出执行期间尝试的同步后端查询。
readonly stage: string源码readonly operation: string | null源码new (stage: string, operation: string | null = null)源码
源码class InteractiveRenderResourceError extends Error渲染器所需的某个文档资源缺失或不可用:媒体节点指向了缺失的资源或非媒体资源,或者存储的资源与其资源定义不符(例如 MIME 类型不同)。
assetId指明该资源。readonly assetId: string源码new (assetId: string, message: string)源码
源码class InteractiveRenderGeometryError extends Error后端查询返回了协调器无法信任的几何数据:属于其他节点的结果、过期的场景代次,或编辑器无法表示的值。如果有被查询的节点,
nodeId会指明它。readonly nodeId: string | null源码new (message: string, nodeId: string | null = null)源码
无障碍路由
协调器为当前页面构建无障碍快照,并把屏幕阅读器的动作转换为 UI 命令。绑定把快照与其来源的确切文档、提交和场景代次关联起来,因此过期的动作会被拒绝。文档刚发生改动时,应用可能比协调器领先一个提交;getDocumentRevision 返回协调器持有的文档和提交,因此应用可以等待协调器跟上,而不是去询问协调器尚未拥有的节点。
源码interface InteractiveAccessibilityBindingV1一个不可变的语义快照,绑定到协调器确切的已提交规范标识和保留标识。只有签发它的协调器才能路由它。
readonly version: typeof ACCESSIBILITY_SNAPSHOT_VERSION源码readonly document: DesignDocument源码readonly commitId: CommitId源码readonly pageId: PageId源码readonly viewport: ViewportState源码readonly generation: bigint源码readonly snapshot: AccessibilitySnapshotV1源码
源码interface InteractiveAccessibilityActionRouteV1纯粹的 UI 意图,仅在精确的上下文和操作权限检查通过后才返回。
readonly version: typeof ACCESSIBILITY_SNAPSHOT_VERSION源码readonly binding: InteractiveAccessibilityBindingV1源码readonly command: InteractiveAccessibilityActionCommandV1源码
源码type InteractiveAccessibilityActionCommandV1 = | { readonly kind: "focus-mirror"; readonly nodeId: NodeId; readonly focusOwner: "accessibility-mirror"; } | { readonly kind: "set-node-selection"; readonly nodeId: NodeId; readonly mode: "replace" | "toggle"; readonly focusOwner: "accessibility-mirror"; } | { readonly kind: "begin-text-edit"; readonly nodeId: NodeId; readonly focusOwner: "text-input"; } | { readonly kind: "begin-code-edit"; readonly nodeId: NodeId; readonly focusOwner: "text-input"; }无障碍操作解析得到的 UI 命令。
源码class InteractiveAccessibilityContextError extends Error一个语义操作,其由协调器拥有的场景标识已不是当前的。
new (readonly code: InteractiveAccessibilityContextErrorCode, message: string)源码
源码type InteractiveAccessibilityContextErrorCode = | "INVALID_BINDING" | "DOCUMENT_IDENTITY_MISMATCH" | "COMMIT_MISMATCH" | "ACTIVE_PAGE_MISMATCH" | "VIEWPORT_IDENTITY_MISMATCH" | "GENERATION_MISMATCH" | "CANONICAL_NODE_MISSING" | "EDIT_TARGET_MISMATCH"
场景查询与结果
RenderCoreSession 报告的关于其保留场景的信息。除非名称另有说明,位置均使用世界(文档)坐标,且大多数结果都带有所属的场景代次。
源码interface RenderSceneInfo保留场景以文档单位表示的大小、节点数和资源数, 以及标识其当前内容的代和摘要。
readonly width: number源码readonly height: number源码readonly nodeCount: number源码readonly resourceCount: number源码readonly generation: bigint源码readonly sceneDigest: bigint源码
源码interface RenderUpdateReport应用一个批次的结果:各项计数、新的场景代和摘要,以及发生变化的区域。
readonly commandsApplied: number源码readonly nodeCount: number源码readonly resourceCount: number源码readonly generation: bigint源码readonly sceneDigest: bigint源码readonly dirtyBounds: RenderDirtyBounds源码
源码interface RenderDirtyBounds上一个批次改动的世界空间区域:被改动节点的旧边界、新边界及二者的并集。
readonly oldBounds?: RenderRect源码脏矩形是场景 / 世界空间中的边界。
readonly newBounds?: RenderRect源码readonly combinedBounds?: RenderRect源码
源码interface RenderRectreadonly x: number源码readonly y: number源码readonly width: number源码readonly height: number源码
源码interface RenderNodeGeometry一个保留节点的边界、变换、绘制顺序和可见性。
原生:
TacoRenderNodeGeometry,TacoRenderGeometryRecordreadonly id: string源码readonly kind: RetainedNodeRecord["kind"]源码readonly localBounds?: RenderRect源码readonly worldBounds?: RenderRect源码readonly visibleWorldBounds?: RenderRect源码应用可见性和祖先裁剪之后的世界空间边界。
readonly subtreeVisibleBounds?: RenderRect源码The union of
visibleWorldBoundsover this node and all its descendants, with children of a clipping frame clipped to it: everything the subtree paints. Only single-node geometry queries report it.readonly worldTransform: Transform源码readonly painterOrder: bigint源码readonly effectivelyVisible: boolean源码readonly effectiveOpacity: number源码
源码interface RenderGeometrySnapshot针对一个已提交场景代的不可变几何视图,按从后到前排列。
readonly generation: bigint源码readonly nodes: readonly RenderNodeGeometry[]源码
源码interface RenderHit命中测试点下方的一个节点。
原生:
TacoRenderHitreadonly id: string源码readonly kind: RetainedNodeRecord["kind"]源码readonly painterOrder: bigint源码readonly visibleWorldBounds: RenderRect源码
源码interface ViewportMappingOptions如何将场景适配到视口中,供
RenderCoreSession.mapViewport使用。readonly viewportWidth: number源码readonly viewportHeight: number源码readonly mode: "fit" | "fill" | "stretch"源码readonly alignX?: number源码零表示对齐到起始边,一表示对齐到末尾边。
readonly alignY?: number源码
源码interface ViewportMapping场景坐标与视口坐标之间的变换,以及场景在视口内的边界。 对于大小为 的场景和大小为 的视口, 缩放比例初始为 和 ;
fit将二者都设为 ,fill设为 ,stretch则保持不变。 对齐方式为 (默认 0.5)时:且
sceneViewportBounds为 。readonly sceneToViewport: Transform源码readonly viewportToScene: Transform源码readonly sceneViewportBounds: RenderRect源码
源码interface RgbaRenderTargetreadonly kind: "rgba"源码readonly width: number源码readonly height: number源码readonly rowBytes: number源码readonly pixels: Uint8Array源码
源码interface RenderFrameReportreadonly backend: "skia-cpu" | "skia-webgpu"源码readonly width: number源码readonly height: number源码
源码interface RenderTextPosition相对于段落的作者文本位置。偏移量以 UTF-16 码元计数。
readonly paragraphIndex: number源码readonly utf16Offset: number源码readonly affinity: RenderTextAffinity源码
源码type RenderTextAffinity = "upstream" | "downstream"光标属于换行处或双向文本边界的哪一侧。
源码interface RenderTextRangeanchor 和 focus 保留作者所做选区的方向。
readonly anchor: RenderTextPosition源码readonly focus: RenderTextPosition源码
源码interface RenderTextCaretGeometryreadonly position: RenderTextPosition源码readonly localBounds: RenderRect源码
源码interface RenderTextCaretSnapshotreadonly generation: bigint源码readonly carets: readonly RenderTextCaretGeometry[]源码
源码interface RenderTextRangeGeometryreadonly generation: bigint源码readonly localRects: readonly RenderRect[]源码
源码interface RenderTextHitResultreadonly generation: bigint源码readonly position: RenderTextPosition源码readonly inside: boolean源码
RenderCoreSession.navigateText的一种光标移动方式。C 代码按此顺序从 0 开始编号。
源码interface RenderTextLayoutMetricsreadonly generation: bigint源码readonly autoResize: RetainedTextNode["autoResize"]源码readonly frameWidth: number源码readonly frameHeight: number源码readonly contentWidth: number源码readonly contentHeight: number源码readonly suggestedWidth: number源码readonly suggestedHeight: number源码readonly paragraphCount: number源码readonly lineCount: number源码readonly caretCount: number源码
源码interface RenderFontMetadataSnapshotreadonly fontResourceId: string源码readonly generation: bigint源码readonly featureTags: readonly string[]源码readonly axes: readonly RenderFontAxisMetadata[]源码
源码interface RenderFontAxisMetadatareadonly tag: string源码readonly minimum: number源码readonly defaultValue: number源码readonly maximum: number源码
源码interface RenderVectorGeometrySnapshotreadonly generation: bigint源码readonly vertices: readonly RenderVectorVertexGeometry[]源码readonly handles: readonly RenderVectorCubicHandleGeometry[]源码readonly segments: readonly RenderVectorSegmentGeometry[]源码readonly regions: readonly RenderVectorRegionGeometry[]源码
源码interface RenderVectorVertexGeometryreadonly kind: "vertex"源码readonly id: string源码readonly localPoint: { readonly x: number; readonly y: number }源码readonly screenPoint: { readonly x: number; readonly y: number }源码
源码interface RenderVectorCubicHandleGeometryreadonly kind: "cubic-handle"源码readonly id: string源码readonly segmentId: string源码readonly vertexId: string源码readonly endpoint: "start" | "end"源码readonly localPoint: { readonly x: number; readonly y: number }源码readonly screenPoint: { readonly x: number; readonly y: number }源码
源码type RenderVectorSegmentGeometry = | RenderVectorLineSegmentGeometry | RenderVectorCubicSegmentGeometry | RenderVectorArcSegmentGeometry
源码interface RenderVectorLineSegmentGeometry extends RenderVectorSegmentGeometryBasereadonly kind: "line"源码
源码interface RenderVectorCubicSegmentGeometry extends RenderVectorSegmentGeometryBasereadonly kind: "cubic"源码readonly startHandleId: string源码readonly endHandleId: string源码
源码interface RenderVectorArcSegmentGeometry extends RenderVectorSegmentGeometryBasereadonly kind: "elliptical-arc"源码readonly radiusX: number源码readonly radiusY: number源码readonly xAxisRotation: number源码readonly largeArc: boolean源码readonly sweep: boolean源码
源码interface RenderVectorRegionGeometryreadonly kind: "region"源码readonly id: string源码readonly windingRule: "nonzero" | "evenodd"源码readonly localBounds: RenderRect源码readonly screenBounds: RenderRect源码
源码interface RenderVectorHitQueryreadonly screenPoint: { readonly x: number; readonly y: number }源码readonly toleranceCssPx: number源码readonly documentToScreen: Transform源码
源码interface RenderVectorHitSnapshotreadonly generation: bigint源码readonly hits: readonly RenderVectorHit[]源码
源码type RenderVectorHit = & { readonly id: string; readonly priority: number; readonly authoredOrder: number; readonly distanceCssPx: number; } & ( | { readonly kind: "vertex" } | { readonly kind: "cubic-handle"; readonly endpoint: "start" | "end" } | { readonly kind: "segment" } | { readonly kind: "region" })
源码type RenderVectorBooleanOperation = | "union" | "intersection" | "difference" | "exclusion"对两条矢量路径执行的布尔运算。C 代码为:union(联集)1、 intersection(交集)2、difference(减去)3、exclusion(排除)4。
源码interface RenderVectorBooleanPathRequestreadonly primaryNodeId: string源码readonly secondaryNodeId: string源码readonly operation: RenderVectorBooleanOperation源码readonly resultIdNamespace: string源码
源码interface RenderVectorBooleanPathSnapshotreadonly generation: bigint源码readonly vectorNetwork: VectorNetworkRecord源码
源码interface RenderStrokeOutlineRequestAsks for one stroke of a path or container node as the filled shape it paints.
strokeIndexcounts the node’s strokes in paint order, hidden ones included, which is the stroke’s index in the model’sVisualStyle.strokes. Every vertex, segment, handle and region ID of the result starts withresultIdNamespacefollowed by a colon.原生:
TacoRenderStrokeOutlineQueryreadonly nodeId: string源码readonly strokeIndex: number源码readonly resultIdNamespace: string源码
源码interface RenderStrokeOutlineSnapshotThe outline of one stroke for one scene generation, in the node’s local coordinates: closed loops in even-odd regions without fills. A ring is one region with a hole, and every dash is a region of its own. A stroke that paints nothing gives a network without components.
原生:
TacoRenderStrokeOutlineResultreadonly generation: bigint源码readonly vectorNetwork: VectorNetworkRecord源码
叠加层
编辑叠加层由渲染器在与场景相同的帧中绘制:选区轮廓和控制柄、吸附线和参考线,以及文本或矢量编辑状态。它们不属于场景,永远不会被导出,并且下一次场景改动会清除编辑叠加层。
源码interface RenderSelectionChrome渲染器绘制在场景之上的选区轮廓和变换控制柄。
RenderCoreSession.setSelectionChrome将其编码为SessionCache.setSelectionChrome读取的字节布局。原生:
taco_render_session_set_selection_chrome,SessionCache.setSelectionChromereadonly items: readonly RenderSelectionChromeItem[]源码readonly strokeRgba: number源码译文已过期
Default colours of items that give none, 0xRRGGBBAA.
readonly handleFillRgba: number源码readonly devicePixelRatio: number源码
源码interface RenderSelectionChromeItem译文已过期
One selection outline or transform handle, resolved against a node at paint time. A handle arrives finished: the editor hit-tests handles, so it alone decides their size and turn, and the renderer only places the centre and paints the rectangle it is given.
readonly nodeId: string | null源码译文已过期
Null places x and y (and an outline’s width and height) in scene coordinates.
readonly kind: "outline" | "square-handle" | "round-handle"源码readonly hover?: boolean源码readonly dashed?: boolean源码readonly x: number源码译文已过期
An outline’s node-local (or scene) rectangle. For a handle, x and y are its centre, and width and height its size on screen in CSS pixels, width along the turned x direction.
readonly y: number源码readonly width?: number源码readonly height?: number源码readonly angle?: number源码A handle’s turn on screen in radians, clockwise (screen y points down). 0 when omitted.
readonly strokeRgba?: number源码0xRRGGBBAA; the chrome’s
strokeRgbawhen omitted.readonly fillRgba?: number源码A handle’s fill, 0xRRGGBBAA; the chrome’s
handleFillRgbawhen omitted.readonly offsetX?: number源码场景空间中的偏移,用于保留场景中没有的预览。
readonly offsetY?: number源码readonly sceneTransform?: Transform源码锚定到场景的项(
nodeId为null)的局部到场景矩阵, 这样旋转节点的预览会保持旋转后的轮廓。省略时为单位矩阵。readonly nodeTransform?: Transform源码Item-to-node matrix of a node-anchored item (wire version 21): the item maps through it, then through the node’s transform. A multi-selection’s box is anchored to one selected node this way. Identity when omitted.
源码function encodeSelectionChrome(chrome: RenderSelectionChrome): Uint8ArrayEncodes the selection chrome in the layout
taco_render_session_set_selection_chromereads (version 3, wire version 20; seerender_core.h). Each item carries its own colours, and each handle the size and angle the editor hit-tests it with, so the renderer paints exactly the handle the editor tests against.原生:
taco_render_session_set_selection_chrome,SessionCache.setSelectionChrome
源码interface RenderCanvasOverlay渲染器在同一帧中绘制在场景之上的编辑器线条:吸附线和对齐线及其 x 标记、 标尺参考线、option 拖动时的轮廓与测量,以及像素网格。它们从不属于文档内容, 也从不改变保留场景。
readonly anchorNodeId: string | null源码叠加层使用其局部坐标的节点(页面根节点),这样线条会与页面在同一帧中跟随平移。 为 null 表示全部使用场景坐标。
readonly devicePixelRatio: number源码readonly grid: RenderOverlayGrid | null源码readonly lines: readonly RenderOverlayLine[]源码readonly marks: readonly RenderOverlayMark[]源码readonly titles?: readonly RenderOverlayTitle[]源码绘制在顶层画框上方的名称。缺省表示没有。
readonly rulers?: RenderOverlayRulers源码沿顶边和左边的标尺。缺省表示没有。
readonly boxes?: readonly RenderOverlayBox[]源码填充、斜线填充或描出轮廓的框,例如自动布局的间距。缺省表示没有。
readonly handles?: readonly RenderOverlayHandle[]源码带边框的短刻度线,例如自动布局的间距控制柄。缺省表示没有。
readonly badges?: readonly RenderOverlayBadge[]源码显示数值的小胶囊标签,例如拖动间距时的数值。缺省表示没有。
源码function encodeCanvasOverlay(overlay: RenderCanvasOverlay): Uint8Array按
taco_render_session_set_canvas_overlay读取的布局(版本 4;参见render_core.h)编码画布叠加层。空叠加层编码为零字节。SessionCache.setCanvasOverlay负责解码它。原生:
taco_render_session_set_canvas_overlay,SessionCache.setCanvasOverlay
源码interface RenderOverlayLine一条直的叠加层线条,按整设备像素绘制。
readonly orientation: "vertical" | "horizontal"源码竖直线的 x 恒定;水平线的 y 恒定。
readonly side: RenderOverlayLineSide源码readonly position: number源码竖直线的 x,或水平线的 y。
readonly start: number | null源码线条沿其长度方向的起点和终点;为
null时贯穿整个画布。readonly end: number | null源码readonly rgba: number源码0xRRGGBBAA。
readonly dash?: { readonly dashCssPx: number; readonly gapCssPx: number }源码以 CSS 像素表示的虚线段长和间隔长度;实线时省略。
readonly scene?: boolean源码使用场景坐标,而不是相对于叠加层锚点的局部坐标。
readonly anchorNodeId?: string源码一个节点,此线条使用其局部坐标而非叠加层的锚点, 例如某个画框自己的参考线必须在移动或调整大小预览中跟随该画框。
readonly spansAnchorBox?: boolean源码沿锚点节点自身的框延伸(从 0 到其宽度或高度);忽略 start 和 end。
源码type RenderOverlayLineSide = "after" | "before" | "centered"一条宽 1 CSS 像素的线条在其位置周围覆盖哪些设备像素: 左边缘或上边缘以及坐标线(网格线、标尺参考线)用“after”, 右边缘或下边缘用“before”,中线用“centered”。 这些正是选区轮廓在该处绘制边缘时覆盖的像素。
源码interface RenderOverlayMark一个抗锯齿的 x 标记,居中于两条叠加层线条的交点。
readonly x: number源码readonly y: number源码readonly xSide: RenderOverlayLineSide源码相交线条所在的侧:x 标记居中于这些线条的像素上。
readonly ySide: RenderOverlayLineSide源码readonly halfSizeCssPx: number源码readonly rgba: number源码readonly scene?: boolean源码
源码interface RenderOverlayGrid从原点起每隔
step个单位一条线,贯穿整个画布。readonly originX: number源码readonly originY: number源码readonly step: number源码readonly rgba: number源码
画布叠加层还携带渲染器在同一帧中绘制的画布界面元素:框、控制柄和胶囊标签(自动布局的内边距、间距和间距控制柄)、标尺,以及顶层画框上方的名称。它们的文字使用传给 taco_render_session_set_canvas_overlay_font 的字体。
源码interface RenderOverlayBox位于其锚点局部坐标中的矩形,经锚点在正在绘制的这一帧中的完整世界变换映射(因此旋转画框的框会随之旋转)。三种外观都是可选的:纯色填充、每隔 4 个 CSS 像素一条、宽一个 CSS 像素的对角条纹(斜线填充),以及框内一个 CSS 像素宽的轮廓。
readonly anchorNodeId?: string源码省略时使用叠加层的锚点。
readonly x: number源码readonly y: number源码readonly width: number源码readonly height: number源码readonly fillRgba?: number源码0xRRGGBBAA;省略时不绘制填充、斜线填充或轮廓。
readonly hatchRgba?: number源码readonly outlineRgba?: number源码
源码interface RenderOverlayHandle两端为圆头、带边框的短刻度线,以锚点局部坐标中的某个点为中心。它沿锚点局部的 x 轴或 y 轴放置,在任何缩放下都保持其 CSS 像素尺寸。
readonly anchorNodeId?: string源码readonly x: number源码readonly y: number源码readonly axis: "x" | "y"源码“x” 沿锚点局部的 x 轴,”y” 沿其 y 轴。
readonly lengthCssPx: number源码readonly thicknessCssPx: number源码readonly rgba: number源码0xRRGGBBAA。
readonly borderRgba: number源码
源码interface RenderOverlayBadge带一行文字的圆角胶囊标签,其左上角相对锚点局部坐标中的某个点偏移若干 CSS 像素。使用传给
setCanvasOverlayFont的字体绘制;没有字体时不绘制。readonly anchorNodeId?: string源码readonly x: number源码readonly y: number源码readonly offsetXCssPx: number源码readonly offsetYCssPx: number源码readonly fontSizeCssPx: number源码readonly text: string源码readonly backgroundRgba: number源码0xRRGGBBAA。
readonly textRgba: number源码
源码interface RenderOverlayRulers标尺。渲染器根据叠加层锚点(页面根节点)在正在绘制的这一帧中的状态布置刻度和数字,因此在平移、缩放或自动平移的每一步中,标尺都随页面移动。数字使用传给
setCanvasOverlayFont的字体。使用叠加层的锚点。readonly sizeCssPx: number源码标尺的粗细。
readonly fontSizeCssPx: number源码readonly minimumMajorCssPx: number源码主刻度按 1-2-5 步长选取,间距至少为此值。
readonly backgroundRgba: number源码0xRRGGBBAA 颜色。
readonly borderRgba: number源码readonly inkRgba: number源码readonly selectionFillRgba: number源码readonly selectionInkRgba: number源码readonly selectionX: readonly RenderOverlayRulerSpan[]源码已排序且互不相接的范围;长度为零的范围标记单个数值。
readonly selectionY: readonly RenderOverlayRulerSpan[]源码readonly labels: readonly RenderOverlayRulerLabel[]源码最多 16 个。
源码interface RenderOverlayRulerSpan标尺上的一段范围,使用叠加层锚点的单位。
readonly start: number源码readonly end: number源码
源码interface RenderOverlayRulerLabel参考线的位置,以圆角标签的形式绘制在其标尺上。
readonly axis: "x" | "y"源码“x” 是顶部标尺上的值,”y” 是左侧标尺上的值。
readonly position: number源码使用叠加层锚点的单位。
readonly backgroundRgba: number源码0xRRGGBBAA。
readonly textRgba: number源码
源码interface RenderOverlayTitle绘制在顶层画框上方的名称。渲染器把它放在画框在正在绘制的这一帧中的屏幕包围盒的左上角,因此它在移动、调整大小、平移或缩放时没有延迟地跟随画框,超出画框宽度的部分以省略号截断。它使用传给
setCanvasOverlayFont的字体绘制。readonly anchorNodeId: string源码readonly text: string源码readonly rgba: number源码0xRRGGBBAA。
readonly fontSizeCssPx: number源码字号,也是标题行框的高度。
readonly gapCssPx: number源码行框底部与画框顶边之间的距离。
源码interface RenderTextEditingOverlay一个带有代标记的临时选区、光标,以及可选的输入法(IME)范围。
readonly selection: RenderTextRange源码readonly composition?: RenderTextRange源码readonly caretVisible: boolean源码
源码interface RenderVectorEditingOverlayreadonly network: VectorNetworkRecord源码readonly selection: RenderVectorEditingSelection源码readonly pendingHandle?: RenderVectorPendingHandle | null源码The Pen’s pending handle, when there is one.
readonly viewport: { readonly documentToScreen: Transform; readonly screenWidthCssPx: number; readonly screenHeightCssPx: number; readonly screenPixelDensity: number; }源码
源码interface RenderVectorEditingSelection按类别列出的选中矢量组件,以及主组件(或
null)。readonly vertexIds: readonly string[]源码readonly handleIds: readonly string[]源码readonly segmentIds: readonly string[]源码readonly regionIds: readonly string[]源码readonly primary: RenderVectorEditingComponent | null源码
源码type RenderVectorEditingComponent = | { readonly kind: "vertex"; readonly id: string } | { readonly kind: "handle"; readonly id: string } | { readonly kind: "segment"; readonly id: string } | { readonly kind: "region"; readonly id: string }矢量网络中按 ID 指定的一个顶点、控制柄、线段或区域。
导出
导出把一个页面或单个图层绘制为 PNG、SVG、PDF 或原始 RGBA 字节。协调器会重新编译页面,并通过一个用后即弃的会话导出,因此实时场景及其叠加层都不会进入文件。
源码interface RenderDocumentExportOptionsInteractiveRenderSessionCoordinator.exportDocument导出什么以及如何导出。readonly format: RenderExportFormat源码readonly scale?: number源码每个文档单位对应的输出单位数。默认为 1。
readonly rootNodeId?: string源码导出此节点的可见边界及其子树;省略时表示整个页面。
readonly options?: RenderExportOptions源码
源码interface RenderExportOptions格式、缩放比例和根节点之外的导出选项。
readonly fixedSize?: { readonly dimension: "width" | "height"; readonly value: number; }源码以输出单位表示的固定输出宽度或高度,用于替代
scale: 缩放比例变为该尺寸除以导出边界的宽度或高度。readonly includeOverlappingLayers?: boolean源码指定根节点时,绘制根节点边界内的所有可见节点,而不仅是根节点的子树, 从而包含与之重叠的图层。
readonly imageSampling?: RenderExportImageSampling源码readonly svgNodeMarkers?: boolean源码readonly pdfRasterDpi?: number源码readonly maxPixels?: number源码The most pixels a raster export (
rgbaorpng) may have. An export over it is refused withRenderExportTooLargeErroronce its size is measured and before anything is allocated or drawn. Left out: only the renderer’s own limit of 16384 pixels a side applies.
源码interface RenderCompiledExportRequest一个冷页面批次,以及新会话绘制和导出它所需的内容。
readonly batch: Uint8Array源码readonly imageAssets: readonly ImageAsset[]源码批次引用的所有图片资源,用于解码成帧。
readonly format: RenderExportFormat源码readonly scale: number源码每个文档单位对应的输出单位数。
readonly rootNodeId?: string源码导出此节点的可见边界及其子树;省略时表示整个页面。
readonly options?: RenderExportOptions源码导出本身的其他选项;见
RenderExportOptions。
源码interface RenderExportRequest通过共享绘制器绘制的一个矩形场景区域。编辑叠加层从不导出,背景保持透明。
readonly format: RenderExportFormat源码readonly x: number源码以场景坐标表示的区域。
readonly y: number源码readonly width: number源码readonly height: number源码readonly scale?: number源码readonly rootNodeId?: string源码设置后,只绘制此节点及其后代。
readonly imageSampling?: RenderExportImageSampling源码图片填充和媒体帧的重采样方式;默认使用屏幕的“linear”。
readonly svgNodeMarkers?: boolean源码仅限 SVG:用节点标记包围每个已绘制节点的元素。见
PROTOCOL.md。readonly pdfRasterDpi?: number源码
源码interface RenderExportResult一次导出的字节及其大小。
源码type RenderExportFormat = "rgba" | "png" | "svg" | "pdf"
源码type RenderExportImageSampling = "linear" | "cubic" | "nearest"导出时图片的重采样方式:“linear”(屏幕所用的采样方式)、“cubic”或 “nearest”。
页面编译器
页面编译器把文档的一个页面转换为保留记录,并将其编码为变更批次。compilePageBatch 构建整个页面;ActivePageCompilerSession 保留上一个页面,只编码变更集涉及的部分。渲染器无法绘制的模型数据会以 RenderDocumentCompileError 失败,而不是悄悄消失。
源码function compilePageBatch( document: DesignDocument, pageId: PageId, options: CompilePageOptions ): CompiledPageBatch将一个规范页面编译为完整的变更批次:把场景重置为页面尺寸,注册其字体,并添加每个节点。不支持的节点和绘制语义会以结构化的
RenderDocumentCompileError报错,而不是直接消失。
源码function compileIncrementalPageBatch( previous: DesignDocument, current: DesignDocument, changes: ChangeSet, pageId: PageId, options: CompilePageOptions ): CompiledPageUpdate编译一次规范文档转换,而不重置保留场景。调用方必须已应用
compilePageBatch(previous, pageId),或同一转换链中上一次成功的结果。模型变更集是一个保守的失效信号。为保证正确性,编译器还会比较两个选中页面子树的完整保留表示,因此不完整的变更集不会让某次更新悄无声息地丢失。
源码class ActivePageCompilerSession当前显示页面的有状态编译器。
规范文档是不可变的,且经过校验的模型变更集会标明每一个受影响的实体。正式运行时的更新只检查这些 ID,以及结构上发生位移的兄弟节点;显式的冷编译审计则执行刻意设计为 O(document) 的验证过程。更新具有事务性:只有整个批次都成功编码后,缓存才会前进。
new (options: CompilePageOptions)源码创建一个空会话;调用
update之前需先调用reset。get initialized(): boolean源码reset是否已编译过一个页面。reset(document: DesignDocument, pageId: PageId): CompiledActivePageBatch源码编译并缓存一个完整的活动页面,包括重置命令。
update( document: DesignDocument, documentChanges: ChangeSet ): CompiledActivePageUpdate源码利用其权威的已变更实体索引,编译一次经过校验的转换。未变更的兄弟节点既不会被遍历,也不会被转换。
auditAgainstColdCompilation( document: | DesignDocument | undefined = this.#active?.document ): ActivePageAuditReport源码在
update()之外执行刻意设计为 O(document) 的正确性审计。clear(): void源码丢弃缓存的页面;下一次调用必须是
reset。
源码interface CompilePageOptions页面编译器从何处获取资源字节和语言偏好。
readonly getAssetBytes: (asset: Asset) => Uint8Array | undefined源码为注册为 wire 资源的资源提供字节。仅供场景使用的媒体元数据从不解析字节;加载解码后的帧属于后续平台适配器的职责。
readonly getFontSlices?: (asset: FontAsset) => | readonly CompileFontSlice[] | undefined源码按优先级顺序,提供来源为“google-fonts”的字体资源目前已加载的文件。当该资源是某个样式的主字体时,第一个文件总会被注册,以便文本拥有行度量信息;其余每个文件只有在覆盖了文本节点中的某个字符时才会被注册。仍在加载中的文件直接视为不存在:宿主会显示加载状态,并在文件到达后重新编译。
readonly userLanguage?: string源码用户的语言,以 BCP 47 标签表示,例如浏览器的
navigator.language。对于样式未指定语言的文本,它用于在 CJK 自动回退字体族之间做出选择;参见preferredCjkFamily。readonly resolveInstance?: InstanceResolver源码Derives an instance’s layers (design 4.1). Defaults to
resolveInstancefrom@taco-slides/model. Each resolved layer compiles as a stored node would, under its virtual ID; the instance compiles as a frame whose paints come from the component root.
源码interface CompileFontSlice按 Unicode 覆盖范围拆分的字体资源中已加载的一个文件,例如以许多小 WOFF2 文件提供的 Google Fonts 字体族。
readonly id: string源码在所属资源内唯一。不得包含“#”。
readonly unicodeRanges: readonly (readonly [number, number])[]源码该文件覆盖的码点范围(闭区间),已排序且互不重叠。
readonly bytes: Uint8Array源码
源码interface CompiledPageBatch以单个变更批次表示的完整页面,会重置保留场景。
readonly batch: Uint8Array源码已编码的批次,可直接传给
RenderCoreSession.apply。readonly nodeIds: readonly NodeId[]源码所有已编译的节点,按遍历顺序排列。
readonly mediaAssetIds: readonly string[]源码场景使用的图片和视频资源;由宿主附加它们的帧。
readonly resourceIds: readonly string[]源码批次中注册的 wire 资源 ID(字体和字体文件)。
源码type CompiledPageUpdate = CompiledIncrementalPageBatch | PageFullReloadRequired
源码interface CompiledIncrementalPageBatch编码为批次的页面变更,用于原地更新保留场景。
readonly kind: "incremental"源码readonly batch: Uint8Array源码不含重置命令的批次,页面未变更时也是如此。
readonly operations: PageIncrementalOperations源码readonly nodeIds: readonly NodeId[]源码readonly mediaAssetIds: readonly string[]源码readonly resourceIds: readonly string[]源码
源码interface PageIncrementalOperations增量批次包含的命令,按节点 ID 和资源 ID 列出。
readonly removeNodeIds: readonly NodeId[]源码被 wire 命令移除的之前的顶层子树。
readonly upsertNodeIds: readonly NodeId[]源码按规范遍历顺序插入或替换的当前节点。
readonly transformNodeIds?: readonly NodeId[]源码除变换外保留数据均未改变的当前节点。
readonly registerResourceIds: readonly string[]源码readonly removeResourceIds: readonly string[]源码
源码interface PageFullReloadRequired该变更无法以增量方式发送;请重新编译整个页面。
readonly kind: "full-reload-required"源码readonly reasons: readonly PageFullReloadReason[]源码
源码interface PageFullReloadReason页面需要整体重新加载的一个原因,附带可读的消息。
readonly code: PageFullReloadReasonCode源码readonly message: string源码
源码type PageFullReloadReasonCode = | "PREVIOUS_PAGE_NOT_FOUND" | "CURRENT_PAGE_NOT_FOUND" | "PAGE_ROOT_RESIZED" | "PAGE_ROOT_CHANGED" | "THEME_CHANGED" | "PAGE_VARIABLE_MODES_CHANGED"增量更新被拒绝、页面必须重新编译的原因。
源码interface CompiledActivePageBatch extends CompiledPageBatch来自
ActivePageCompilerSession.reset的完整页面批次,附带工作量计数。readonly metrics: ActivePageCompileMetrics源码
源码interface CompiledActivePageIncrementalBatch extends CompiledIncrementalPageBatch来自
ActivePageCompilerSession.update的增量批次,附带工作量计数。readonly metrics: ActivePageCompileMetrics源码
源码type CompiledActivePageUpdate = | CompiledActivePageIncrementalBatch | PageFullReloadRequired
源码interface ActivePageCompileMetrics有状态的活动页面编译器报告的确定性工作量计数。
readonly nodesInspected: number源码由经过校验的变更集和层级索引选出的规范节点。
readonly nodesCompiled: number源码从规范模型转换而来的选中节点。
readonly nodesReused: number源码保留给未经重新编译即被选中的已接受缓存记录。
readonly nodesUpserted: number源码编码进本批次的节点 upsert(插入或更新)命令。
readonly resourcesResolved: number源码本次编译期间执行的平台资源解析次数。
readonly resourcesRegistered: number源码编码进本批次的资源数据。
readonly resourcesRemoved: number源码readonly batchBytes: number源码
源码interface ActivePageAuditReportActivePageCompilerSession.auditAgainstColdCompilation的结果:缓存的记录是否与一次全新编译的结果一致,以及哪些记录不一致。readonly matchesColdCompilation: boolean源码readonly nodesInspected: number源码readonly mismatchedNodeIds: readonly NodeId[]源码readonly mismatchedResourceIds: readonly string[]源码
源码class RenderDocumentCompileError extends Error一种有意设置的边界错误;不受支持的模型数据绝不能悄无声息地消失。
readonly code: RenderDocumentCompileErrorCode源码readonly nodeId: NodeId | undefined源码new (code: RenderDocumentCompileErrorCode, message: string, nodeId?: NodeId)源码
源码type RenderDocumentCompileErrorCode = | "PAGE_NOT_FOUND" | "PAGE_ROOT_WITHOUT_SIZE" | "NODE_NOT_FOUND" | "UNSUPPORTED_NODE" | "UNSUPPORTED_STYLE" | "INVALID_MEDIA_CROP" | "MEDIA_ASSET_REQUIRED" | "FONT_ASSET_REQUIRED" | "FONT_BYTES_REQUIRED" | "RESOURCE_LIMIT" | "INVALID_COLOR" | "INSTANCE_UNRESOLVED"
源码function compileRetainedPaint( paint: Paint, nodeId: NodeId, label: string, document?: DesignDocument ): RetainedPaintRecord将一个规范绘制(paint)降级为其保留记录。图片绘制必须指向
document中的一个图片资源,因为宿主会通过媒体帧约定按资源 ID 附加其像素。
源码function parseRetainedColor(value: string, nodeId: NodeId): RgbaColor解析第一版共享 wire 格式所接受的确定性 CSS 颜色子集。
源码function fontSliceResourceId(assetId: string, sliceId: string): string按 Unicode 覆盖范围拆分的字体资源中某个文件的 wire 资源 ID。
源码function fontResourceAsset( document: DesignDocument, resourceId: string ): Asset | undefined某个 wire 字体资源编译自的文档资源。资源 ID 要么是资源 ID,要么是“google-fonts”资源或自动回退资源(见 automatic-font-fallback.ts)的
fontSliceResourceId(assetId, sliceId);两种形式冲突的文档会被编译器拒绝。
源码function textNodeCodePoints(node: TextualNode): Set<number>文本节点可能绘制的每个码点:其文本片段、显式列表标记, 以及生成的标记所用的字符(“•”和“1.”)。
源码const RETAINED_IDENTITY_TRANSFORM: Transform
Connectors
The page compiler draws a connector from its stored ends: an attached end goes on its layer’s edge where it faces the other end, spread apart from other connectors on the same side, and an elbow route goes around the other layers under the same parent. The editor asks for the same line, so a connector’s frame and end handles stay on what is drawn.
源码function connectorLineGeometry( document: DesignDocument, node: Extract<SceneNode, { type: "connector" }>, parentId: NodeId | undefined ): ConnectorLineGeometryThe line
nodedraws, routed exactly as the page compiler draws it: an attached end is placed on its layer’s edge where it faces the other end (spread apart from other automatic ends on the same side), and an elbow route goes around the other layers under the same parent. The editor uses it to keep a connector’s frame and end handles on the drawn line.parentIdis the connector’s parent. Throws the compiler’sRenderDocumentCompileErrorwhen an attachment cannot be drawn.
源码interface ConnectorLineGeometryThe line a connector draws, in the connector’s own coordinates.
readonly start: { readonly x: number; readonly y: number }源码Where the line starts, after an attached start is placed on its layer’s edge.
readonly end: { readonly x: number; readonly y: number }源码Where the line ends (an arrowhead’s tip), after an attached end is placed.
readonly bounds: { readonly x: number; readonly y: number; readonly width: number; readonly height: number; }源码The box around the whole line, bends and curves included, without stroke or end caps.
源码function connectorRoutePoints( node: Extract< SceneNode, { type: "connector"; } >, curveSteps = 24, document?: DesignDocument ): readonly { readonly x: number; readonly y: number }[]The route
nodedraws, as points along it in the connector’s own coordinates, from start to end: the corners of a bent route, and each curve split intocurveStepsstraight pieces. The line is not shortened for arrowheads. The editor draws a selected or hovered connector’s outline along it.With
document, an attached connector is routed as the page compiler draws it in that document (around the other layers, apart from other connectors), so pass the document the drawn scene shows. Without it, or for a connector with no attached end, the route runs between the stored ends (the line’s real ends once the editor has fitted the connector).
保留场景记录
页面编译器生成、编码器写入的记录,每个节点一条。它们是贴近 wire 格式的普通数据:颜色是 RGBA 数值,ID 是字符串,每个 Paint、描边和文本片段都完整写出。
源码type RetainedNodeRecord = | RetainedPathNode | RetainedTextNode | RetainedContainerNode | RetainedMediaNode
源码interface RetainedNodeBasereadonly id: string源码readonly parentId?: string源码readonly zOrder: number源码readonly visible: boolean源码readonly blendMode?: RetainedBlendMode源码wire 版本 10 通过一个隔离图层合成混合模式非 normal 的节点。 省略表示 normal。
readonly mask?: boolean源码wire 版本 10 允许节点为其后续同级节点充当蒙版:这些节点只保留在蒙版自身绘制 具有 alpha 的地方,而蒙版本身不绘制任何内容。隐藏的蒙版不遮挡任何内容。
readonly transform: Transform源码readonly style: RetainedNodeStyle源码
源码interface RetainedNodeStylereadonly opacity: number源码readonly fill?: RgbaColor源码紧凑的通用节点记录携带
fill。wire 版本 5 则可以改为在节点 upsert 中追加fills,以提供精确有序的绘制列表。这两种表示互斥。readonly fills?: readonly RetainedPaintRecord[]源码readonly strokes?: readonly RetainedStrokeRecord[]源码在填充之后绘制的有序描边,第一项位于最底层。 第一个描边使用紧凑的通用节点记录;wire 版本 7 将其余描边追加到外观尾部。
readonly shadows?: readonly RetainedShadowRecord[]源码wire 版本 6 追加有序的阴影;wire 版本 9 增加内阴影。
readonly layerBlur?: number源码wire 版本 9 追加一个高斯模糊半径,作为一个隔离图层应用于该节点及其后代。 为零或省略表示不模糊。
readonly backgroundBlur?: number源码wire 版本 9 追加一个高斯模糊半径,在节点的填充绘制之前, 应用于节点形状背后的内容。为零或省略表示无。
源码interface RetainedContainerNode extends RetainedNodeBasewire 版本 2 引入的与渲染器无关的层级与裁剪节点。
readonly kind: "container"源码readonly width: number源码readonly height: number源码readonly clip: boolean源码readonly cornerRadius?: number源码wire 版本 11 在半径为正时追加圆角半径和圆角平滑系数, 并在容器的第一个保留字节中加以标记。正的半径会让容器自身的绘制、 其内阴影、背景模糊和子元素裁剪都变为圆角;半径最大取短边的一半。 为零或省略表示直角。
readonly cornerRadii?: readonly [number, number, number, number]源码wire 版本 14 用标志位(位 2)表示四个独立的半径,顺序为左上、右上、右下、左下,后跟圆角平滑。每个半径被限制在较短边的一半以内。与非零的
cornerRadius互斥;编译器只在各半径不同时发送它。readonly cornerSmoothing?: number源码圆角平滑,从 0(圆弧)到 1(连续曲率)。每个平滑后的圆角最多占用
(1 + smoothing) * radius的边长,上限为短边的一半。为零或省略时保持圆弧。
源码interface RetainedPathNode extends RetainedNodeBasereadonly kind: "path"源码readonly vectorNetwork: VectorNetworkRecord源码readonly vertexCornerRadii?: readonly RetainedVertexCornerRadius[]源码wire 版本 12 为节点设置标志(第 2 位),并在网络记录之后追加此表。 只有恰好连接两条直线或三次曲线线段的顶点才会在绘制时变为圆角; 作者创建的顶点仍作为编辑和查询所用的几何。为空或省略表示尖角。
readonly strokeCaps?: RetainedStrokeCaps源码译文已过期
Wire version 13 flags the node (bit 4) and appends both caps after any vertex corner table. The start cap sits at the start vertex of the first segment and the end cap at the end vertex of the last one; both must be open chain ends. Omitted keeps round caps at every stroke end. Lines and connectors both send their end styles here; since wire version 22 heads point the way the line arrives across a triangle head’s length, and dashes get round ends while heads stay solid.
源码interface RetainedTextNode extends RetainedNodeBasereadonly kind: "text"源码readonly width: number源码readonly height: number源码readonly wrap: "none" | "word" | "character"源码readonly verticalAlign: "top" | "middle" | "bottom"源码readonly overflow: "clip" | "visible"源码readonly autoResize: "none" | "height" | "width-and-height"源码readonly styles: readonly RichTextStyleRecord[]源码readonly paragraphs: readonly RichTextParagraphRecord[]源码
源码interface RetainedMediaNode extends RetainedNodeBasewire 版本 4 引入的仅场景使用的媒体元数据。
readonly kind: "media"源码readonly mediaKind: "image" | "video"源码readonly fit: "contain" | "cover" | "fill"源码readonly width: number源码readonly height: number源码readonly assetId: string源码readonly crop?: { readonly x: number; readonly y: number; readonly width: number; readonly height: number; }源码
源码type Transform = readonly [ a: number, b: number, c: number, d: number, tx: number, ty: number ]一个仿射变换矩阵,布局
[a, b, c, d, tx, ty]与模型的TransformMatrix相同。它按 映射一个点。
源码type RgbaColor = readonly [ red: number, green: number, blue: number, alpha: number ]
源码type RetainedBlendMode = | "normal" | "darken" | "multiply" | "color-burn" | "lighten" | "screen" | "color-dodge" | "overlay" | "soft-light" | "hard-light" | "difference" | "exclusion" | "hue" | "saturation" | "color" | "luminosity"wire 版本 10 的混合模式,以 CSS
mix-blend-mode的术语表示。wire 代码 (按此顺序为 0 到 15)即 C++BlendMode的值。原生:
BlendMode
源码type RetainedPaintRecord = | RetainedSolidPaintRecord | RetainedLinearGradientPaintRecord | RetainedRadialGradientPaintRecord | RetainedAngularGradientPaintRecord | RetainedImagePaintRecord一个填充或描边绘制。wire 类型代码(solid 1、linear 2、radial 3、 angular 4、image 5)即 C++
PaintKind的值。原生:
PaintKind,RetainedPaint
源码interface RetainedPaintCompositingwire 版本 19 在 paint 头部的保留字节中携带两个按 paint 设置的字段:字节 1 是混合模式代码(与节点混合模式代码相同,0 表示正常),字节 2 存放标志,其中位 1 隐藏该 paint。两者取默认值时都省略。
渲染器跳过隐藏的 paint,但保留它在列表中的位置。
readonly blendMode?: RetainedBlendMode源码让该 paint 与同一节点上位于其下方的 paint 混合;正常模式时省略。只要有任何可见的 paint 设置了混合模式,节点的所有 paint 就会绘制到它们自己的图层中,因此混合不会影响节点后方的内容。
源码interface RetainedSolidPaintRecord extends RetainedPaintCompositingreadonly kind: "solid"源码readonly color: RgbaColor源码readonly opacity: number源码
源码interface RetainedLinearGradientPaintRecord extends RetainedPaintCompositingreadonly kind: "linear-gradient"源码readonly angle: number源码readonly stops: readonly { readonly offset: number; readonly color: RgbaColor; }[]源码readonly opacity: number源码
源码interface RetainedRadialGradientPaintRecord extends RetainedPaintCompositingwire 版本 8 新增以形状边界为参照的径向渐变和角度渐变。
readonly kind: "radial-gradient"源码readonly centerX: number源码中心点,以形状边界的比例表示。
readonly centerY: number源码readonly radiusX: number源码椭圆半径,以形状边界的比例表示;二者均为正数。
readonly radiusY: number源码readonly stops: readonly { readonly offset: number; readonly color: RgbaColor; }[]源码readonly opacity: number源码
源码interface RetainedAngularGradientPaintRecord extends RetainedPaintCompositingreadonly kind: "angular-gradient"源码readonly centerX: number源码readonly centerY: number源码readonly angle: number源码起始角度,单位为度,从正 x 轴开始按顺时针方向计算。
readonly stops: readonly { readonly offset: number; readonly color: RgbaColor; }[]源码readonly opacity: number源码
源码interface RetainedImagePaintRecord extends RetainedPaintCompositingwire 版本 8 新增图片绘制。像素通过与图片节点相同的媒体帧约定送达, 以逻辑资源 ID 为键。
readonly kind: "image"源码readonly assetId: string源码readonly fit: RetainedImagePaintFit源码readonly opacity: number源码
源码type RetainedImagePaintFit = "contain" | "cover" | "fill"图片绘制如何适配其形状。wire 代码(按此顺序为 0、1、2) 即 C++
MediaFit的值。原生:
MediaFit
源码interface RetainedStrokeRecordreadonly color: RgbaColor源码readonly width: number源码readonly position?: RetainedStrokePosition源码wire 版本 6 追加描边位置。省略它或指定为
center时, 保持紧凑的 wire v5 编码。readonly dash?: readonly number[]源码wire 版本 6 追加虚线间隔。长度为奇数的模式会重复成偶数长度的周期, 与 SVG 的 stroke-dasharray 一致。
readonly paint?: RetainedPaintRecord源码wire 版本 6 可以追加完整的描边绘制。省略时,
color仍是权威的纯色描边绘制。第一个之后的每个描边总是携带绘制, 因为只有第一个描边具有紧凑的颜色字段。readonly sides?: readonly [number, number, number, number]源码wire 版本 18 为容器的描边按边设置各自的粗细,顺序为上、右、下、左,由描边的第一个保留字节标记,并追加在虚线间隔之后。此时
width应保存最大的粗细,包围盒和命中测试都使用它。只有容器接受此字段。readonly join?: RetainedStrokeJoin源码Wire version 23 sets the stroke’s join, the ends of its dashes and its miter limit together, flagged in the stroke flags byte (bit 2) and appended after any side weights. Give all three or none. Without them a path strokes with round joins and round dash ends and a container with miter joins (limit 4) and flat dash ends, as before wire version 23. On a path with stroke caps,
dashCapsets only the dash ends; the path’s own ends take its caps. Side weights ignore the join.readonly dashCap?: RetainedDashCap源码Wire version 23: the ends of every dash; see
join.readonly miterLimit?: number源码Wire version 23: the longest a miter join may reach, as a multiple of half the stroke width, before it is beveled (SVG’s
stroke-miterlimit); at least 1. Only miter joins use it; seejoin.
源码type RetainedStrokePosition = "center" | "inside" | "outside"保留描边相对于形状边界的位置。wire 代码(按此顺序为 0、1、2) 即 C++
StrokePosition的值。原生:
StrokePosition
源码type RetainedStrokeCap = | "none" | "round" | "square" | "line-arrow" | "triangle-arrow" | "reversed-triangle" | "circle-arrow" | "diamond-arrow"wire 版本 13 的描边端点,采用 Figma 的术语。wire 代码(按此顺序为 0 到 7) 即 C++
StrokeCap的值。原生:
StrokeCap
源码interface RetainedStrokeCapsreadonly start: RetainedStrokeCap源码readonly end: RetainedStrokeCap源码
源码type RetainedStrokeJoin = "miter" | "bevel" | "round"Wire version 23 stroke joins. The wire codes (0 to 2 in this order) are the C++
StrokeJoinvalues.原生:
StrokeJoin
源码type RetainedDashCap = "none" | "round" | "square"Wire version 23 dash ends. The wire codes (0 to 2 in this order) are the C++
DashCapvalues.原生:
DashCap
源码interface RetainedShadowRecord
源码interface RetainedVertexCornerRadiuswire 版本 12:路径中的一个圆角顶点,由稳定的顶点 ID 指定。
readonly vertexId: string源码readonly radius: number源码正数;渲染器会将其限制为较短的相邻线段长度的一半。
源码interface VectorNetworkRecordreadonly vertices: readonly VectorVertexRecord[]源码readonly segments: readonly VectorSegmentRecord[]源码readonly constraints?: readonly VectorTangentConstraintRecord[]源码readonly regions: readonly VectorRegionRecord[]源码
源码interface VectorVertexRecordreadonly id: string源码readonly x: number源码readonly y: number源码
源码interface VectorHandleRecordreadonly id: string源码readonly dx: number源码readonly dy: number源码
源码type VectorSegmentRecord = | VectorLineSegmentRecord | VectorCubicSegmentRecord | VectorEllipticalArcSegmentRecord
源码interface VectorLineSegmentRecordreadonly id: string源码readonly kind: "line"源码readonly start: string源码readonly end: string源码
源码interface VectorCubicSegmentRecordreadonly id: string源码readonly kind: "cubic"源码readonly start: string源码readonly end: string源码readonly startHandle: VectorHandleRecord源码readonly endHandle: VectorHandleRecord源码
源码interface VectorEllipticalArcSegmentRecord为迁移和 SVG 交换而保留的精确兼容几何。
readonly id: string源码readonly kind: "elliptical-arc"源码readonly start: string源码readonly end: string源码readonly radiusX: number源码readonly radiusY: number源码readonly xAxisRotation: number源码readonly largeArc: boolean源码readonly sweep: boolean源码
源码interface VectorRegionRecordreadonly id: string源码readonly windingRule: "nonzero" | "evenodd"源码readonly loops: readonly VectorRegionLoopRecord[]源码readonly fills?: readonly RetainedPaintRecord[]源码省略时继承路径的填充;空列表则明确禁用此区域的填充。
源码interface VectorRegionLoopRecordreadonly segments: readonly VectorSegmentReferenceRecord[]源码readonly implicitClose?: true源码
源码interface VectorSegmentReferenceRecordreadonly segmentId: string源码readonly direction: "forward" | "reverse"源码
源码interface VectorTangentConstraintRecordreadonly vertexId: string源码readonly handleIds: readonly [string, string]源码readonly mode: "angle" | "angle-and-length"源码
源码interface RichTextStyleRecordreadonly fontResourceIds: readonly string[]源码首先是主字体,其后是确定性的整形回退字体。
readonly language?: string源码readonly fontSize: number源码readonly lineHeight: number源码渲染器空间中的绝对行高;不同样式可以使用不同的值。
readonly letterSpacing: number源码readonly weight: number源码readonly italic?: boolean源码readonly underline?: boolean源码readonly strikethrough?: boolean源码readonly color: RgbaColor源码readonly openTypeFeatures?: Readonly<Record<string, boolean | number>>源码readonly fontVariations?: Readonly<Record<string, number>>源码
源码interface RichTextParagraphRecordreadonly direction: "auto" | "ltr" | "rtl"源码readonly align: "left" | "center" | "right" | "justify"源码readonly spacingBefore: number源码readonly spacingAfter: number源码readonly indent?: { readonly left: number; readonly right: number; readonly firstLine: number; }源码readonly list?: { readonly kind: "ordered" | "unordered"; readonly level: number; readonly start?: number; readonly marker?: { readonly text?: string; readonly styleIndex?: number; readonly gap?: number; }; }源码readonly runs: readonly RichTextRunRecord[]源码空段落以及携带样式的空文本片段都会保留。
源码interface RichTextRunRecord
源码type ResourceKind = "font" | "image" | "blob"已注册资源的类型。wire 代码(font 1、image 2、blob 3) 即 C++
ResourceKind的值。原生:
ResourceKind
变更批次与 wire 协议
变更批次由一个头部和随后的命令组成,例如“upsert path”或“remove node”。C++ 会话要么完整应用一个批次,要么完全不应用。独立的矢量网络载荷使用另一个冻结的版本,用于叠加层和布尔运算结果。
源码class RenderChangeBatchEncoder构建一个保留场景的变更批次:20 字节的头部(魔数
TCR1、RENDER_CORE_WIRE_VERSION、各项大小和命令数),后跟若干命令。 每个方法追加一条命令并返回编码器,因此可以链式调用;finish返回字节。每个值在添加时都会按WIRE_LIMITS和节点规则进行检查,因此错误的节点会在这里抛出,而不是在渲染器中。 字节布局见PROTOCOL.md。渲染器通过
RenderCoreSession.apply应用批次,它会调用taco_render_session_apply。RetainedSession.apply使用WireReader读取批次,并且要么应用全部命令,要么一条都不应用。原生:
taco_render_session_apply,RetainedSession.apply,WireReaderresetScene(width: number, height: number, clearResources = true): this源码移除所有节点,并以文档单位设置场景大小。启用
clearResources(默认)时,还会移除所有资源。resizeScene(width: number, height: number): this源码更改场景大小,保留所有节点和资源。编辑器的场景就是以文档单位表示的视口, 因此缩放会调整场景大小;若改用重置,则会白白丢弃已编译的场景和所有绘制缓存。
registerResource(id: string, kind: ResourceKind, bytes: Uint8Array): this源码在
id下添加或替换一个资源,例如字体文件。removeResource(id: string): this源码移除一个资源。
upsertPath(node: RetainedPathNode): this源码添加或替换一个路径节点:包括其矢量网络、样式、圆角半径和端点。
upsertText(node: RetainedTextNode): this源码添加或替换一个文本节点及其样式和段落。
upsertContainer(node: RetainedContainerNode): this源码添加或替换一个画框或编组:包括大小、裁剪和圆角半径。
upsertMedia(node: RetainedMediaNode): this源码添加或替换一个图片或视频节点。其像素以媒体帧的形式送达。
removeNode(id: string): this源码移除一个节点及其所有后代。
setTransform(id: string, transform: RetainedNodeBase["transform"]): this源码仅更改现有节点的变换。
finish(): Uint8Array源码写入批次头部,并返回完整的批次字节。
源码const WIRE_LIMITS: Readonly< { batchBytes: number; commands: 100000; identifierBytes: 1024; textBytes: number; nodes: 100000; resources: 4096; resourceBytes: number; batchResourceBytes: number; retainedPayloadBytes: number; vectorVertices: 1000000; vectorSegments: 1000000; vectorConstraints: 1000000; vectorRegions: 100000; vectorLoops: 1000000; vectorReferences: 3000000; regionPaints: 100000; nodePaints: 100000; gradientStops: 1000000; textStyles: 65536; textParagraphs: 65536; textRuns: 65536; fontFallbacks: 4096; fontFallbackReferences: 65536; openTypeSettings: 256; strokeDashIntervals: 64; shadows: 16; nodeStrokes: 16; } >单个变更批次和整个保留场景的大小与数量限制。编码器会在写入超出限制之前抛出
RangeError,C++ 读取器也会拒绝任何超出相同限制的批次(即session.h中的kMaximum*常量)。retainedPayloadBytes限制整个场景: 节点、标识符、矢量和文本数据以及资源。
源码const RENDER_CORE_WIRE_VERSION: 24RenderChangeBatchEncoder写出的变更批次版本。
源码const RENDER_CHANGE_COMMAND_HEADER_BYTES: 8每个命令头的大小:
u8操作码、三个保留字节、u32载荷长度。
源码const RENDER_CORE_VECTOR_NETWORK_WIRE_VERSION: 5无头部的独立
VectorNetwork载荷所用的固定 wire 版本。
源码function encodeVectorNetworkRecord(network: VectorNetworkRecord): Uint8Array为临时原生叠加层和布尔运算结果编码一个独立的
VectorNetwork数据。它的冻结版本为RENDER_CORE_VECTOR_NETWORK_WIRE_VERSION,与当前批次版本无关。它刻意不带批次头或命令头,并使用与保留路径命令相同的校验、边界、规范顺序和绘制表示。C++ 端用decodeVectorNetwork读取它。
源码function decodeVectorNetworkRecord(bytes: Uint8Array): VectorNetworkRecord解码恰好一个规范的独立
VectorNetwork,例如 C++ 端用encodeVectorNetwork写出的布尔运算结果。该数据必须能经共享编码器逐字节往返一致,从而保证布尔查询结果不会与保留路径和矢量叠加层的 wire 语义产生偏差。
Wire 版本历史
场景 wire 格式版本的每次提升,最新的在前,并附上做出该改动的提交。
| 版本 | 提交标题 | 引入于 |
|---|---|---|
24 | fix(render-core): tight paint bounds for lines/connectors; exports cover everything a layer and its children paint | d00b191 #121 2026-10-04 |
23 | feat(web): Stroke settings panel with dashes, end points and joins, and round Pencil strokes | dad417a #88 2026-09-28 |
22 | feat(web): add connectors: Connector tool, key-point attach points, pinned and re-attachable ends, and line end styles | f6199e2 #73 2026-09-28 |
21 | feat(web): transform a multi-selection through one box, as in Figma | b833870 #72 2026-09-27 |
20 | refactor(render-core): paint transform handles with the size and angle the editor sends | 0d6ea45 #71 2026-09-27 |
19 | feat(model): hide paints and give each paint a blend mode | c753479 #59 2026-09-26 |
18 | feat(model): give each rectangle and frame stroke its own side weights | 7382f68 #55 2026-09-26 |
17 | feat(web): auto layout gap and padding handles on the canvas, drawn by the renderer | a292d32 #67 2026-09-26 |
16 | feat(web): draw the rulers in the renderer and hit-test rulers and guides | 7b2e247 #64 2026-09-26 |
15 | feat(web): draw frame titles in the renderer and hit-test them to select, move and rename frames | 555ae8d #62 2026-09-26 |
14 | feat(model): round each corner of rectangles and frames on its own | e6739c6 #54 2026-09-26 |
13 | feat: draw lines, arrows, ellipses, polygons and stars | 4c61909 #20 2026-09-23 |
12 | feat(render-core): round vector vertices with per-vertex corner radii | 837342a 2026-09-18 |
11 | feat(render-core): support corner smoothing and rounded frames | a9795ca 2026-09-17 |
10 | feat(render-core): support blend modes and sibling masks | b90c0f5 2026-09-17 |
9 | feat(render-core): support inner shadows, layer blur, and background blur | ebc9460 2026-09-17 |
8 | feat(render-core): support radial, angular, and image paints | 142ea63 2026-09-17 |
7 | feat(render-core): support multiple strokes per node | d037d4d 2026-09-17 |
6 | feat(render-core): support positioned strokes | 9bac561 2026-08-18 |
5 | feat(render-core): add wire-v5 retained styling | 5aa0d67 2026-08-12 |
4 | feat(render-core): retain media scene metadata | d4dee2d 2026-08-12 |
3 | feat(renderer): retain rich text in wire v3 | 4a4a289 2026-08-10 |
2 | feat(renderer): add interactive C++ foundation | 5e38c7a 2026-08-10 |
来自对 RENDER_CORE_WIRE_VERSION 执行的 git log -S。文字是提升该版本的提交的标题(英文)。
Wasm 模块与会话
RenderCoreModule 和 RenderCoreSession 是与具体渲染器无关的会话接口;可移植 Wasm 门面(facade)基于 C ABI 实现它们。不含 Skia 的构建使用 createPortableWasmRenderCore;在同样负责绘制的构建中额外创建会话使用 createOwnedWasmRenderCoreSession;封装由其他后端持有的会话则使用 attachPortableWasmRenderCoreSession。
源码interface RenderCoreModule一个可以创建会话的已加载渲染器构建。
readonly capabilities: RenderCoreCapabilities源码此构建支持的功能。
createSession(): RenderCoreSession源码创建一个场景为空的会话。
原生:
taco_render_session_destroy原生(在辅助函数中):
taco_render_session_create
源码interface RenderCoreSession在编辑器契约背后使用的底层同步 wire / C ABI 会话。
一个会话持有一个保留场景。每个方法都是对一个 C 函数的薄封装。 接受
expectedGeneration的查询在场景自该代之后发生过变化时会失败, 因此过时的结果不会被误当作当前结果。节点或资源不存在时,查询返回undefined。PortableWasmRenderCoreSession是其 Wasm 实现。apply(batch: Uint8Array): RenderUpdateReport源码应用一个来自
RenderChangeBatchEncoder的变更批次。批次要么完全应用, 要么完全不应用;被拒绝的批次会抛出异常。原生(在辅助函数中):
taco_render_session_get_last_dirty_bounds,taco_render_session_copy_last_errorapplyWithStaticImageFrames( batch: Uint8Array, expectedGeneration: bigint, frames: readonly RenderStaticImageFrame[] ): RenderUpdateReport源码原子地发布批次以及候选代的精确静态图片集合。
原生:
taco_render_session_apply_with_static_image_frames原生(在辅助函数中):
taco_render_session_get_last_dirty_bounds,taco_render_session_copy_last_errorapplyWithMediaFrames( batch: Uint8Array, expectedGeneration: bigint, frames: readonly RenderMediaFrame[] ): RenderUpdateReport源码原子地发布批次及其精确的图片 / 视频混合帧集合。
原生:
taco_render_session_apply_with_media_frames原生(在辅助函数中):
taco_render_session_get_last_dirty_bounds,taco_render_session_copy_last_errorupdateVideoFrames( expectedGeneration: bigint, frames: readonly RenderVideoFrame[] ): RenderUpdateReport源码仅替换视频帧,同时保持场景标识完全不变。
原生:
taco_render_session_update_video_frames原生(在辅助函数中):
taco_render_session_get_scene_info,taco_render_session_copy_last_errorgetSceneInfo(): RenderSceneInfo源码场景大小、计数、代和摘要。
原生:
taco_render_session_get_scene_info原生(在辅助函数中):
taco_render_session_copy_last_errorgetNodeGeometry(id: string): RenderNodeGeometry | undefined源码一个节点的边界和变换。
原生:
taco_render_session_get_node_geometry原生(在辅助函数中):
taco_render_session_copy_last_errorgetGeometrySnapshot(): RenderGeometrySnapshot源码所有节点的几何信息,按从后到前的顺序排列。
原生:
taco_render_session_get_geometry_snapshot原生(在辅助函数中):
taco_render_session_copy_last_errorhitTest(x: number, y: number, worldTolerance?: number): readonly RenderHit[]源码使用显式的世界空间容差,按从上到下的顺序返回几何命中结果。
原生:
taco_render_session_hit_test原生(在辅助函数中):
taco_render_session_copy_last_errorgetTextCarets( nodeId: string, expectedGeneration?: bigint ): RenderTextCaretSnapshot | undefined源码文本节点中的每个光标位置及其几何信息。
原生:
taco_render_session_get_text_carets原生(在辅助函数中):
taco_render_session_get_scene_info,taco_render_session_copy_last_errorgetTextRangeGeometry( nodeId: string, range: RenderTextRange, expectedGeneration?: bigint ): RenderTextRangeGeometry | undefined源码覆盖某个文本范围的矩形,每行一个或多个。
原生:
taco_render_session_get_text_range_rects原生(在辅助函数中):
taco_render_session_get_scene_info,taco_render_session_copy_last_errorhitTestText( nodeId: string, localX: number, localY: number, expectedGeneration?: bigint ): RenderTextHitResult | undefined源码在节点局部坐标中距某点最近的文本位置。
原生:
taco_render_session_hit_test_text原生(在辅助函数中):
taco_render_session_get_scene_info,taco_render_session_copy_last_error将文本位置移动一个光标步长。上下跨行移动时,
preferredLocalX用于保持所在列。原生:
taco_render_session_navigate_text原生(在辅助函数中):
taco_render_session_get_scene_info,taco_render_session_copy_last_errorgetTextLayoutMetrics( nodeId: string, expectedGeneration?: bigint ): RenderTextLayoutMetrics | undefined源码文本节点的行度量以及建议的自动尺寸。
原生:
taco_render_session_get_text_layout_metrics原生(在辅助函数中):
taco_render_session_get_scene_info,taco_render_session_copy_last_errorgetFontMetadata( fontResourceId: string, expectedGeneration?: bigint ): RenderFontMetadataSnapshot | undefined源码-
原生:
taco_render_session_get_font_metadata原生(在辅助函数中):
taco_render_session_get_scene_info,taco_render_session_copy_last_error setTextEditingOverlay( nodeId: string, overlay: RenderTextEditingOverlay, expectedGeneration?: bigint ): void源码绘制正在编辑的文本节点的选区、输入法组合范围和光标。 下一次场景变更会将其清除。
原生:
taco_render_session_set_text_editing_overlay原生(在辅助函数中):
taco_render_session_get_scene_info,taco_render_session_copy_last_errorclearTextEditingOverlay(expectedGeneration?: bigint): void源码移除文本编辑叠加层。
原生:
taco_render_session_clear_text_editing_overlay原生(在辅助函数中):
taco_render_session_get_scene_info,taco_render_session_copy_last_errorsetSelectionChrome(chrome: RenderSelectionChrome | null): boolean源码替换渲染器绘制在场景之上的选区轮廓和控制柄,或传入
null将其清除。 若已加载的模块早于原生选区框与控制柄的实现,则返回false,由宿主继续使用自己的实现。原生:
taco_render_session_set_selection_chrome原生(在辅助函数中):
taco_render_session_copy_last_error原生,经由
encodeSelectionChrome:taco_render_session_set_selection_chrome,SessionCache.setSelectionChromesetCanvasOverlay(overlay: RenderCanvasOverlay | null): void源码替换渲染器绘制在场景之上的叠加层线条,或传入
null将其清除。 已加载的模块无法绘制这些线条时会抛出异常。原生:
taco_render_session_set_canvas_overlay原生(在辅助函数中):
taco_render_session_copy_last_error原生,经由
encodeCanvasOverlay:taco_render_session_set_canvas_overlay,SessionCache.setCanvasOverlaysetCanvasOverlayFont(bytes: Uint8Array): boolean源码设置画布叠加层中画框标题所用的字体文件(TrueType、OpenType 或 WOFF2 字节)。已加载的模块无法绘制标题时返回
false。原生:
taco_render_session_set_canvas_overlay_font原生(在辅助函数中):
taco_render_session_copy_last_errorgetVectorGeometry( nodeId: string, documentToScreen: Transform, expectedGeneration?: bigint ): RenderVectorGeometrySnapshot | undefined源码矢量节点的顶点、控制柄、线段和区域,以及由
documentToScreen得出的屏幕位置。原生:
taco_render_session_get_vector_geometry原生(在辅助函数中):
taco_render_session_get_scene_info,taco_render_session_copy_last_error原生,经由
decodeWasmVectorGeometry:TacoRenderVectorVertex,TacoRenderVectorCubicHandle,TacoRenderVectorSegment,TacoRenderVectorRegionhitTestVector( nodeId: string, query: RenderVectorHitQuery, expectedGeneration?: bigint ): RenderVectorHitSnapshot | undefined源码屏幕上某点附近的矢量顶点、控制柄、线段和区域。
原生:
taco_render_session_hit_test_vector原生(在辅助函数中):
taco_render_session_get_scene_info,taco_render_session_copy_last_errorbooleanVectorPaths( request: RenderVectorBooleanPathRequest, expectedGeneration?: bigint ): RenderVectorBooleanPathSnapshot源码合并两个节点的路径,并返回结果矢量网络。
原生:
taco_render_session_boolean_vector_paths原生(在辅助函数中):
taco_render_session_get_scene_info,taco_render_session_copy_last_errorsetVectorEditingOverlay( nodeId: string, overlay: RenderVectorEditingOverlay, expectedGeneration?: bigint ): void源码绘制一个节点的矢量编辑叠加层(顶点、控制柄和选区)。 下一次场景变更会将其清除。
原生:
taco_render_session_set_vector_editing_overlay原生(在辅助函数中):
taco_render_session_get_scene_info,taco_render_session_copy_last_errorclearVectorEditingOverlay(expectedGeneration?: bigint): void源码移除矢量编辑叠加层。
原生:
taco_render_session_clear_vector_editing_overlay原生(在辅助函数中):
taco_render_session_get_scene_info,taco_render_session_copy_last_errormapViewport(options: ViewportMappingOptions): ViewportMapping源码计算场景如何适配给定大小的视口。
原生:
taco_render_session_map_viewport原生(在辅助函数中):
taco_render_session_copy_last_errorrender(target: RgbaRenderTarget): RenderFrameReport源码将场景绘制到 RGBA 像素缓冲区中。没有 CPU 光栅后端的构建(例如可移植的 Wasm 构建)会抛出异常。
原生:
taco_render_session_render_rgba原生(在辅助函数中):
taco_render_session_copy_last_errorgetLastError(): string源码复制会话持有的诊断字符串;不会有原生内存泄露到外部。
原生(在辅助函数中):
taco_render_session_copy_last_errordispose(): void源码释放会话。之后的调用会抛出异常。
源码interface RenderCoreCapabilities已加载的渲染器构建支持的功能,从 C 能力结构体中读取。 调用对应的会话方法之前,先用
requireRenderCapability检查标志。原生:
TacoRenderCapabilities,TacoRenderExtendedCapabilitiesreadonly abiVersion: number源码readonly wireVersion: number源码保留场景 / 变更批次的 wire 版本。
readonly vectorNetworkWireVersion: number源码叠加层和布尔运算结果使用的无头部
VectorNetwork载荷版本。readonly retainedScene: boolean源码readonly structuredPaths: boolean源码readonly styledTextRecords: boolean源码readonly embeddedResources: boolean源码readonly skia: boolean源码readonly nativeRaster: boolean源码readonly wasm: boolean源码readonly webgpu: boolean源码readonly skparagraph: boolean源码readonly harfbuzz: boolean源码readonly icu: boolean源码readonly geometryQueries: boolean源码readonly hitTesting: boolean源码readonly dirtyBounds: boolean源码readonly textCarets: boolean源码readonly textRangeRects: boolean源码readonly textHitTesting: boolean源码readonly textLayoutMetrics: boolean源码readonly textEditingOverlays: boolean源码readonly fontMetadata: boolean源码readonly incrementalRendering: boolean源码readonly renderDiagnostics: boolean源码readonly staticImageFrames: boolean源码readonly videoFrames: boolean源码readonly vectorGeometry: boolean源码readonly vectorHitTesting: boolean源码readonly vectorEditingOverlays: boolean源码readonly vectorBooleanOperations: boolean源码
源码type RequiredRenderCapability = | "skia" | "nativeRaster" | "wasm" | "webgpu" | "skparagraph" | "harfbuzz" | "icu" | "textCarets" | "textRangeRects" | "textHitTesting" | "textNavigation" | "textLayoutMetrics" | "textEditingOverlays" | "fontMetadata" | "incrementalRendering" | "renderDiagnostics" | "staticImageFrames" | "videoFrames" | "vectorGeometry" | "vectorHitTesting" | "vectorEditingOverlays" | "vectorBooleanOperations"requireRenderCapability可以检查的能力标志。
源码function requireRenderCapability( capabilities: RenderCoreCapabilities, capability: RequiredRenderCapability ): void除非
capabilities具有该标志,否则抛出RenderCoreCapabilityError。
源码class RenderCoreCapabilityError extends Error当构建缺少某项能力时,由
requireRenderCapability抛出。readonly capability: RequiredRenderCapability源码new (capability: RequiredRenderCapability)源码
源码function createPortableWasmRenderCore( module: PortableWasmExports, options: PortableWasmFacadeOptions = {} ): PortableWasmRenderCoreModule包装一个已加载的可移植 Wasm 模块;参见
PortableWasmRenderCoreModule。
源码class PortableWasmRenderCoreModule implements RenderCoreModule基于可移植 Wasm 构建(不含 Skia)的
RenderCoreModule。构造函数会检查模块的导出以及 ABI 和 wire 版本,并拒绝带有渲染器的模块;这类模块请使用createOwnedWasmRenderCoreSession。readonly capabilities: RenderCoreCapabilities源码new (module: PortableWasmExports, options: PortableWasmFacadeOptions = {})源码原生(在辅助函数中):
taco_render_wasm_abi_version,taco_render_wasm_wire_version,taco_render_wasm_vector_network_wire_version,taco_render_wasm_portable_capabilities,taco_render_get_capabilities,taco_render_get_extended_capabilitiescreateSession(): PortableWasmRenderCoreSession源码原生:
taco_render_session_destroy原生(在辅助函数中):
taco_render_session_create
源码function createOwnedWasmRenderCoreSession( module: PortableWasmExports, options: PortableWasmFacadeOptions = {} ): PortableWasmRenderCoreSession在同样带有渲染器的模块(例如 Skia WebGPU 构建)中创建第二个由门面拥有的会话。
createPortableWasmRenderCore会拒绝这类模块,因为它要认证的是不含 Skia 的基础模块;此入口只跳过这项认证。释放该门面会销毁原生会话。原生:
taco_render_session_destroy原生(在辅助函数中):
taco_render_wasm_abi_version,taco_render_wasm_wire_version,taco_render_wasm_vector_network_wire_version,taco_render_wasm_portable_capabilities
源码function attachPortableWasmRenderCoreSession( module: PortableWasmExports, session: number, options: PortableWasmFacadeOptions = {} ): PortableWasmRenderCoreSession将共享的严格 Wasm C ABI 门面(facade)附加到一个生命周期由渲染器后端管理的会话上。释放该门面只会释放它的暂存内存;原生会话句柄仍由后端负责。
原生(在辅助函数中):
taco_render_wasm_abi_version,taco_render_wasm_wire_version,taco_render_wasm_vector_network_wire_version,taco_render_wasm_portable_capabilities,taco_render_get_capabilities,taco_render_get_extended_capabilities
源码interface PortableWasmRenderCoreSession extends RenderCoreSessionRenderCoreSession的 Wasm 实现。每个方法都会将输入复制到 Wasm 内存中,调用一个taco_render_session_*函数,严格检查结果,再把输出复制回来,因此不会有 Wasm 内存泄露到外部。readonly capabilities: RenderCoreCapabilities源码已加载模块支持哪些功能。
readonly transferMetrics: WasmBatchStagingMetrics源码用于将批次传入 Wasm 内存的复用缓冲区的计数器。
exportScene(request: RenderExportRequest): RenderExportResult源码-
原生:
taco_render_session_export,taco_render_session_copy_export_bytes原生(在辅助函数中):
taco_render_session_copy_last_error outlineStroke( request: RenderStrokeOutlineRequest, expectedGeneration?: bigint, budget?: StrokeOutlineBudget ): RenderStrokeOutlineSnapshot | undefined源码One stroke of a path or container node as the filled shape it paints (see
RenderStrokeOutlineSnapshot), orundefinedwhen the node does not exist. ThrowsPortableWasmStatusErrorwhen the node has no such stroke, is a text or media node, or the stroke cannot be outlined; itsdetailis the renderer’s reason. Throws a plain error when the renderer build predates the query. With abudget, the outline’s size on the wire is charged to it before the outline is copied out and decoded; one that does not fit throwsStrokeOutlineBudgetError.原生:
taco_render_session_outline_stroke原生(在辅助函数中):
taco_render_session_get_scene_info,taco_render_session_copy_last_error
源码interface PortableWasmFacadeOptions extends WasmBatchStagingOptions可选的上限,限制单次查询可向模块申请的内存量。每个值都必须为正数,且不超过门面内置的最大值。
readonly maximumQueryRecords?: number源码readonly maximumTextQueryRecords?: number源码readonly maximumQueryIdentifierBytes?: number源码readonly maximumVectorQueryRecords?: number源码readonly maximumVectorIdentifierBytes?: number源码readonly maximumErrorBytes?: number源码
源码interface PortableWasmExports extends WasmBatchMemory门面所需的 Emscripten 模块接口:Wasm 堆、
malloc和free,以及导出的taco_render_*C 函数(Emscripten 会给每个函数加上下划线前缀)。_taco_render_get_capabilities(capabilities: number): number源码_taco_render_get_extended_capabilities( version: number, capabilities: number ): number源码_taco_render_session_create(options: number, sessionOutput: number): number源码_taco_render_session_destroy(session: number): void源码_taco_render_session_apply( session: number, batch: number, batchSize: number, report: number ): number源码_taco_render_session_apply_with_static_image_frames( session: number, batch: number, batchSize: number, frameSet: number, report: number ): number源码_taco_render_session_apply_with_media_frames( session: number, batch: number, batchSize: number, frameSet: number, report: number ): number源码_taco_render_session_update_video_frames( session: number, frameSet: number, dirtyBounds: number ): number源码_taco_render_session_get_scene_info(session: number, info: number): number源码_taco_render_session_get_node_geometry( session: number, nodeId: number, nodeIdSize: number, geometry: number ): number源码_taco_render_session_get_geometry_snapshot( session: number, records: number, recordCapacity: number, nodeIds: number, nodeIdCapacity: number, generation: number, recordCount: number, nodeIdByteCount: number ): number源码_taco_render_session_hit_test( session: number, worldX: number, worldY: number, worldTolerance: number, hits: number, hitCapacity: number, nodeIds: number, nodeIdCapacity: number, hitCount: number, nodeIdByteCount: number ): number源码_taco_render_session_get_last_dirty_bounds( session: number, dirtyBounds: number ): number源码_taco_render_session_get_text_carets( session: number, nodeId: number, nodeIdSize: number, query: number, carets: number, caretCapacity: number, result: number ): number源码_taco_render_session_get_text_range_rects( session: number, nodeId: number, nodeIdSize: number, query: number, rects: number, rectCapacity: number, result: number ): number源码_taco_render_session_hit_test_text( session: number, nodeId: number, nodeIdSize: number, query: number, result: number ): number源码_taco_render_session_get_text_layout_metrics( session: number, nodeId: number, nodeIdSize: number, query: number, metrics: number ): number源码_taco_render_session_get_font_metadata( session: number, fontResourceId: number, fontResourceIdSize: number, query: number, features: number, featureCapacity: number, axes: number, axisCapacity: number, result: number ): number源码_taco_render_session_set_text_editing_overlay( session: number, nodeId: number, nodeIdSize: number, overlay: number ): number源码_taco_render_session_clear_text_editing_overlay( session: number, query: number ): number源码_taco_render_session_set_selection_chrome?( session: number, bytes: number, size: number ): number源码在原生选区框与控制柄之前构建的模块中不存在。
_taco_render_session_set_canvas_overlay?( session: number, bytes: number, size: number ): number源码在原生叠加层线条之前构建的模块中不存在。
_taco_render_session_set_canvas_overlay_font?( session: number, bytes: number, size: number ): number源码在画布叠加层支持画框标题之前构建的模块中不存在。
_taco_render_session_get_vector_geometry( session: number, nodeId: number, nodeIdSize: number, query: number, vertices: number, vertexCapacity: number, handles: number, handleCapacity: number, segments: number, segmentCapacity: number, regions: number, regionCapacity: number, identifiers: number, identifierCapacity: number, result: number ): number源码Absent from modules built before wire version 24.
_taco_render_session_hit_test_vector( session: number, nodeId: number, nodeIdSize: number, query: number, hits: number, hitCapacity: number, identifiers: number, identifierCapacity: number, result: number ): number源码_taco_render_session_set_vector_editing_overlay( session: number, nodeId: number, nodeIdSize: number, overlay: number, networkBytes: number, networkByteCount: number, components: number, componentCount: number, identifiers: number, identifierByteCount: number ): number源码_taco_render_session_clear_vector_editing_overlay( session: number, query: number ): number源码_taco_render_session_boolean_vector_paths( session: number, primaryNodeId: number, primaryNodeIdSize: number, secondaryNodeId: number, secondaryNodeIdSize: number, resultIdNamespace: number, resultIdNamespaceSize: number, query: number, networkBytes: number, networkCapacity: number, result: number ): number源码_taco_render_session_map_viewport( session: number, options: number, mapping: number ): number源码_taco_render_session_render_rgba(session: number, target: number): number源码_taco_render_session_render_rgba_incremental( session: number, target: number, options: number, report: number ): number源码_taco_render_session_export?( session: number, request: number, result: number ): number源码可选:在场景导出功能之前的构建中,两个导出入口都不存在。
_taco_render_session_copy_export_bytes?( session: number, destination: number, destinationSize: number ): number源码_taco_render_session_copy_last_error( session: number, destination: number, destinationSize: number ): number源码_taco_render_wasm_abi_version(): number源码_taco_render_session_outline_stroke?( session: number, nodeId: number, nodeIdSize: number, resultIdNamespace: number, resultIdNamespaceSize: number, query: number, networkBytes: number, networkCapacity: number, result: number ): number源码Absent from renderer builds made before stroke outlines; no capability flag announces it, so
outlineStrokechecks for the export._taco_render_wasm_vector_network_wire_version(): number源码_taco_render_wasm_wire_version(): number源码_taco_render_wasm_portable_capabilities(): number源码
源码class PortableWasmAbiError extends ErrorWasm 模块违反了 C ABI 约定:缺少导出、版本错误,或结果中的大小、保留字节或值不正确。
new (message: string)源码
源码class PortableWasmStatusError extends Errorreadonly operation: string源码readonly status: RenderCoreStatus源码readonly statusName: string源码readonly detail: string源码new (operation: string, status: RenderCoreStatus, detail = "")源码
源码const RENDER_CORE_STATUS: Readonly< { readonly ok: 0; readonly invalidArgument: 1; readonly unsupportedVersion: 2; readonly malformedBatch: 3; readonly limitExceeded: 4; readonly invalidScene: 5; readonly notFound: 6; readonly capabilityUnavailable: 7; readonly bufferTooSmall: 8; readonly internalError: 9; readonly staleGeneration: 10; } >每个 C 函数返回的状态码,按名称列出。其值为
TacoRenderStatus常量。原生:
TacoRenderStatus
源码type RenderCoreStatus = (typeof RENDER_CORE_STATUS)[keyof typeof RENDER_CORE_STATUS]一个
RENDER_CORE_STATUS值。
源码const RENDER_CORE_ABI_VERSION: 1
源码const PORTABLE_WASM_ABI_LAYOUT: Readonly< { readonly capabilitiesBytes: 28; readonly sessionOptionsBytes: 32; readonly updateReportBytes: 32; readonly sceneInfoBytes: 48; readonly nodeGeometryBytes: 216; readonly geometryRecordBytes: 184; readonly dirtyBoundsBytes: 112; readonly hitRecordBytes: 64; readonly viewportOptionsBytes: 40; readonly viewportMappingBytes: 136; readonly rgbaTargetBytes: 24; readonly staticImageFrameBytes: 56; readonly staticImageFrameSetBytes: 24; readonly extendedCapabilitiesBytes: 88; readonly textQueryBytes: 16; readonly textPositionBytes: 16; readonly textCaretBytes: 56; readonly textBufferResultBytes: 16; readonly textRangeQueryBytes: 48; readonly textRectBytes: 40; readonly textHitQueryBytes: 32; readonly textHitResultBytes: 32; readonly textNavigationQueryBytes: 48; readonly textNavigationResultBytes: 48; readonly textLayoutMetricsBytes: 80; readonly textEditingOverlayBytes: 80; readonly vectorQueryBytes: 64; readonly vectorVertexBytes: 48; readonly vectorHandleBytes: 64; readonly vectorSegmentBytes: 144; readonly vectorRegionBytes: 96; readonly vectorBufferResultBytes: 40; readonly vectorHitQueryBytes: 88; readonly vectorHitBytes: 40; readonly vectorHitBufferResultBytes: 24; readonly vectorEditingOverlayBytes: 128; readonly vectorEditingComponentBytes: 32; readonly vectorEditingOverlayQueryBytes: 16; readonly vectorBooleanQueryBytes: 24; readonly vectorBooleanResultBytes: 16; readonly strokeOutlineQueryBytes: 24; readonly strokeOutlineResultBytes: 16; readonly fontMetadataQueryBytes: 16; readonly fontFeatureBytes: 8; readonly fontAxisBytes: 40; readonly fontMetadataResultBytes: 24; } >ABI 版本 1 经过审核的 wasm32 布局:门面在 Wasm 内存中读写的每个 C 结构体的字节大小。每一项都必须等于
render_core.h中对应结构体的大小(例如updateReportBytes对应TacoRenderUpdateReport);C++ 端用static_assert检查其中大部分。原生:
TacoRenderCapabilities,TacoRenderSessionOptions,TacoRenderUpdateReport,TacoRenderSceneInfo,TacoRenderNodeGeometry,TacoRenderGeometryRecord,TacoRenderDirtyBounds,TacoRenderHit另有 36 项
TacoRenderViewportOptions,TacoRenderViewportMapping,TacoRenderRgbaTarget,TacoRenderStaticImageFrame,TacoRenderStaticImageFrameSet,TacoRenderExtendedCapabilities,TacoRenderTextQuery,TacoRenderTextPosition,TacoRenderTextCaret,TacoRenderTextBufferResult,TacoRenderTextRangeQuery,TacoRenderTextRect,TacoRenderTextHitQuery,TacoRenderTextHitResult,TacoRenderTextNavigationQuery,TacoRenderTextNavigationResult,TacoRenderTextLayoutMetrics,TacoRenderTextEditingOverlay,TacoRenderVectorQuery,TacoRenderVectorVertex,TacoRenderVectorCubicHandle,TacoRenderVectorSegment,TacoRenderVectorRegion,TacoRenderVectorBufferResult,TacoRenderVectorHitQuery,TacoRenderVectorHit,TacoRenderVectorHitBufferResult,TacoRenderVectorEditingOverlay,TacoRenderVectorEditingComponent,TacoRenderVectorEditingOverlayQuery,TacoRenderVectorBooleanQuery,TacoRenderVectorBooleanResult,TacoRenderFontMetadataQuery,TacoRenderFontFeature,TacoRenderFontAxis,TacoRenderFontMetadataResult
源码const RENDER_FONT_METADATA_MAX_FEATURES: 131070
源码const RENDER_FONT_METADATA_MAX_AXES: 65535字体元数据查询最多返回的可变轴数量。
源码function decodeWasmGeometryRecords( recordBytes: Uint8Array, recordCount: number, identifierBytes: Uint8Array ): readonly RenderNodeGeometry[]解码
taco_render_session_get_geometry_snapshot写出的几何记录及其节点 ID,且不保留对 Wasm 内存的引用。
源码function decodeWasmHitRecords( recordBytes: Uint8Array, hitCount: number, identifierBytes: Uint8Array ): readonly RenderHit[]解码按最上层优先排列的 ABI-v1 命中记录,且不保留 Wasm 内存。
原生:
TacoRenderHit
源码function decodeWasmVectorGeometry( vertexBytes: Uint8Array, vertexCount: number, handleBytes: Uint8Array, handleCount: number, segmentBytes: Uint8Array, segmentCount: number, regionBytes: Uint8Array, regionCount: number, identifierBytes: Uint8Array, generation: bigint ): RenderVectorGeometrySnapshot严格解码一个带代次标记的矢量几何数据。
原生:
TacoRenderVectorVertex,TacoRenderVectorCubicHandle,TacoRenderVectorSegment,TacoRenderVectorRegion
源码function decodeWasmVectorHits( hitBytes: Uint8Array, hitCount: number, identifierBytes: Uint8Array, generation: bigint ): RenderVectorHitSnapshot按原生的优先级、距离和顺序严格解码矢量命中结果。
源码type RenderMediaFrame = | ({ readonly kind: "image" } & RenderStaticImageFrame) | ({ readonly kind: "video" } & RenderVideoFrame)按资源 ID 全局排序的图片 / 视频混合帧集合中的一个成员。
源码type RenderStaticImageFrame = | RenderStaticImageFrameReuse | RenderStaticImageFrameRgba8888完整的、按逻辑资源 ID 去重的静态图片集合中的一个成员。
源码interface RenderStaticImageFrameRgba8888一张紧密排列、非预乘 alpha 的 RGBA8888 sRGB 替换图片。
readonly disposition: "rgba8888"源码readonly assetId: string源码readonly contentRevision: bigint源码readonly width: number源码readonly height: number源码readonly pixels: Uint8Array源码
源码interface RenderStaticImageFrameReuse复用调用方持有的内容修订号相匹配的那张当前活动图片。
readonly disposition: "reuse-active"源码readonly assetId: string源码readonly contentRevision: bigint源码
源码type RenderVideoFrame = RenderVideoFrameReuse | RenderVideoFrameRgba8888一个精确的已解码视频帧修订;替换时修订号单调递增。
源码interface RenderVideoFrameRgba8888 extends RenderStaticImageFrameRgba8888一个紧密排列的已解码视频帧替换。
源码interface RenderVideoFrameReuse extends RenderStaticImageFrameReuse复用调用方持有的某个修订号所对应的那一帧当前活动视频帧。
Wasm 内存传输
批次通过一块复用的、只增不减的内存分配进入 Wasm 内存,因此持续不断的编辑不会为每个批次都分配内存。
源码class ReusableWasmBatchStagingBuffer为连续的保留 wire 批次复用同一块只增不减的 Wasm 分配。 在下一次写入或释放之前,批次在返回的指针处有效。
new (memory: WasmBatchMemory, options: WasmBatchStagingOptions = {})源码get metrics(): WasmBatchStagingMetrics源码当前的计数器。
write(batch: Uint8Array): StagedWasmBatch源码将批次复制到缓冲区中,需要时扩大缓冲区。
apply<Result>( batch: Uint8Array, applyBatch: (pointer: number, byteLength: number) => Result ): Result源码写入批次,并将其指针和长度传给
applyBatch。dispose(): void源码释放 Wasm 分配。之后的写入会抛出异常。
源码interface WasmBatchMemory传输保留 wire 批次所需的最小 Emscripten 内存接口。
readonly HEAPU8: Uint8Array源码_malloc(bytes: number): number源码_free(pointer: number): void源码
源码interface StagedWasmBatch已暂存批次在 Wasm 内存中的位置。
readonly pointer: number源码readonly byteLength: number源码
源码interface WasmBatchStagingOptions暂存缓冲区大小的上下限,单位为字节。上限默认为
WIRE_LIMITS.batchBytes。readonly minimumCapacityBytes?: number源码readonly maximumCapacityBytes?: number源码
源码interface WasmBatchStagingMetrics显示暂存缓冲区分配和复制频率的计数器。
readonly allocations: number源码此暂存缓冲区在整个生命周期内进行的原生分配次数。
readonly copies: number源码JavaScript 到 Wasm 的
HEAPU8.set操作次数。readonly bytesCopied: number源码readonly capacityBytes: number源码readonly peakBatchBytes: number源码readonly heapGrowthBytes: number源码自构造以来观察到的线性内存增长量,包括 Wasm 自身工作造成的增长。
readonly peakHeapBytes: number源码
字体
当文本样式的所有字体都无法绘制某个字符时,渲染器会回退到来自 Google Fonts 的内置 Noto 字体族,因此字符永远不会显示为空白方框。回退字体在渲染时选定,从不保存到文档中。
源码const AUTOMATIC_FALLBACK_FAMILIES: readonly [ "Noto Sans", "Noto Sans SC", "Noto Sans TC", "Noto Sans HK", "Noto Sans JP", "Noto Sans KR", "Noto Color Emoji" ]自动回退可用于绘制的内置 Noto 字体族。
源码type AutomaticFallbackFamily = typeof AUTOMATIC_FALLBACK_FAMILIES[number]AUTOMATIC_FALLBACK_FAMILIES中的某一项。
源码function automaticFallbackFamilies( cjk: CjkFamily, emoji: boolean ): readonly AutomaticFallbackFamily[]为单个字素簇依次尝试自动回退字体族的顺序。文本先尝试 Noto Sans(拉丁文、希腊文、西里尔文、天城文和越南文),然后尝试从
cjk开始的 CJK 字体族,最后尝试 Noto Color Emoji。emoji 字素簇(见isEmojiGrapheme)会先尝试 Noto Color Emoji,因此带 U+FE0F 的心形会以彩色绘制,即使 CJK 字体中有黑白的心形。
源码function automaticFallbackAsset(family: AutomaticFallbackFamily): FontAsset代表一个自动回退字体族的字体资源。它不属于任何文档;宿主通过
CompilePageOptions.getFontSlices为它传入该字体族已加载的文件,与“google-fonts”文档资源的做法相同。
源码function automaticFallbackAssetById(id: string): FontAsset | undefined具有此 ID 的自动回退资源(如果该 ID 属于自动回退资源)。
源码const AUTOMATIC_FALLBACK_ASSET_ID_PREFIX: "automatic-fallback/"以此前缀开头的资源 ID 保留给自动回退使用。
源码function isAutomaticFallbackFamily( family: string ): family is AutomaticFallbackFamilyfamily是否为AUTOMATIC_FALLBACK_FAMILIES之一。
源码function preferredCjkFamily( styleLanguage: string | undefined, nodeCodePoints: Iterable<number>, userLanguage: string | undefined ): CjkFamily选择由哪个 CJK 字体族绘制多个字体族都包含的汉字。字形样式因地区而异,因此按以下顺序决定:
- 文本样式上设置的语言(“ja”、“zh-TW”……);
- 文本节点本身:出现假名表示日文,出现谚文表示韩文;
- 用户的语言(浏览器的
navigator.language); - 否则使用简体中文。
源码function cjkFamilyForLanguage( language: string | undefined ): CjkFamily | undefinedBCP 47 语言标签所要求的字形样式对应的 CJK 字体族:“ja”对应 JP,“ko”对应 KR;中文在香港和澳门对应 HK,在繁体字(如“zh-TW”或“zh-Hant”)下对应 TC,其他情况对应 SC。其他语言和格式错误的标签返回
undefined。
源码function graphemeClusters(text: string): string[]
源码function isEmojiGrapheme(grapheme: string): boolean某个字素簇是否为以彩色绘制的 emoji:即 Unicode 推荐通用的 emoji 和 emoji 序列(RGI)之一,例如“😀”、“❤️”(带 U+FE0F)、“1️⃣”或“🇯🇵”。默认以文本样式呈现的字符(例如不带 U+FE0F 的“❤”)则不是。
源码function essentialCodePoints(grapheme: string): number[]字体要绘制某个字素簇时必须能映射的码点。默认可忽略字符(连接符、变体选择符)和控制字符不包括在内:文本整形会隐藏它们,而不是绘制一个空方框。
特性策略
能力说明某个渲染器构建包含什么。特性策略则说明当文档使用某个已建模的特性时产品如何处理:渲染它、在应用中处理它,或以明确的错误拒绝它。每个模型特性都有一条对应条目。
源码const RENDER_FEATURE_POLICY_VERSION: 25渲染器策略有意与能力探测分开。能力说明某个二进制文件包含什么; 此表说明当规范文档使用某个已建模的特性时,产品会如何处理。
源码interface RenderFeaturePolicyreadonly feature: string源码供测试和开发者诊断使用的稳定语义标识符。
readonly code: RenderFeaturePolicyCode源码稳定的机器可读代码。实现状态变化时不要重命名。
readonly scope: RenderFeatureScope源码readonly disposition: RenderFeatureDisposition源码readonly note: string源码当前保留模式渲染器的确切边界或归属规则。
源码type RenderFeaturePolicyCode = `TACO_RENDER_POLICY_${string}`
源码type RenderFeatureDisposition = | "rendered" | "deliberate-static-policy" | "application-overlay" | "structured-rejection"
源码type RenderFeatureScope = "node" | "style" | "asset" | "document" | "editor"
源码const RENDER_FEATURE_POLICIES: readonly RenderFeaturePolicy[]扁平的注册表,用于诊断、文档生成和不变量测试。
源码const RENDER_FEATURE_POLICY_TABLES: Readonly< { sceneNodes: { readonly frame: RenderFeaturePolicy; readonly group: RenderFeaturePolicy; readonly text: RenderFeaturePolicy; readonly code: RenderFeaturePolicy; readonly "shape.rectangle": RenderFeaturePolicy; readonly "shape.ellipse": RenderFeaturePolicy; readonly "shape.polygon": RenderFeaturePolicy; readonly "shape.star": RenderFeaturePolicy; readonly "shape.line": RenderFeaturePolicy; readonly "shape.path": RenderFeaturePolicy; readonly image: RenderFeaturePolicy; readonly video: RenderFeaturePolicy; readonly connector: RenderFeaturePolicy; readonly instance: RenderFeaturePolicy; }; paints: { readonly solid: RenderFeaturePolicy; readonly "linear-gradient": RenderFeaturePolicy; readonly "radial-gradient": RenderFeaturePolicy; readonly "angular-gradient": RenderFeaturePolicy; readonly image: RenderFeaturePolicy; }; strokePositions: { readonly center: RenderFeaturePolicy; readonly inside: RenderFeaturePolicy; readonly outside: RenderFeaturePolicy; }; strokeJoins: { readonly miter: RenderFeaturePolicy; readonly bevel: RenderFeaturePolicy; readonly round: RenderFeaturePolicy; }; strokeDashCaps: { readonly none: RenderFeaturePolicy; readonly round: RenderFeaturePolicy; readonly square: RenderFeaturePolicy; }; layouts: { readonly absolute: RenderFeaturePolicy; readonly vertical: RenderFeaturePolicy; readonly horizontal: RenderFeaturePolicy; readonly grid: RenderFeaturePolicy; }; mediaFits: { readonly contain: RenderFeaturePolicy; readonly cover: RenderFeaturePolicy; readonly fill: RenderFeaturePolicy; }; connectorRouting: { readonly straight: RenderFeaturePolicy; readonly elbow: RenderFeaturePolicy; readonly curve: RenderFeaturePolicy; }; connectorCaps: { readonly none: RenderFeaturePolicy; readonly round: RenderFeaturePolicy; readonly square: RenderFeaturePolicy; readonly "line-arrow": RenderFeaturePolicy; readonly "triangle-arrow": RenderFeaturePolicy; readonly "reversed-triangle": RenderFeaturePolicy; readonly "circle-arrow": RenderFeaturePolicy; readonly "diamond-arrow": RenderFeaturePolicy; }; codeDecorations: { readonly emphasis: RenderFeaturePolicy; readonly addition: RenderFeaturePolicy; readonly deletion: RenderFeaturePolicy; readonly annotation: RenderFeaturePolicy; }; vectorSegments: { readonly line: RenderFeaturePolicy; readonly cubic: RenderFeaturePolicy; readonly "elliptical-arc": RenderFeaturePolicy; }; assetKinds: { readonly image: RenderFeaturePolicy; readonly video: RenderFeaturePolicy; readonly font: RenderFeaturePolicy; }; assetSources: { readonly url: RenderFeaturePolicy; readonly data: RenderFeaturePolicy; }; variableBindings: { readonly visibility: RenderFeaturePolicy; readonly opacity: RenderFeaturePolicy; readonly width: RenderFeaturePolicy; readonly height: RenderFeaturePolicy; readonly cornerRadius: RenderFeaturePolicy; readonly fillColor: RenderFeaturePolicy; readonly strokeColor: RenderFeaturePolicy; readonly strokeWidth: RenderFeaturePolicy; readonly gap: RenderFeaturePolicy; readonly wrapGap: RenderFeaturePolicy; readonly columnGap: RenderFeaturePolicy; readonly rowGap: RenderFeaturePolicy; readonly paddingTop: RenderFeaturePolicy; readonly paddingRight: RenderFeaturePolicy; readonly paddingBottom: RenderFeaturePolicy; readonly paddingLeft: RenderFeaturePolicy; readonly fontFamily: RenderFeaturePolicy; readonly fontSize: RenderFeaturePolicy; readonly fontWeight: RenderFeaturePolicy; readonly lineHeight: RenderFeaturePolicy; readonly letterSpacing: RenderFeaturePolicy; readonly textColor: RenderFeaturePolicy; }; crossCutting: { readonly singleFill: RenderFeaturePolicy; readonly multipleFills: RenderFeaturePolicy; readonly singleStroke: RenderFeaturePolicy; readonly multipleStrokes: RenderFeaturePolicy; readonly dashedStroke: RenderFeaturePolicy; readonly rectangleCornerRadius: RenderFeaturePolicy; readonly frameCornerRadius: RenderFeaturePolicy; readonly otherCornerRadius: RenderFeaturePolicy; readonly vectorCornerRadius: RenderFeaturePolicy; readonly strokeCaps: RenderFeaturePolicy; readonly cornerSmoothing: RenderFeaturePolicy; readonly shadows: RenderFeaturePolicy; readonly innerShadows: RenderFeaturePolicy; readonly layerBlur: RenderFeaturePolicy; readonly backgroundBlur: RenderFeaturePolicy; readonly blendModes: RenderFeaturePolicy; readonly masks: RenderFeaturePolicy; readonly paintCompositing: RenderFeaturePolicy; readonly sceneExport: RenderFeaturePolicy; readonly nodeOpacity: RenderFeaturePolicy; readonly isolatedGroupOpacity: RenderFeaturePolicy; readonly rectangularClip: RenderFeaturePolicy; readonly pathRegionPaints: RenderFeaturePolicy; readonly imageCrop: RenderFeaturePolicy; readonly videoCrop: RenderFeaturePolicy; readonly videoPlayback: RenderFeaturePolicy; readonly connectorCoordinates: RenderFeaturePolicy; readonly connectorAttachments: RenderFeaturePolicy; readonly codeSyntax: RenderFeaturePolicy; readonly codeDecorations: RenderFeaturePolicy; readonly codeLineNumbers: RenderFeaturePolicy; readonly variableResolution: RenderFeaturePolicy; readonly comments: RenderFeaturePolicy; readonly rulerGuides: RenderFeaturePolicy; readonly documentMetadata: RenderFeaturePolicy; }; } >
源码type SceneNodePolicyKey = SceneNodePolicyKeyFor<SceneNode>新增
SceneNode或形状判别值时,必须在此处明确指定策略。
源码const SCENE_NODE_FEATURE_POLICIES: { readonly frame: RenderFeaturePolicy; readonly group: RenderFeaturePolicy; readonly text: RenderFeaturePolicy; readonly code: RenderFeaturePolicy; readonly "shape.rectangle": RenderFeaturePolicy; readonly "shape.ellipse": RenderFeaturePolicy; readonly "shape.polygon": RenderFeaturePolicy; readonly "shape.star": RenderFeaturePolicy; readonly "shape.line": RenderFeaturePolicy; readonly "shape.path": RenderFeaturePolicy; readonly image: RenderFeaturePolicy; readonly video: RenderFeaturePolicy; readonly connector: RenderFeaturePolicy; readonly instance: RenderFeaturePolicy; }
源码const PAINT_FEATURE_POLICIES: { readonly solid: RenderFeaturePolicy; readonly "linear-gradient": RenderFeaturePolicy; readonly "radial-gradient": RenderFeaturePolicy; readonly "angular-gradient": RenderFeaturePolicy; readonly image: RenderFeaturePolicy; }
源码const STROKE_POSITION_FEATURE_POLICIES: { readonly center: RenderFeaturePolicy; readonly inside: RenderFeaturePolicy; readonly outside: RenderFeaturePolicy; }
源码const LAYOUT_FEATURE_POLICIES: { readonly absolute: RenderFeaturePolicy; readonly vertical: RenderFeaturePolicy; readonly horizontal: RenderFeaturePolicy; readonly grid: RenderFeaturePolicy; }
源码const MEDIA_FIT_FEATURE_POLICIES: { readonly contain: RenderFeaturePolicy; readonly cover: RenderFeaturePolicy; readonly fill: RenderFeaturePolicy; }
源码const CONNECTOR_ROUTING_FEATURE_POLICIES: { readonly straight: RenderFeaturePolicy; readonly elbow: RenderFeaturePolicy; readonly curve: RenderFeaturePolicy; }
源码const CONNECTOR_CAP_FEATURE_POLICIES: { readonly none: RenderFeaturePolicy; readonly round: RenderFeaturePolicy; readonly square: RenderFeaturePolicy; readonly "line-arrow": RenderFeaturePolicy; readonly "triangle-arrow": RenderFeaturePolicy; readonly "reversed-triangle": RenderFeaturePolicy; readonly "circle-arrow": RenderFeaturePolicy; readonly "diamond-arrow": RenderFeaturePolicy; }
源码const STROKE_JOIN_FEATURE_POLICIES: { readonly miter: RenderFeaturePolicy; readonly bevel: RenderFeaturePolicy; readonly round: RenderFeaturePolicy; }What the renderer does with each stroke join (wire version 23).
源码const STROKE_DASH_CAP_FEATURE_POLICIES: { readonly none: RenderFeaturePolicy; readonly round: RenderFeaturePolicy; readonly square: RenderFeaturePolicy; }What the renderer does with each dash end of a dashed stroke (wire version 23).
源码const CODE_DECORATION_FEATURE_POLICIES: { readonly emphasis: RenderFeaturePolicy; readonly addition: RenderFeaturePolicy; readonly deletion: RenderFeaturePolicy; readonly annotation: RenderFeaturePolicy; }
源码const VECTOR_SEGMENT_FEATURE_POLICIES: { readonly line: RenderFeaturePolicy; readonly cubic: RenderFeaturePolicy; readonly "elliptical-arc": RenderFeaturePolicy; }
源码const ASSET_KIND_FEATURE_POLICIES: { readonly image: RenderFeaturePolicy; readonly video: RenderFeaturePolicy; readonly font: RenderFeaturePolicy; }
源码const ASSET_SOURCE_FEATURE_POLICIES: { readonly url: RenderFeaturePolicy; readonly data: RenderFeaturePolicy; }
源码const VARIABLE_BINDING_FEATURE_POLICIES: { readonly visibility: RenderFeaturePolicy; readonly opacity: RenderFeaturePolicy; readonly width: RenderFeaturePolicy; readonly height: RenderFeaturePolicy; readonly cornerRadius: RenderFeaturePolicy; readonly fillColor: RenderFeaturePolicy; readonly strokeColor: RenderFeaturePolicy; readonly strokeWidth: RenderFeaturePolicy; readonly gap: RenderFeaturePolicy; readonly wrapGap: RenderFeaturePolicy; readonly columnGap: RenderFeaturePolicy; readonly rowGap: RenderFeaturePolicy; readonly paddingTop: RenderFeaturePolicy; readonly paddingRight: RenderFeaturePolicy; readonly paddingBottom: RenderFeaturePolicy; readonly paddingLeft: RenderFeaturePolicy; readonly fontFamily: RenderFeaturePolicy; readonly fontSize: RenderFeaturePolicy; readonly fontWeight: RenderFeaturePolicy; readonly lineHeight: RenderFeaturePolicy; readonly letterSpacing: RenderFeaturePolicy; readonly textColor: RenderFeaturePolicy; }新增可绑定的模型属性时,必须为渲染器制定明确的策略。
源码const CROSS_CUTTING_FEATURE_POLICIES: { readonly singleFill: RenderFeaturePolicy; readonly multipleFills: RenderFeaturePolicy; readonly singleStroke: RenderFeaturePolicy; readonly multipleStrokes: RenderFeaturePolicy; readonly dashedStroke: RenderFeaturePolicy; readonly rectangleCornerRadius: RenderFeaturePolicy; readonly frameCornerRadius: RenderFeaturePolicy; readonly otherCornerRadius: RenderFeaturePolicy; readonly vectorCornerRadius: RenderFeaturePolicy; readonly strokeCaps: RenderFeaturePolicy; readonly cornerSmoothing: RenderFeaturePolicy; readonly shadows: RenderFeaturePolicy; readonly innerShadows: RenderFeaturePolicy; readonly layerBlur: RenderFeaturePolicy; readonly backgroundBlur: RenderFeaturePolicy; readonly blendModes: RenderFeaturePolicy; readonly masks: RenderFeaturePolicy; readonly paintCompositing: RenderFeaturePolicy; readonly sceneExport: RenderFeaturePolicy; readonly nodeOpacity: RenderFeaturePolicy; readonly isolatedGroupOpacity: RenderFeaturePolicy; readonly rectangularClip: RenderFeaturePolicy; readonly pathRegionPaints: RenderFeaturePolicy; readonly imageCrop: RenderFeaturePolicy; readonly videoCrop: RenderFeaturePolicy; readonly videoPlayback: RenderFeaturePolicy; readonly connectorCoordinates: RenderFeaturePolicy; readonly connectorAttachments: RenderFeaturePolicy; readonly codeSyntax: RenderFeaturePolicy; readonly codeDecorations: RenderFeaturePolicy; readonly codeLineNumbers: RenderFeaturePolicy; readonly variableResolution: RenderFeaturePolicy; readonly comments: RenderFeaturePolicy; readonly rulerGuides: RenderFeaturePolicy; readonly documentMetadata: RenderFeaturePolicy; }描述建模基数、跨字段行为以及由应用拥有的展示/编辑器状态的策略,而不是字符串联合类型。
其他导出
尚未归入上述章节的导出,按字母顺序排列。
源码function compilePageRecords( document: DesignDocument, pageId: PageId, options: CompilePageOptions ): readonly RetainedNodeRecord[]The retained node records a page compiles to, in paint order, before they are encoded;
compilePageBatchencodes the same records. For tests and tools that compare compiled scenes.
源码const compilerApplyStats: { orderPathComputations: number; hierarchyRebuilds: number; resourceMapCopies: number; reusableResourceScans: number; incrementalAncestorWalks: number; }
源码function createStrokeOutlineBudget( maximumNetworkBytes: number, maximumRendererMilliseconds: number ): StrokeOutlineBudgetA new budget for one command, with nothing charged yet.
自 0.26.0源码function documentWithEditorInstances( canonical: DesignDocument, renderer: DesignDocument | undefined ): DesignDocumentThe canonical document with the instance nodes a renderer projection adds for the editor (the “Show all variants” views of isolation mode, which draw a component with other property values). Such an instance and the layers inside it stand for themselves in hits and geometry, as a page instance does, although no canonical node owns them. The canonical document itself when the projection adds none.
源码function expandPageInstances( document: DesignDocument, pageId: PageId, resolver: InstanceResolver = resolveInstance, cache?: InstanceResolveCache ): InstanceExpansionWalks a page’s stored tree, expands every instance on it and writes the bound fields of layers under modes other than the active ones.
源码function exportFromLoadedSession( session: ExportSession, request: Omit< RenderCompiledExportRequest, "batch" | "imageAssets" > ): RenderExportResultExports from a session that already holds the page: measures the export with
measureExportFromLoadedSession, then asks the session to draw the region at the scale that the measurement gave. The size that is checked and the size that is drawn come from that one measurement, so they cannot differ.With
options.maxPixels, a raster export (rgbaorpng) whose pixel size is over the limit is refused withRenderExportTooLargeErrorbeforeexportSceneis called, so nothing is allocated or drawn for it.原生,经由
measureExportFromLoadedSession:taco_render_session_get_scene_info,taco_render_session_get_node_geometry,taco_render_session_copy_last_error原生,经由
PortableWasmRenderCoreSession.exportScene:taco_render_session_export,taco_render_session_copy_export_bytes,taco_render_session_copy_last_error
源码function exportPixelSize( region: Pick< RenderRect, | "width" | "height" >, scale: number ): { readonly pixelWidth: number; readonly pixelHeight: number }The pixel size the renderer gives a raster export of a region at a scale: each side rounded up, as the native export rounds it.
源码type ExportSession = Pick< PortableWasmRenderCoreSession, "getSceneInfo" | "getNodeGeometry" | "exportScene" >What
exportFromLoadedSessionuses of a renderer session.
源码function inheritedVectorRegionFills( document: DesignDocument, nodeId: NodeId ): readonly Paint[] | undefinedThe fills a path’s regions are drawn with when they take the layer’s fills and the renderer needs those written on each region: several fills, or one that is not a plain solid colour (a gradient, an image, an opacity, a blend mode, a hidden fill).
undefinedwhen the layer’s one plain fill is enough, or the layer is not a path. The compiler writes these on the regions of the scene; the vector editing overlay, which draws the path from its own copy of the network, needs the same.
源码interface InstanceExpansionA page’s document with its instances replaced by plain nodes: each instance becomes a frame whose children are its resolved layers, stored under their virtual IDs. The compiler then compiles it like any page. Layers whose variable bindings read a mode other than the active one (a page, frame, group or instance chose it, design 7.3) are stored with the values of their modes.
readonly document: DesignDocument源码The input document itself when the page has no instances and no layer needs other modes.
readonly instances: ReadonlyMap<NodeId, ExpandedInstance>源码readonly inheritedModes: ReadonlyMap<NodeId, VariableModes>源码The variable modes each page node inherits from its parent. A node left out inherits none, so its collections show their active modes.
readonly rebound: ReadonlyMap<NodeId, SceneNode>源码Page layers with their bound fields written for their modes.
readonly instancesByComponent: ReadonlyMap<ComponentId, ReadonlySet<NodeId>>源码The reverse index of design 4.3: every component to the instances that draw it, directly or through nesting (
ResolvedInstance.componentIds).readonly textSizesVersion: number源码getDrawnTextSizesVersionwhen the instances were resolved. A resolved text takes the size the renderer measured for text like it; when a size is measured later, every instance is resolved again on the next update.
源码interface InstanceExpansionUpdateWhat
updatePageInstancesreturns.readonly expansion: InstanceExpansion源码readonly changes: ChangeSet源码changesin terms of the expanded documents, virtual layers included.
源码type InstanceResolver = ( document: DesignDocument, instanceId: NodeId, options?: ResolveInstanceOptions ) => ResolvedInstanceDerives the layers an instance shows. The page compiler calls it once per instance on the page;
resolveInstancefrom@taco-slides/modelis the default (design 4.1).
源码interface MeasuredExportWhat an export will draw, as
measureExportFromLoadedSessionworks it out.readonly region: RenderRect源码The part of the page the export shows, in page units.
readonly scale: number源码How many output units one page unit becomes.
readonly pixelWidth: number源码The size of the output, which for a raster export is its size in pixels: the region times the scale, each side rounded up.
readonly pixelHeight: number源码
源码function measureExportFromLoadedSession( session: Pick< ExportSession, "getSceneInfo" | "getNodeGeometry" >, request: Pick< RenderCompiledExportRequest, "rootNodeId" | "scale" | "options" > ): MeasuredExportMeasures an export from a session that already holds the page, without drawing: the region (the page, or everything the root layer and its descendants paint, with shadows, blurs and strokes outside the layer’s box), the scale, and the pixel size these give. It only reads geometry the session already has, so it allocates no picture, however large the export would be. Throws when the root layer paints nothing.
原生,经由
RenderCoreSession.getSceneInfo:taco_render_session_get_scene_info,taco_render_session_copy_last_error原生,经由
RenderCoreSession.getNodeGeometry:taco_render_session_get_node_geometry,taco_render_session_copy_last_error
源码function outlineStrokesInThrowawaySession( createSession: () => StrokeOutlineSession, request: RenderCompiledStrokeOutlineRequest, modelVectorNetwork: ( network: VectorNetworkRecord ) => VectorNetwork, now: () => number = () => performance.now() ): readonly StrokeOutlineResult[]Outlines the strokes of a request in a session made for it and disposed when it ends, however it ends. A stroke the renderer refuses (
PortableWasmStatusError) is answered with the renderer’s reason and the others go on; any other error ends the request with the answers so far dropped.The renderer works on the calling thread, so with a
request.budgetthe time every step takes is measured withnow(milliseconds) and counted down in the budget: making the session, loading the page into it, and each stroke with its decoding, whether the stroke is outlined, refused by the renderer or fails. Before each step, the first included, the time left is checked; when none is left the step is not started and the request fails withStrokeOutlineTimeError. So many slow strokes cannot keep the thread for longer than the budget and one step, however many are asked for and however many of them the renderer refuses. A request whose last step uses up the time is still answered: its work is done. The budget arrives with the time already taken off that compiling the page took (InteractiveRenderSessionCoordinator.outlineDocumentStrokes).原生,经由
RenderCoreSession.apply:taco_render_session_apply,taco_render_session_get_last_dirty_bounds,taco_render_session_copy_last_error原生,经由
RenderCoreSession.getSceneInfo:taco_render_session_get_scene_info,taco_render_session_copy_last_error原生,经由
PortableWasmRenderCoreSession.outlineStroke:taco_render_session_outline_stroke,taco_render_session_get_scene_info,taco_render_session_copy_last_error原生,经由
RenderCoreSession.dispose:taco_render_session_destroy
源码class RenderExportTooLargeError extends ErrorA raster export would have more pixels than
RenderExportOptions.maxPixelsallows. It is thrown before the renderer is asked to draw, so no picture was allocated.readonly pixelWidth: number源码readonly pixelHeight: number源码readonly maxPixels: number源码new (pixelWidth: number, pixelHeight: number, maxPixels: number)源码
源码interface RenderVectorPendingHandleA curve handle that no segment of the previewed network owns yet: the one a Pen drag pulls out of a point for the segment drawn from it next. The renderer draws it as editing chrome only (a guide line and a knob).
readonly vertexId: string源码The point the handle belongs to; it must be in the previewed network.
readonly dx: number源码The handle’s offset from its point, in the path’s local units.
readonly dy: number源码readonly mirrored: boolean源码Also draw the exact mirror of the handle about its point.
源码function resetCompilerApplyStats(): void
源码function resetSceneGeometrySnapshotStats(): void
源码function resetWasmGeometryDecodeStats(): void
源码function resolvedVisualStyle( document: DesignDocument, style: VisualStyle | undefined ): VisualStyleThe style a node is drawn with: its own style over the shared node style it names (
styleId). A fill, stroke or shadow list the node sets itself replaces the shared list whole, also when it is empty. A style ID that names no shared style leaves the node’s own style. Every node compiled here goes through this, so an editor tool that must agree with what is on screen reads the style through it too.
源码function retainInstances( expansion: InstanceExpansion, drawn: (id: NodeId) => boolean ): InstanceExpansionDrops instances the compiler did not draw, such as ones on another page.
源码const sceneGeometrySnapshotStats: { nodeArrayCopies: number }
源码interface StrokeOutlineBudgetHow many bytes of outlines one command may still keep. Every outline of the command (all its strokes, layers and views) is charged its size on the wire before it is copied out of the renderer and decoded, so the outlines held at once never pass
maximumNetworkBytes, however many are asked for. The object is shared and counted down as outlines arrive.readonly maximumNetworkBytes: number源码remainingNetworkBytes: number源码readonly maximumRendererMilliseconds: number源码How long the renderer may work on the command’s strokes, in milliseconds, over all its strokes, layers and views. The renderer outlines on the thread that draws the editor, which cannot answer the user meanwhile. Every step is measured and counted down here (
timedStrokeOutlineStep): compiling the page (InteractiveRenderSessionCoordinator.outlineDocumentStrokes), then loading it and each stroke, whether it is outlined or refused (outlineStrokesInThrowawaySession). No step is started once nothing is left; the request fails withStrokeOutlineTimeErrorinstead. A step that has started is not interrupted, so a command can take this long and one step more, and that step can be the compile of a large page.remainingRendererMilliseconds: number源码
源码class StrokeOutlineBudgetError extends ErrorThrown by
outlineStrokefor the outline that would take a command past itsStrokeOutlineBudget. The outline was sized and nothing else: it was not copied out of the renderer or decoded, and the budget is unchanged.readonly networkByteCount: number源码new (networkByteCount: number, budget: StrokeOutlineBudget)源码
源码type StrokeOutlineSession = Pick< PortableWasmRenderCoreSession, "apply" | "getSceneInfo" | "outlineStroke" | "dispose" >What
outlineStrokesInThrowawaySessionuses of a renderer session.
源码class StrokeOutlineTimeError extends ErrorThrown in place of starting a step of a command (compiling a page, loading it into the renderer, or outlining a stroke) when the command has already kept the thread for as long as its
StrokeOutlineBudgetallows, byInteractiveRenderSessionCoordinator.outlineDocumentStrokesandoutlineStrokesInThrowawaySession.outlinedStrokeCountof the request’sstrokeCountstrokes were answered before it; their answers are dropped with the request.readonly outlinedStrokeCount: number源码readonly strokeCount: number源码new ( budget: StrokeOutlineBudget, outlinedStrokeCount: number, strokeCount: number )源码
源码function timedStrokeOutlineStep<Result>( budget: StrokeOutlineBudget | undefined, progress: { readonly outlinedStrokeCount: number; readonly strokeCount: number; }, step: () => Result, now: () => number = () => performance.now() ): ResultRuns one step of a command’s work on the thread that draws the editor and counts the time it takes, measured with
nowin milliseconds, down in the command’sbudget, whether the step answers or throws. A step is not started once no time is left:StrokeOutlineTimeErroris thrown in its place, with how many of the request’s strokes were answered by then. A step that has started is not interrupted, so it can run past the time; the budget is then left at 0 and the next step is not started. Without a budget the step runs untimed.
源码function updatePageInstances( previous: InstanceExpansion, current: DesignDocument, changes: ChangeSet, resolver: InstanceResolver = resolveInstance, cache?: InstanceResolveCache ): InstanceExpansionUpdateBrings an expansion up to date after an edit without walking the page. An instance is resolved again when its own node changed, or when any component it draws changed (
changedComponentIds, looked up in the reverse index, so editing a component nested in another reaches the outer instances too). Instances found inchangesmay be on another page; the compiler drops their layers, andretainInstancesprunes them after.
源码const wasmGeometryDecodeStats: { identifierSetInserts: number }从有界的堆切片中解码 ABI v1 几何记录。返回的对象不会持有所提供的 Wasm 内存,也从不包含指针。
自 0.23.0源码function withCanonicalComponentChanges( rendererChanges: ChangeSet | undefined, canonicalChanges: ChangeSet ): ChangeSetThe change set the compiler updates from: the renderer projection’s, with the changed components of the canonical change set added. An editor projection may draw a component’s root under a frame of its own (the component view of isolation mode, components design 5.5), where a diff of renderer documents no longer sees the component’s layers as component layers; the canonical change set still names the component, so its instances are resolved again.
@taco-design/electron TypeScript
58 个导出中已记录 57 个 · 大纲
@taco-design/electron shows the Taco Design editor inside an Electron app, in a WebContentsView. The package holds the built editor and a small helper for the main process. The helper serves the editor’s files from a custom address, taco-design://app/, makes the view with safe settings, and carries the document and the events between the app and the editor’s page.
Everything here runs in Electron’s main process. The app brings its own Electron, version 42 or later; 44.7.0 on macOS is the one that was tried. The package can be installed from https://packages.luyu.computer/ (stable or next) or from a CI .tgz file.
For a walk through a whole app, from installing the file to closing a window without losing work, read the guide Add Taco Design to an Electron app. The package’s own README lists what does not work yet, and how to build the .tgz file.
Registering the scheme
The editor’s page is loaded from taco-design://app/. Electron only treats that address as a secure page, which WebGPU needs, when the scheme is registered before the app is ready. An app with no custom scheme of its own calls registerTacoDesignScheme. Electron accepts protocol.registerSchemesAsPrivileged once per app, so an app with schemes of its own adds tacoDesignScheme to its own call instead.
源码function registerTacoDesignScheme(): voidRegisters the
taco-designscheme. Call it before the app is ready.Electron accepts
protocol.registerSchemesAsPrivilegedonce per app, so an app with schemes of its own must not call this: it adds the exportedtacoDesignSchemeobject to its own call instead.
源码const tacoDesignScheme: { readonly scheme: "taco-design"; readonly privileges: { readonly standard: true; readonly secure: true; readonly supportFetchAPI: true; readonly stream: true; readonly codeCache: true; }; }The entry for Electron’s
protocol.registerSchemesAsPrivileged.Electron accepts that call once per app, before the app is ready. An app with schemes of its own adds this object to its own single call; an app with none calls
registerTacoDesignScheme().standard: addresses such as/assets/app.jsresolve, and storage works.secure: the page is a secure context, which WebGPU needs.supportFetchAPI: the renderer file is downloaded withfetch.stream,codeCache: the renderer compiles while it downloads, and compiled scripts are kept between starts.
A scheme handler belongs to one session. createTacoDesignView sets the handler up for its own storage partition, so most apps never call handleTacoDesignScheme.
源码function handleTacoDesignScheme( session: Session, options: { readonly appDirectory?: string } = {} ): voidServes
taco-design://app/on one session from a folder of editor files.A scheme handler belongs to a session: a view in its own partition does not see a handler registered on another session.
createTacoDesignViewcalls this for its own partition; call it yourself only when you make theWebContentsViewyourself. Calling it again for the same session and folder does nothing.options.appDirectorynames another folder of editor files to serve than the package’s own, and must be an absolute path.
源码const TACO_DESIGN_SCHEME: "taco-design"The custom scheme the editor’s files are served from.
源码const TACO_DESIGN_HOST: "app"The only host the scheme answers for.
源码const TACO_DESIGN_ORIGIN: "taco-design://app"The origin of the editor page; permission rules compare against it.
源码const TACO_DESIGN_APP_URL: "taco-design://app/"The address
createTacoDesignViewloads.
The package finds its editor files and its preload script next to its own code on disk. An app that bundles its main process keeps @taco-design/electron out of the bundle for that reason.
源码const appDirectory: stringThe folder of editor files inside this package, served as
taco-design://app/.
源码const preloadPath: stringThe preload script of the editor’s view, as a file path.
Creating the view
createTacoDesignView makes the view and starts loading the editor. Add TacoDesignView.view to a window and give it bounds, then wait for TacoDesignView.ready: it resolves when the document is open and the renderer has drawn, and rejects with a TacoDesignError when the editor cannot start. A failed start is never a blank view: the view shows the message too.
源码function createTacoDesignView( options: TacoDesignViewOptions = {} ): TacoDesignViewMakes a
WebContentsViewthat shows the Taco Design editor, with safe settings: sandbox and context isolation on, no Node.js in the page, its own storage partition, a short list of permissions, no navigation to other addresses and no new windows.Call it after the app is ready, and after the scheme was registered.
源码interface TacoDesignViewOptionsThe options of
createTacoDesignView. Every one can be left out.readonly document?: unknown源码The document to open, as plain JSON (what
getDocument()returned earlier and the app stored). Leave it out, or pass null, for a new blank document. A document that cannot be opened rejectsreadywithinvalid-documentorschema-too-new, and the view shows why.readonly requestTimeoutMs?: number源码How long one request (
getDocument()and the others) waits for its answer. Default 30 000 ms.readonly partition?: string源码The storage partition of the view. Default
persist:taco-design.The package sets its own permission rules on this partition’s session, so do not share the partition with other pages of your app.
readonly appDirectory?: string源码A folder of editor files to serve instead of the one inside this package, as an absolute path. Anything else throws
app-directory-invalid.readonly readyTimeoutMs?: number源码How long one load of the editor’s page may take, from its beginning to a drawn editor, before it ends with
ready-timeout:readyrejects for the first load,reload()for a later one. Default 60 000 ms.readonly startupProgress?: TacoDesignStartupProgressDrawer源码Who draws the progress while the editor starts.
"editor"(the default): the editor shows its own slim bar in the view, from the first drawing of the page until the editor’s first frame."host": the editor shows none, and the app draws its own from thestartupProgressevent. The event is sent either way.readonly onDownload?: (item: DownloadItem) => void源码Called for every download the editor starts (an export, for example). Call
item.setSavePath()to save without asking. Without this option Electron shows its own save dialog.readonly shortcuts?: ShortcutOverrides源码Changes to the editor’s keyboard shortcuts: a command ID mapped to its new keys (
"CmdOrCtrl+Shift+D"), to a list of keys, or tonullto switch that shortcut off.getShortcuts()lists the command IDs. Keys that cannot be read throwinvalid-shortcut-keyshere; an unknown command ID, a command that cannot be changed, or two commands on the same keys rejectreadywith the matching error code.What happens to a key that is an editor shortcut and also an accelerator in the app’s menu, while the editor has the keyboard:
"editor"(the default) runs the editor’s command only,"app"runs the menu item only,"both"runs both. The README says how each is done.
源码interface TacoDesignViewWhat
createTacoDesignViewreturns: the view to put in a window, and the calls and events that reach the editor inside it.Every call that returns a promise waits for
readyfirst. It rejects with aTacoDesignErrorwhen the editor never started or transport fails. Design calls also report domain errors as documented ondesignRequest.readonly view: WebContentsView源码A plain
WebContentsView: add it to a window and give it bounds.readonly ready: Promise<TacoDesignReadyState>源码Resolves when the editor’s renderer reports ready. Rejects with a
TacoDesignErrorwhen the page cannot be loaded or the editor cannot start; the view then shows a message instead of staying blank. Always handle the rejection.getDocument(): Promise<TacoDesignDocumentSnapshot>源码The open document as plain JSON, without undo history, and the revision it was read at. Call it when you save; the editor stores nothing itself.
setDocument( document: unknown, options?: TacoDesignSetDocumentOptions ): Promise<TacoDesignSetDocumentResult>源码Replaces the open document. Undo history, selection and zoom start fresh. Rejects with
invalid-documentorschema-too-newand leaves the open document as it was when the new one cannot be opened.With
{ ifRevision }the document is replaced only while the editor’s document is at that revision, the onegetDocument()resolved with. Otherwise the call rejects withrevision-changedand nothing changes.newDocument(options?: TacoDesignSetDocumentOptions): Promise<DocumentInfo>源码Replaces the open document with a new blank one: one empty page, the default fonts and styles, and an ID of its own, like the document a view starts with when it is given none. Everything else is as for
setDocument(): undo history, selection and zoom start fresh, thechangeevent has the origin"host", and with{ ifRevision }the document is replaced only at that revision (revision-changedotherwise). Resolves with the new document’s ID, title, page count and revision. Read it withgetDocument()when you want to store it.getState(): Promise<EditorState>源码The versions the editor speaks and a few facts about the open document.
designRequest( request: DesignRequest, options?: TacoDesignRequestOptions ): Promise<DesignReply>源码Sends a validated read/planning envelope after startup and version discovery. Preserves the explicit editor/document/epoch target. Domain failures resolve as DesignReply; transport failures reject with TacoDesignError. Local catalog or capability failures reject with DesignError. Use createDesignClient for typed results and throwing domain errors. No public writes are enabled.
undo(): Promise<TacoDesignHistoryResult>源码Undoes one step.
doneis false when there was nothing to undo.redo(): Promise<TacoDesignHistoryResult>源码Redoes one step.
doneis false when there was nothing to redo.exportLayers( options: TacoDesignExportOptions ): Promise<TacoDesignExportedFile[]>源码Draws one layer (
nodeId) or one whole page (pageId) into a PNG, JPEG, SVG or PDF file through the editor’s own export, and resolves with the file’s name, type and bytes. The list has one file. Rejects withunknown-layer,unknown-page,unsupported-format,invalid-request,export-too-large(more than 8192 x 8192 pixels),renderer-failedorexport-failed. A document with no page has nothing to export: every target isunknown-pageorunknown-layer.getSelection(): Promise<SelectionSummary>源码The page that is shown and the selected layers, each with its ID, name and kind.
zoomToFit( options?: { readonly target?: "page" | "selection"; } ): Promise<{ done: boolean }>源码Zooms the canvas so that the whole page fits, or the selected layers with
{ target: "selection" }.doneis false when the selection was asked for and nothing is selected, and when the document has no page.focusCanvas(): Promise<FocusSummary>源码Gives the keyboard to the view and, inside it, to the canvas, so that the editor’s shortcuts work. Resolves with where the keyboard is.
getShortcuts(): Promise<ShortcutCommandInfo[]>源码The editor’s keyboard shortcuts: every command with its stable ID, its title, its default keys and the keys in use now (none when it is switched off).
setShortcuts(overrides: ShortcutOverrides): Promise<ShortcutCommandInfo[]>源码Replaces this app’s changes to the shortcuts and resolves with the list as it is afterwards.
overridesis the whole set: a command that is not named goes back to its default keys, and{}resets them all. When a change is wrong nothing is changed, and the promise rejects withunknown-shortcut-command,invalid-shortcut-keys,shortcut-keys-in-useorshortcut-not-customizable;error.pathis the command ID. The changes are kept by this object, not by the page: they last as long as the view and survivereload().The setting for keys that are both an editor shortcut and a menu accelerator.
setMenuShortcutConflict(conflict: MenuShortcutConflict): void源码Changes that setting. Any other value than the three throws
invalid-option.reload(): Promise<TacoDesignReloaded>源码Loads the editor’s page again without losing work. The page first ends editing and freezes (it accepts no edit, and refuses
setDocument(),undo()andredo()withnot-ready), then hands over its document; only after that answer is it loaded again, and the new page gets the document back. No edit can fall in between. Use it after afailureevent. Resolves when the new page is ready as it is afterready: the editor answers and its renderer has drawn, so anexportLayers()right after it works.handedOveris false when the page did not hand over (its process had ended, or it did not answer in 5 seconds), and the editor then shows the last document this app set or read. The new page is loaded and watched exactly as the first one, soreload()rejects with every errorreadycan reject with, as soon as it is known (load-failed,app-files-missing,renderer-failed,page-crashed,ready-timeoutafterreadyTimeoutMs, and the others), and thefailurelisteners hear the same error. It also rejects withdisposedwhen the view is disposed meanwhile, and withload-failedwhen the page was not loaded again within 10 seconds of its answer (it then accepts edits again). Two calls at the same time are one reload. The undo history starts empty and the revision at 0.on<Event extends keyof TacoDesignEvents>( event: Event, listener: TacoDesignEvents[Event] ): () => void源码Listens for
"change"(the document changed),"selection"(the selection changed),"focus"(the keyboard moved),"saveRequested"(the Save keys were pressed in the editor),"startupProgress"(how far the start-up is),"failure"(the editor stopped working afterready, or could not be loaded again) or"reloaded"(the page was loaded again), or"design"(a stamped design invalidation). The returned function removes the listener.focus(): void源码Gives the keyboard to the editor’s view.
dispose(): void源码Closes the view’s page. The view cannot be used afterwards.
源码interface TacoDesignReadyStateWhat
readyresolves with.readonly url: string源码The address the editor was loaded from.
readonly build: TacoDesignBuildInfo | null源码What the editor was built from, or null when the folder has no build record.
readonly protocolVersion: number源码The version of the host protocol the editor and this package agreed on.
readonly documentSchemaVersion: string源码The newest document schema version the editor reads, and the one it writes.
readonly rendererWireVersion: number源码The version of the format the editor and its renderer talk in.
readonly document: DocumentInfo源码The open document: its id, title, page count, revision, and whether undo and redo are possible.
源码interface TacoDesignBuildInfoWhat the assemble script wrote next to the editor files.
readonly documentSchemaVersion: string源码The document schema version the editor reads and writes, such as
0.27.0.readonly rendererWireVersion: number源码The version of the format the editor and its renderer talk in.
readonly commit: string源码The commit the editor was built from.
源码const DEFAULT_READY_TIMEOUT_MS: 60000How long
readywaits for the editor before it rejects, unless the app says otherwise.
The document
The editor in the view stores no document. It starts from the one the app hands over (TacoDesignViewOptions.document), keeps it in memory, and tells the app when it changes. Saving is the app’s job: read the document with TacoDesignView.getDocument and write it as JSON.
A document holds its pictures, so it can be tens of megabytes. Events therefore carry only a few facts about it (DocumentInfo), never the document itself. The undo history is not part of the document: it lives in the page and starts empty each time a document is handed over.
Read the document once more before a window closes, every time. The page has no “unsaved changes” guard, and TacoDesignView.getDocument is the only call that is never behind the newest edit.
TacoDesignView.setDocument replaces the open document. An app that opens another file saves the open one first, and an edit may arrive between that last read and the replacement, because the page is another process. So pass the revision of the read: setDocument(document, { ifRevision }) replaces the document only while the editor’s document is still at that revision. At any other revision the call rejects with revision-changed and nothing changes; read and write again, then retry. Revisions start at 0 again on every page load, so use a revision read after the last reloaded event.
TacoDesignView.newDocument replaces the open document with a new blank one, like the document a view starts with when it is given none. It takes ifRevision too and is otherwise setDocument. Use it for a “New” command and for a file that does not exist yet. setDocument(null) is refused, so that a file with no document in it never opens as a blank one by accident.
源码type DocumentJson =A whole document as plain JSON, without its undo history. The host stores it and hands it back; it need not look inside.
readonly schemaVersion: string源码The document schema version the document is written in, such as
0.27.0.readonly id: string源码The document’s ID.
readonly title: string源码The document’s title.
readonly [key: string]: unknown源码Everything else in the document: its pages, layers, components and pictures.
源码interface TacoDesignDocumentSnapshotWhat
getDocument()resolves with.readonly document: DocumentJson源码The whole document as plain JSON, without undo history. Write it with
JSON.stringify.readonly revision: number源码The revision the document was read at. It counts every change made so far, also those whose
changeevent has not arrived yet, so achangeevent’s revision can be lower. Do not compare the two to decide whether to save before closing: always read the document one last time.
源码interface TacoDesignSetDocumentOptionsWhat
setDocument()takes besides the document, and whatnewDocument()takes.readonly ifRevision?: number源码Replace the document only while the editor’s document is at this revision (the
revisionthatgetDocument()resolved with). At any other revision the call rejects withrevision-changedand nothing changes: an edit was made since that read. Revisions start at 0 again on every page load, so use one read after the lastreloadedevent.
源码interface TacoDesignSetDocumentResult extends DocumentInfoWhat
setDocument()resolves with.readonly migratedFrom?: string源码The schema version the document arrived in, when the editor had to bring it up to date.
源码interface TacoDesignHistoryResult extends DocumentInfoWhat
undo()andredo()resolve with.readonly done: boolean源码False when there was nothing to undo or redo.
源码interface DocumentInfoA few facts about the open document, small enough to send with every change.
readonly id: string源码The document’s ID.
readonly title: string源码The document’s title.
readonly pageCount: number源码How many pages the document has.
readonly revision: number源码Goes up by one on every change to the document and on every
setDocument. Starts at 0 on each page load.readonly canUndo: boolean源码True when there is a step to undo.
readonly canRedo: boolean源码True when there is a step to redo.
源码interface EditorStateThe versions the editor speaks and a few facts about the open document: the answer to a
getStaterequest.readonly design?: DesignCapability源码Optional read/planning capability; absent in older editors.
readonly protocolVersion: number源码The version of the host protocol the editor and the host agreed on.
readonly documentSchemaVersion: string源码The newest document schema version the editor reads, and the one it writes.
readonly rendererWireVersion: number源码The version of the format the editor and its renderer talk in.
readonly build: string源码Names the build of the editor’s page, for error reports.
readonly document: DocumentInfo源码The open document: its ID, title, page count, revision, and whether undo and redo are possible.
Events
TacoDesignView.on takes an event name and a listener and returns a function that removes the listener. A listener that throws does not stop the editor or the other listeners. Events are small: none of them carries the document.
change, selection and focus say what happened in the editor. startupProgress, failure and reloaded say how the page itself is doing. saveRequested says that the person pressed the editor’s Save shortcut (Cmd+S, or Ctrl+S on Windows and Linux). The editor saves nothing itself, so answer it by reading the document and writing it, with the same function the app’s own Save menu item calls.
// Cmd/Ctrl+S in the editor. The editor saves nothing itself.
editor.on("saveRequested", saveNow);apps/electron-sample/main.mjs,第 260 至 261 行
源码interface TacoDesignEventsThe events of a
TacoDesignView, each with the listener it calls. The names are whatTacoDesignView.ontakes.design: (event: DesignEvent) => void源码Stamped invalidations for the current page, not a resumable synchronization log.
change: (change: TacoDesignChange) => void源码The document changed. Changes by the person using the editor arrive at most once per 100 ms, and the last one always arrives. Ask for the document with
getDocument()when you save.selection: (selection: SelectionSummary) => void源码Other layers are selected, another page is shown, or a selected layer was renamed. Arrives at most once per 100 ms, and the last one always arrives.
focus: (focus: FocusSummary) => void源码The keyboard moved: into or out of the editor, or between its canvas, a text field and the rest.
failure: (error: TacoDesignError) => void源码The editor stopped working after
ready, or could not be loaded again.error.codesays how. It worked and stopped:renderer-failed(the canvas stopped drawing;detailis the renderer’s own code),editor-crashed(the editor shows its crash screen) orpage-crashed(the page’s process ended). A reload failed: any codereadycan reject with (load-failed,app-files-missing,ready-timeout,renderer-failed,page-crashedand the others); areload()that was waiting rejects with the same error.reload()brings the editor back.reloaded: (document: TacoDesignReloaded) => void源码The editor’s page was loaded again (its crash screen’s Reload button, or
reload()) and is ready as it is afterready: the editor answers and its renderer has drawn.handedOversays which document it shows.saveRequested: () => void源码The Save keys were pressed while the editor had the keyboard (the command
file.save: Cmd+S on macOS and Ctrl+S elsewhere, unless the shortcut was changed). The editor saves nothing itself: read the document withgetDocument()and store it.startupProgress: (progress: TacoDesignStartupProgress) => void源码How far the editor’s start-up is: a fraction, and the step in progress. At most ten arrive per second. They can only start once the page has its connection, so the first one already counts what happened before. The last one is
{ fraction: 1, step: "done" }and arrives beforereadyresolves. A start that fails has no last report:readyrejects instead, and no report of that page load follows the rejection, so loading is over whenreadysettles either way. A page that is loaded again reports its progress again, in the same way: the last report arrives beforereloadedis told andreload()resolves, and a reload that fails has no last report and tellsfailureinstead.
源码interface TacoDesignChange extends DocumentInfoWhat a
changelistener gets: a few facts about the document, never the document.readonly origin: "user" | "host"源码"host": caused bysetDocument()ornewDocument()."user": everything else (edits, undo and redo, and changes the editor makes by itself after an edit).
Export
TacoDesignView.exportLayers draws one layer or one whole page through the editor’s own export, so the file is what the editor’s Export section would download. It resolves with a list that holds one file. One PNG or JPEG may have at most 8192 x 8192 pixels.
源码interface TacoDesignExportOptionsWhat
exportLayers()takes: one layer or one page, a format, and the choices of the editor’s own Export section.readonly nodeId?: string源码The layer to export, with everything inside it. Give this or
pageId.readonly pageId?: string源码The page to export whole. Give this or
nodeId.readonly format: HostExportFormat源码The file format:
"png","jpeg","svg"or"pdf".readonly scale?: number源码PNG and JPEG: pixels per document unit. Default 1. Give at most one of
scale,widthandheight.readonly width?: number源码readonly height?: number源码readonly quality?: "low" | "medium" | "high"源码JPEG: compression. PDF: resolution of effects that cannot be drawn as shapes. Default: high for JPEG, medium for PDF.
readonly resampling?: "detailed" | "basic"源码How pictures inside the layer are sampled. Default
"detailed".readonly ignoreOverlappingLayers?: boolean源码For a layer: true (default) draws the layer alone, false also what else lies within its bounds.
readonly includeIdAttribute?: boolean源码SVG:
idattributes made from layer names. Default false.readonly suffix?: string源码Added to the file name after the layer’s or page’s name.
readonly timeoutMs?: number源码How long to wait for the export. Default 120 000 ms.
源码type HostExportFormat = "png" | "jpeg" | "svg" | "pdf"The file formats an export can be written in.
源码interface TacoDesignExportedFileOne exported file.
readonly fileName: string源码<layer or page name><suffix>.<extension>, safe as a file name.readonly mimeType: string源码image/png,image/jpeg,image/svg+xmlorapplication/pdf.readonly bytes: Uint8Array源码The file’s bytes; write them with
fs.writeFile.
Selection, zoom and focus
TacoDesignView.getSelection and the selection event say which page is shown and which layers are selected. There is no call that sets the selection. TacoDesignView.zoomToFit does what the editor’s “Zoom to fit” and “Zoom to selection” do. TacoDesignView.focusCanvas gives the keyboard to the canvas, and the focus event says where the keyboard is.
源码interface SelectionSummaryThe page that is shown and the selected layers: the answer to a
getSelectionrequest, and what a selection event carries.readonly pageId: string | null源码The page that is shown, or null when the document has none.
readonly nodes: readonly SelectedLayer[]源码The selected layers, in the order they were selected. Empty when nothing is selected.
源码interface SelectedLayerOne selected layer.
readonly id: string源码The ID the document knows the layer by. A layer inside an instance has an ID made of the instance’s ID and the layer’s place inside it.
readonly name: string源码The layer’s name, as the layers panel shows it.
readonly type: string源码The layer’s kind, the same word as its
typein the document:"frame","group","text","shape","image","instance"and so on. An instance is"instance"wherever it is: on a page, inside a component, or inside another instance. A component’s root is the frame it is stored as.readonly shape?: string源码For a layer of type
"shape": which shape, the same word as itsshapein the document ("rectangle","ellipse","line","path", ...).readonly componentId?: string源码For a layer of type
"instance": the ID of the component it shows, as in the document’scomponents. For an instance inside another instance this is the component in effect after a swap by the outer one.readonly componentName?: string源码For a layer of type
"instance": the name of that component.
源码interface FocusSummaryWhere the keyboard is: the answer to a
focusCanvasrequest, and what a focus event carries.readonly focused: boolean源码True while the editor’s page has the keyboard.
readonly target: "canvas" | "text" | "other" | null源码What has the keyboard inside the page:
"canvas";"text"(a text field, or text being edited on the canvas), where keys such as copy and undo belong to the text;"other"(a button, a panel, or nothing in particular). Null while the page does not have the keyboard.
Reload and failures
Every failure is a TacoDesignError with a code. Before the editor is ready it rejects TacoDesignView.ready. Afterwards it reaches the failure listeners: the renderer stopped, the editor crashed, or the page’s process ended. TacoDesignView.reload loads the editor again; where the page can still answer, it hands its document over first, so no edit is lost.
A call the editor refuses rejects with a TacoDesignError too, and changes nothing: revision-changed from TacoDesignView.setDocument or TacoDesignView.newDocument with ifRevision, and the shortcut codes from TacoDesignView.setShortcuts (unknown-shortcut-command, invalid-shortcut-keys, shortcut-keys-in-use, shortcut-not-customizable). TacoDesignErrorCode lists every code.
There is no automatic retry. When TacoDesignView.ready rejected, dispose the view and make a new one. Do not call TacoDesignView.reload from a failure listener without a limit, because a failure that comes back at once would reload for ever.
源码interface TacoDesignReloaded extends DocumentInfoWhat a
reloadedlistener gets, and whatreload()resolves with.readonly handedOver: boolean源码True: the page handed over its document right before it was loaded again, so the editor shows the latest work. False: it could not (its process had ended, for example), and the editor shows the last document this app set or read; edits made after that are lost.
源码class TacoDesignError extends ErrorThe error
readyrejects with, and the package’s functions throw.readonly code: TacoDesignErrorCode源码What went wrong. Decide by this, never by the message, which is written for a person.
readonly url: string | undefined源码The address that was being loaded.
readonly errorCode: number | undefined源码Chromium’s network error number, such as
-2forERR_FAILED.readonly errorDescription: string | undefined源码Chromium’s network error name, such as
ERR_FAILED.readonly httpStatus: number | undefined源码The HTTP status the page answered with.
readonly rendererErrorCode: string | undefined源码The editor’s own renderer error code, such as
WEBGPU_UNAVAILABLE.readonly path: string | undefined源码Where a document is wrong, as a JSON path such as
$.nodes.n1.opacity.readonly detail: string | undefined源码The document model’s own error code, such as
INVALID_SCHEMA; forrenderer-failedafterready, the renderer’s own code.new ( code: TacoDesignErrorCode, message: string, details: TacoDesignErrorDetails = {} )源码Makes an error from a code, a message written for a person, and the extra facts that are known.
源码type TacoDesignErrorCode = | "app-files-missing" | "load-failed" | "scheme-not-registered" | "scheme-registered-too-late" | "scheme-handler-conflict" | "app-directory-invalid" | "renderer-failed" | "editor-failed" | "page-crashed" | "ready-timeout" | "disposed" | "invalid-document" | "schema-too-new" | "protocol-mismatch" | "not-ready" | "unknown-method" | "request-aborted" | "request-timeout" | "connection-closed" | "editor-crashed" | "invalid-request" | "unknown-layer" | "unknown-page" | "unsupported-format" | "export-too-large" | "export-failed" | "revision-changed" | "unknown-shortcut-command" | "invalid-shortcut-keys" | "shortcut-keys-in-use" | "shortcut-not-customizable" | "invalid-option" | "internal"Why the editor could not be shown.
app-files-missing: the folder of editor files has noindex.html(the package was not assembled, orappDirectoryis wrong).load-failed: Electron could not load the page (errorCodeanderrorDescriptionare Chromium’s), or the page answered with an HTTP error status (httpStatus).scheme-not-registered: the page is not a secure context, which meanstacoDesignSchemewas not registered before the app was ready.scheme-registered-too-late:registerTacoDesignScheme()ran after the app was ready.scheme-handler-conflict: the session already serves the scheme from another folder.app-directory-invalid: theappDirectoryoption is not an absolute path of a folder, or is the root of a disk.renderer-failed: the page loaded but the WebGPU renderer did not start (rendererErrorCodeis the editor’s own code, such asWEBGPU_UNAVAILABLE).editor-failed: the page loaded but the editor showed its start-up error screen (for example its stored data could not be opened).page-crashed: the page’s process ended. Beforereadyit rejectsready; afterwards it reaches thefailurelisteners.ready-timeout: the editor did not report ready in time.reload()rejects with it when the page that was loaded again did not connect, or did not report ready, in that time.disposed:dispose()was called, or the view was destroyed, first.
From the editor, about a document or a request (see the host protocol):
invalid-document: the document handed over is not one Taco Design can open.pathsays where it is wrong (a JSON path such as$.title) anddetailholds the document model’s own code.schema-too-new: the document was written by a newer Taco Design.protocol-mismatch: this package and the editor files speak no common version of the host protocol (they come from different releases).not-ready: the editor is not shown (it failed, or is reloading), so the request was not run.unknown-method: the editor files are older than this package and do not know the request.request-timeout: the editor did not answer a request in time.request-aborted: the caller stopped waiting for a design request.connection-closed: the editor’s page went away (it reloaded or crashed) before it answered.internal: the editor failed in a way it has no code for.
From
exportLayers():unknown-layer,unknown-page: the document has no such layer on a page, or no such page.unsupported-format: the format is not PNG, JPEG, SVG or PDF.invalid-request: an option has a value the editor cannot use (two sizes at once, a scale of 0, ...). Other requests use it too.export-too-large: the picture would have more than 8192 x 8192 pixels.export-failed: the renderer could not draw or encode the export; the message says why (fonts still loading, for example).
To the
failurelisteners, afterready:renderer-failed: the canvas stopped drawing (detailis the renderer’s own code).editor-crashed: the editor threw and shows its crash screen.page-crashed: see above.
源码interface TacoDesignErrorDetailsThe extra facts a
TacoDesignErrorcan carry besides its code and its message. Which of them are set depends on the code.readonly url?: string源码The address that was being loaded.
readonly errorCode?: number源码Chromium’s network error number, such as
-2forERR_FAILED.readonly errorDescription?: string源码Chromium’s network error name, such as
ERR_FAILED.readonly httpStatus?: number源码The HTTP status the page answered with.
readonly rendererErrorCode?: string源码The editor’s own renderer error code, such as
WEBGPU_UNAVAILABLE.readonly path?: string源码Where a document is wrong, as a JSON path such as
$.nodes.n1.opacity.readonly detail?: string源码The document model’s own error code, such as
INVALID_SCHEMA.
Start-up progress
While the editor starts it shows a slim progress bar of its own, and it tells the app the same thing with the startupProgress event. An app that draws the progress itself, in a splash screen for example, passes TacoDesignViewOptions.startupProgress as "host". Loading is over when TacoDesignView.ready settles: a start that fails sends no last report.
源码interface TacoDesignStartupProgressWhat a
startupProgresslistener gets.readonly fraction: number源码The share of start-up that is finished, 0 to 1. It never goes down within one page load.
readonly step: string源码The step in progress, in order:
page-code,fonts,document,module-download,module-create,creating-session,installing-page, anddonein the last report. Later versions may add steps, so showlabeland do not switch on this.readonly label: string源码A few plain words for the step, such as “Downloading the renderer”.
readonly indeterminate: boolean源码True while the step in progress cannot say how long it is (a download without a known size).
fractionthen stays where it was: show a bar that moves without a percentage.
源码type TacoDesignStartupProgressDrawer = "editor" | "host"The option that says who draws the progress while the editor starts.
Keyboard and menus
While the editor has the keyboard, the editor’s shortcuts are the editor’s: Cmd+Z undoes on the canvas, Cmd+C and Cmd+V copy and paste layers, Cmd+D duplicates, the letter keys choose tools, even when an item of the app’s menu has an accelerator on the same keys. (Cmd is Ctrl on Windows and Linux.) An app can change that in three ways: give a command other keys, switch a command’s shortcut off, and choose who gets a key that its menu wants too.
/** The override the sample's "Duplicate on Cmd/Ctrl+Shift+D" item switches on. */
export const DUPLICATE_REMAP = /** @type {const} */ ({ "edit.duplicate": "CmdOrCtrl+Shift+D" });apps/electron-sample/appMenu.mjs,第 30 至 31 行const editor = createTacoDesignView({
document: startDocument,
startupProgress: process.argv.includes("--host-progress") ? "host" : "editor",
menuShortcutConflict: startConflict,
shortcuts: startRemapped ? DUPLICATE_REMAP : {},
});apps/electron-sample/main.mjs,第 136 至 141 行Changing the editor’s shortcuts
The editor’s shortcuts are a list of commands. Each has a stable ID such as edit.duplicate, a title, its default keys and the keys in use now (ShortcutCommandInfo). TacoDesignView.getShortcuts returns the list; the package’s README has it as a table. The IDs are part of the package’s API: they are not renamed or reused.
TacoDesignViewOptions.shortcuts and TacoDesignView.setShortcuts take the same object (ShortcutOverrides): a command ID mapped to its new keys, to a list of keys, or to null to switch the shortcut off. It is always the whole set of the app’s changes: a command that is not named has its default keys, and setShortcuts({}) puts every command back. Keys are written like Electron accelerators, for example CmdOrCtrl+Shift+D.
- The old keys of a command that is moved or switched off stop working, and the editor no longer claims them: a menu accelerator on those keys runs.
- Nothing is applied when something is wrong. The call rejects with a
TacoDesignErrorwhosepathis the command ID:unknown-shortcut-command,invalid-shortcut-keys,shortcut-keys-in-use(two commands would run on the same key press) orshortcut-not-customizable(edit.paste). A wrongshortcutsoption rejectsTacoDesignView.readythe same way. - The app keeps the changes, the editor’s page does not. The view object holds them and gives them to the page again after every reload. Store them in the app’s own settings if they should outlast the app.
- They do not apply while text is being typed. While a text field or text on the canvas has the keyboard (the
focusevent says"text"), every key means what it means in a text field. The one exception is Save.
源码type ShortcutOverrides =An embedding app’s changes to the editor’s shortcuts: a command ID mapped to its new key combination, to a list of them, or to
nullto switch the shortcut off. Commands that are not named keep their default keys.readonly [commandId: string]: string | readonly string[] | null源码
源码interface ShortcutCommandInfoOne command of the editor’s shortcut list.
Key combinations are written like Electron accelerators, for example
CmdOrCtrl+Shift+D;shortcuts.tsdescribes the spelling.readonly id: string源码The stable name of the command, for example
edit.duplicate. Part of the public API.readonly title: string源码What the command does, in a few words of English.
readonly defaultKeys: readonly string[]源码The keys the command has when the embedding app changes nothing.
readonly keys: readonly string[]源码The keys in use now. Empty when the shortcut is switched off.
readonly customizable: boolean源码False for a command whose keys cannot be changed or switched off.
A key that is an editor shortcut and a menu accelerator
TacoDesignViewOptions.menuShortcutConflict, and TacoDesignView.setMenuShortcutConflict at run time, say what happens to a key press that runs an editor command and is also the accelerator of an enabled, visible item of the application menu, while the editor has the keyboard. With "editor" (the default) the editor’s command runs and the menu item does not. With "app" the menu item runs and the editor does not see the key. With "both" the menu item runs first, then the editor’s command.
- Only editor shortcuts are touched. A key that is no editor command (Cmd+Q, Cmd+W, the app’s own accelerators on free keys) is handled by the menu as in any Electron app.
- Nothing is done while a text field or text on the canvas has the keyboard, except for Save: Cmd+Z, Cmd+C, Cmd+X, Cmd+V and Cmd+A must reach the text.
- Paste (Cmd+V) is never touched, because on macOS the system’s paste comes from the menu’s
pasterole. - A changed shortcut counts with its new keys.
源码type MenuShortcutConflict = "editor" | "app" | "both"What happens to a key press that is an editor shortcut and also an accelerator of an item in the app’s menu, while the editor has the keyboard:
"editor"(the default): the editor runs its command; the menu item does not run."app": the menu item runs; the editor does not see the key."both": the menu item runs and the editor runs its command.
源码const MENU_SHORTCUT_CONFLICTS: readonly MenuShortcutConflict[]Every value
menuShortcutConflictcan have.
A menu for an app that shows the editor
- Make Undo and Redo plain items, not roles. The
undorole runs the page’s text undo, which does nothing on the canvas. CallTacoDesignView.undoandTacoDesignView.redowhen the canvas or a panel has the keyboard, and do what the role does when a text field has it. - Keep Cut, Copy, Paste and Select All as roles. Text fields need them, and on macOS paste in the editor needs the
pasterole to exist. - Leave out the zoom roles (
zoomIn,zoomOut,resetZoom): they scale the whole view. Cmd with plus, minus and 0 zoom the canvas. - Call one save function from the menu’s Save item and from the
saveRequestedlistener. With"both"it would run twice; switchfile.saveoff (shortcuts: { "file.save": null }) then. - Give no
reloadrole an accelerator: Cmd+R is Rename in the editor, and a reload that does not go throughTacoDesignView.reloadloses the edits since the last read.
The File, Edit and View items of the sample app’s menu template:
{
label: "File",
submenu: [
{ id: SAVE_MENU_ID, label: "Save", accelerator: "CmdOrCtrl+S", click: () => options.save() },
{ type: "separator" },
mac ? { role: "close" } : { role: "quit" },
],
},
{
label: "Edit",
submenu: [
{ id: UNDO_MENU_ID, label: "Undo", accelerator: "CmdOrCtrl+Z", click: history("undo") },
{ id: REDO_MENU_ID, label: "Redo", accelerator: "Shift+CmdOrCtrl+Z", click: history("redo") },
{ type: "separator" },
{ role: "cut" },
{ role: "copy" },
{ role: "paste" },
{ role: "selectAll" },
],
},
// No zoom roles here: they would scale the whole view.
{ label: "View", submenu: [{ role: "togglefullscreen" }] },apps/electron-sample/appMenu.mjs,第 89 至 110 行The guide’s step Keyboard and menus builds the whole menu. The package’s README says how each setting is carried out in Electron, and what is not proven on Windows and Linux.
Security settings and versions
createTacoDesignView sets all of this, so the app does not have to: the page runs in a sandbox with context isolation and without Node.js, in its own storage partition; it may only move inside taco-design://app/ and may open no window; every answer carries the content security policy below; and only the listed permissions are granted, only to the editor’s own page.
源码const CONTENT_SECURITY_POLICY: stringSent with every answer.
'wasm-unsafe-eval'lets the renderer compile;'unsafe-inline'styles are for the editor’s inline styles. There is no'unsafe-eval'and no inline script.https://fonts.gstatic.comis the only other site, used to fetch a Google font the first time a document needs it.
源码const ALLOWED_PERMISSIONS: readonly string[]The only permissions the editor page is given: listing installed fonts, the clipboard, and keeping its storage from being cleared under disk pressure. Everything else (camera, microphone, location, notifications, ...) is refused.
源码const DEFAULT_PARTITION: "persist:taco-design"The partition used when the app names none.
persist:keeps it on disk.
源码const HOST_PROTOCOL_VERSION: 1Counts up by one when a change would confuse an older host or page.
These additions do not count, so they keep the number: a new request (a page that does not know it answers
unknown-method), a new event (a host skips events it does not know), a new optional parameter or result field, and a new error code (it arrives as a string with its message). Changing or removing a message, or changing what an existing one means, counts.Still 1 after the export, selection, view and reload messages were added, and after the shortcut requests (
getShortcuts,setShortcuts), thesaveRequestedevent and the four shortcut error codes, and after thenewDocumentrequest.
Design reads and plans
TacoDesignView.designRequest uses the explicit binding advertised by getState().design. createDesignClient validates operation arguments and results with the shared catalog. Public mutations remain disabled; geometry is stored model geometry. design events are stamped invalidations, not a resumable log.
源码const DESIGN_PROTOCOL_VERSION: "taco.design/1.0.0"Version of the design envelope, independent of document schema and renderer wire versions.
源码function createDesignClient( send: (request: DesignRequest) => Promise<DesignReply>, target: DesignBinding, requestId: () => string )A typed transport adapter; the host supplies the binding returned by discovery.
源码class DesignError extends Errorreadonly committed: false源码Read and planning failures never commit a document change.
new (readonly code: string, message: string, readonly path = "$")源码
源码type DesignArguments< K extends DesignOperation > = Infer<(typeof operations)[K]["input"]>Arguments validated by the catalog for an operation.
源码type DesignBinding = Infer<typeof bindingSchema>Identifies one editor and one document opening; never substitute a new epoch on retry.
源码interface DesignCapabilityCapability advertised by getState; public mutation remains disabled.
readonly versions: readonly string[]源码readonly binding: DesignBinding源码readonly mutationEnabled: false源码
源码type DesignCommand = Infer<typeof commandSchema>A duplicate or translate command accepted by the read-only planner.
源码interface DesignEventStamped invalidation; not a resumable synchronization log.
readonly binding: DesignBinding源码readonly revision: number源码readonly kind: "reset" | "transition"源码
源码type DesignOperation = keyof typeof operationsOperations supported by this version of the read and planning catalog.
源码type DesignReply = | { readonly ok: true; readonly requestId: string; readonly result: unknown } | { readonly ok: false; readonly requestId: string; readonly error: { readonly code: string; readonly message: string; readonly path: string; readonly committed: false; }; }Domain errors retain their code, path and committed flag, separate from transport failures.
源码type DesignRequest = { [K in DesignOperation]: { readonly protocol: typeof DESIGN_PROTOCOL_VERSION; readonly requestId: string; readonly target: DesignBinding; readonly operation: K; readonly arguments: DesignArguments<K>; } }[DesignOperation]A versioned request with an explicit document-opening target.
源码type DesignResult< K extends DesignOperation > = Infer<(typeof operations)[K]["output"]>Result validated by the catalog for an operation.
源码type DesignTarget = Infer<typeof targetReferenceSchema>A canonical node or a layer within a component instance.
源码interface TacoDesignRequestOptionsLimits the entire design call, including startup and capability discovery.
readonly timeoutMs?: number源码Default 30 seconds. Must be a positive integer no greater than 2,147,483,647.
readonly signal?: AbortSignal源码Stops waiting and prevents unstarted requests; does not undo a completed remote plan.
C++ 渲染器 C++
310 个条目中已记录 157 个 · 大纲
packages/render-core/cpp 中的 C++ 渲染器只有一个公开接口:include/taco/render_core.h 中的 C 函数和类型。本页的其余内容都是这些函数所调用的内部 C++ 代码。C ABI 是纯 C,因此同一个头文件同时服务于原生构建、测试和 Wasm 构建。
所有工作都在会话上进行。taco_render_session_create 创建一个空会话,taco_render_session_apply 向它输入二进制场景批次(参见 PROTOCOL.md),查询、渲染和叠加层函数则读取它。每个可能失败的函数都返回一个 TacoRenderStatus;大多数失败还会留下一条消息,供 taco_render_session_copy_last_error 读取。输出结构体以一个由调用方设置的 struct_size 字段开头;填充调用方缓冲区的调用会报告所需的大小,并在缓冲区不足时返回 TACO_RENDER_STATUS_BUFFER_TOO_SMALL。针对编辑状态的调用接收它们期望的场景代次,并在场景已经更新时返回 TACO_RENDER_STATUS_STALE_GENERATION。
WebGPU Wasm 构建通过 Emscripten 导出这些 taco_render_* 函数,同时导出 malloc、free 以及它自己的 taco_render_webgpu_* 辅助函数。TypeScript 包以 module._taco_render_session_apply 等形式调用它们,并传入指向 Wasm 堆的指针。一个更小的可移植 Wasm 构建不含 Skia,也不进行绘制;它改为导出“Wasm bridge”下列出的 taco_render_wasm_* 函数。
在 C 函数背后,RetainedSession 保存场景及其计算出的几何信息,SessionCache 保存 Skia 一侧的内容:字体、文本布局、媒体帧、叠加层和增量渲染的脏区域。不含 Skia 的构建保留场景和几何查询,但任何需要绘制或进行文本排版的调用都会返回 TACO_RENDER_STATUS_CAPABILITY_UNAVAILABLE。
版本与能力
ABI 和 wire 格式的版本常量,以及两个报告本构建能力的调用。扩展能力通过追加字段来增长,因此调用方请求自己能理解的版本。
源码#define TACO_RENDER_ABI_VERSION 1u该 C ABI 的版本。
TacoRenderSessionOptions.abi_version必须等于它,TacoRenderCapabilities.abi_version会报告它。TypeScript:
RENDER_CORE_ABI_VERSION
源码#define TACO_RENDER_WIRE_VERSION 24u最新的保留场景/变更批次 wire 格式版本。一个批次可以声明从 1 到此版本之间的任意版本;更新的版本会以
UNSUPPORTED_VERSION失败。TypeScript:
RENDER_CORE_WIRE_VERSION
源码#define TACO_RENDER_VECTOR_NETWORK_WIRE_VERSION 5u无头部的独立
VectorNetwork载荷版本。TypeScript:
RENDER_CORE_VECTOR_NETWORK_WIRE_VERSION
源码#define TACO_RENDER_EXTENDED_CAPABILITIES_VERSION 8utaco_render_get_extended_capabilities接受的最新版本。每个版本 N 都有对应的 _VERSION_N 和 _VERSION_N_SIZE(该版本所需的结构体大小)。
wasm源码TacoRenderStatus taco_render_get_capabilities( TacoRenderCapabilities *capabilities ) noexcept填充版本 1 的能力结构体。调用方设置
struct_size;它必须至少为 sizeof(TacoRenderCapabilities),否则调用返回INVALID_ARGUMENT。不需要会话。由 TS 调用,位于这些条目的辅助函数中:
PortableWasmRenderCoreModule.constructor,createOwnedWasmRenderCoreSession,attachPortableWasmRenderCoreSession
源码struct TacoRenderCapabilities此构建支持的功能,由
taco_render_get_capabilities写入。调用方设置struct_size。每个uint8_t字段在支持时为 1。Skia 相关字段(skia、native_raster、skparagraph、harfbuzz、icu)仅在 Skia 构建中为 1;此调用总是将 wasm 和 webgpu 写为 0。较新的功能改由TacoRenderExtendedCapabilities报告。TypeScript:
PORTABLE_WASM_ABI_LAYOUT,RenderCoreCapabilitiesuint32_t struct_size源码uint32_t abi_version源码uint32_t wire_version源码uint8_t retained_scene源码uint8_t structured_paths源码uint8_t styled_text_records源码uint8_t embedded_resources源码uint8_t skia源码uint8_t native_raster源码uint8_t wasm源码uint8_t webgpu源码uint8_t skparagraph源码uint8_t harfbuzz源码uint8_t icu源码uint8_t geometry_queries源码uint8_t hit_testing源码uint8_t dirty_bounds源码uint8_t[2] reserved源码
wasm源码TacoRenderStatus taco_render_get_extended_capabilities( uint32_t capabilities_version, TacoRenderExtendedCapabilities *capabilities ) noexcept填充扩展能力,直到
capabilities_version(1 到TACO_RENDER_EXTENDED_CAPABILITIES_VERSION)为止。只写入前TACO_RENDER_EXTENDED_CAPABILITIES_VERSION_N_SIZE个字节,因此使用较小结构体的旧调用方仍然安全。版本未知时返回UNSUPPORTED_VERSION,struct_size小于该版本的大小时返回INVALID_ARGUMENT。不需要会话。由 TS 调用,位于这些条目的辅助函数中:
PortableWasmRenderCoreModule.constructor,createOwnedWasmRenderCoreSession,attachPortableWasmRenderCoreSession
源码struct TacoRenderExtendedCapabilities只追加的能力信息,有意与已冻结的 ABI 版本 1
TacoRenderCapabilities布局分开。调用方请求一个已声明的版本并提供struct_size;所有保留字节都写为零。TypeScript:
PORTABLE_WASM_ABI_LAYOUT,RenderCoreCapabilitiesuint32_t struct_size源码uint32_t capabilities_version源码uint32_t text_query_version源码uint8_t text_carets源码uint8_t text_range_rects源码uint8_t text_hit_testing源码uint8_t text_layout_metrics源码uint8_t text_editing_overlays源码uint8_t[14] reserved源码uint32_t vector_query_version源码版本 2 追加的字段。版本 1 的调用方只能看到前 32 字节。
uint8_t vector_geometry源码uint8_t vector_hit_testing源码uint8_t[2] reserved_v2源码uint32_t vector_editing_overlay_version源码版本 3 追加的字段。版本 2 的调用方只能看到前 40 字节。
uint8_t vector_editing_overlays源码uint8_t[3] reserved_v3源码uint32_t vector_boolean_version源码版本 4 追加的字段。版本 3 的调用方只能看到前 48 字节。
uint8_t vector_boolean_operations源码uint8_t[3] reserved_v4源码uint32_t font_metadata_version源码版本 5 追加的字段。版本 4 的调用方只能看到前 56 字节。
uint8_t font_metadata源码uint8_t[3] reserved_v5源码uint32_t incremental_render_version源码版本 6 追加的字段。版本 5 的调用方只能看到前 64 字节。
uint8_t incremental_rendering源码uint8_t render_diagnostics源码uint8_t[2] reserved_v6源码uint32_t static_image_frame_version源码版本 7 追加的字段。版本 6 的调用方只能看到前 72 字节。
uint8_t static_image_frames源码uint8_t[3] reserved_v7源码uint32_t video_frame_version源码版本 8 追加的字段。版本 7 的调用方只能看到前 80 字节。
uint8_t video_frames源码uint8_t[3] reserved_v8源码
会话与状态码
一个会话持有一个保留场景。可以创建、销毁会话,并读取失败状态背后的消息。
不透明类型源码struct TacoRenderSession不透明的渲染器会话:一个保留场景,以及(在 Skia 构建中)用于绘制它的缓存、帧和叠加层。使用
taco_render_session_create创建,使用taco_render_session_destroy释放。会话不是线程安全的;同一时间只能从一个线程调用它。
wasm源码TacoRenderStatus taco_render_session_create( const TacoRenderSessionOptions *options, TacoRenderSession **session ) noexcept创建一个空会话并存入
*session(失败时为NULL)。options 可以为NULL。提供 options 时,abi_version不一致返回UNSUPPORTED_VERSION,struct_size小于 sizeof(TacoRenderSessionOptions) 返回INVALID_ARGUMENT。由 TS 调用:
InteractiveRetainedBackend.exportCompiledScene,InteractiveRetainedBackend.outlineCompiledStrokes由 TS 调用,位于这些条目的辅助函数中:
RenderCoreModule.createSession,PortableWasmRenderCoreModule.createSession,createOwnedWasmRenderCoreSession
源码struct TacoRenderSessionOptionstaco_render_session_create的可选设置。将struct_size设为 sizeof(TacoRenderSessionOptions),将abi_version设为TACO_RENDER_ABI_VERSION。目前还没有其他选项。TypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t struct_size源码uint32_t abi_version源码uint32_t[6] reserved源码
wasm源码void taco_render_session_destroy(TacoRenderSession *session) noexcept释放一个会话及其拥有的一切。允许传入
NULL。由 TS 调用:
RenderCoreSession.dispose,RenderCoreModule.createSession,PortableWasmRenderCoreModule.createSession,createOwnedWasmRenderCoreSession由 TS 调用,经由
RenderCoreSession.dispose:outlineStrokesInThrowawaySession
源码enum TacoRenderStatus所有可能失败的 C 函数的返回结果。大多数失败还会保存一条消息,可由
taco_render_session_copy_last_error返回;taco_render_status_name给出该常量的名称。TypeScript:
RENDER_CORE_STATUSTACO_RENDER_STATUS_OK = 0源码TACO_RENDER_STATUS_INVALID_ARGUMENT = 1源码空指针、过小的
struct_size,或无效的值。TACO_RENDER_STATUS_UNSUPPORTED_VERSION = 2源码此构建不接受的 ABI、wire 格式或载荷版本。
TACO_RENDER_STATUS_MALFORMED_BATCH = 3源码批次字节被截断,或不符合 wire 格式。
TACO_RENDER_STATUS_LIMIT_EXCEEDED = 4源码超出了大小、数量或字节数限制。
TACO_RENDER_STATUS_INVALID_SCENE = 5源码场景,或调用需要从场景中获取的数据无效。
TACO_RENDER_STATUS_NOT_FOUND = 6源码指定的节点或资源不存在。
TACO_RENDER_STATUS_CAPABILITY_UNAVAILABLE = 7源码此构建无法执行该操作,例如在没有 Skia 的情况下绘制。
TACO_RENDER_STATUS_BUFFER_TOO_SMALL = 8源码输出缓冲区过小;所需的大小仍会被写入。
TACO_RENDER_STATUS_INTERNAL_ERROR = 9源码原生层面的失败,例如内存分配失败或异常。
TACO_RENDER_STATUS_STALE_GENERATION = 10源码调用传入的
expected_generation不是场景的当前代次。
wasm源码size_t taco_render_session_copy_last_error( const TacoRenderSession *session, char *destination, size_t destination_size ) noexcept把会话的最后一条错误信息复制为以 NUL 结尾的字符串,并返回所需的字节数(包括末尾的 NUL)。复制内容会截断为
destination_size- 1 个字节;传 0 可查询所需大小。大多数成功的调用会清除该信息,但并非每次失败都会设置它,所以请先检查状态码。NULL会话得到空信息。由 TS 调用,位于这些条目的辅助函数中:
RenderCoreSession.apply,RenderCoreSession.applyWithStaticImageFrames,RenderCoreSession.applyWithMediaFrames,RenderCoreSession.updateVideoFrames,RenderCoreSession.getSceneInfo,RenderCoreSession.getNodeGeometry,RenderCoreSession.getGeometrySnapshot,PortableWasmRenderCoreSession.exportScene另有 21 项
RenderCoreSession.hitTest,RenderCoreSession.getTextCarets,RenderCoreSession.getTextRangeGeometry,RenderCoreSession.hitTestText,RenderCoreSession.navigateText,RenderCoreSession.getTextLayoutMetrics,RenderCoreSession.getFontMetadata,RenderCoreSession.setTextEditingOverlay,RenderCoreSession.setSelectionChrome,RenderCoreSession.setCanvasOverlayFont,RenderCoreSession.setCanvasOverlay,RenderCoreSession.clearTextEditingOverlay,RenderCoreSession.getVectorGeometry,RenderCoreSession.hitTestVector,RenderCoreSession.setVectorEditingOverlay,RenderCoreSession.clearVectorEditingOverlay,PortableWasmRenderCoreSession.outlineStroke,RenderCoreSession.booleanVectorPaths,RenderCoreSession.mapViewport,RenderCoreSession.render,RenderCoreSession.getLastError由 TS 调用,经由
RenderCoreSession.apply:outlineStrokesInThrowawaySession由 TS 调用,经由
RenderCoreSession.getSceneInfo:outlineStrokesInThrowawaySession,measureExportFromLoadedSession由 TS 调用,经由
PortableWasmRenderCoreSession.outlineStroke:outlineStrokesInThrowawaySession由 TS 调用,经由
RenderCoreSession.getNodeGeometry:measureExportFromLoadedSession由 TS 调用,经由
measureExportFromLoadedSession:exportFromLoadedSession由 TS 调用,经由
PortableWasmRenderCoreSession.exportScene:exportFromLoadedSession
源码const char *taco_render_status_name(TacoRenderStatus status) noexcept返回状态码的静态名称,例如 “OK” 或 “
STALE_GENERATION”;对于TacoRenderStatus之外的值,返回 “UNKNOWN_STATUS”。
场景更新
一个批次要么一次性改动整个场景,要么完全不改动。含有图片或视频的场景还会传入解码后的帧,因此像素与场景始终对应同一代号。
wasm源码TacoRenderStatus taco_render_session_apply( TacoRenderSession *session, const uint8_t *batch, size_t batch_size, TacoRenderUpdateReport *report ) noexcept应用一个完整的保留场景批次(
PROTOCOL.md中的“TCR1” wire 格式)。批次要么全部生效,要么全部不生效:失败时场景保持不变,不写入报告,状态码通常为MALFORMED_BATCH、UNSUPPORTED_VERSION、LIMIT_EXCEEDED或INVALID_SCENE。report 可以为NULL。至少包含一条命令的批次会使代次加一。在 Skia 构建中,成功的应用还会丢弃所有已安装的图片帧和视频帧,因此包含媒体的场景应改用
taco_render_session_apply_with_media_frames;代次变化还会清除文本和矢量编辑叠加层。由 TS 调用:
InteractiveRetainedBackend.apply,InteractiveRetainedBackend.exportCompiledScene,InteractiveRetainedBackend.outlineCompiledStrokes,RenderChangeBatchEncoder,RenderCoreSession.apply由 TS 调用,经由
InteractiveRetainedBackend.apply:InteractiveRenderSession.loadDocument,InteractiveRenderSessionCoordinator.loadDocument,InteractiveRenderSession.applyDocumentUpdate,InteractiveRenderSessionCoordinator.applyDocumentUpdate,InteractiveRenderSession.setActivePage,InteractiveRenderSessionCoordinator.setActivePage由 TS 调用,经由
RenderCoreSession.apply:outlineStrokesInThrowawaySession实现者:
RetainedSession.state,RetainedSession.apply,SessionCache.recordSuccessfulApply,SessionCache.invalidateMediaFrames,SessionCache.recordSceneUpdateTime
源码struct TacoRenderUpdateReport在批次成功应用后写入。
commands_applied统计该批次的命令数;node_count和resource_count描述应用批次之后的场景。每个至少包含一条命令的批次都会使 generation 加一,scene_digest是保留场景内容的哈希值。TypeScript:
PORTABLE_WASM_ABI_LAYOUT,RenderUpdateReportuint32_t struct_size源码uint32_t commands_applied源码uint32_t node_count源码uint32_t resource_count源码uint64_t generation源码uint64_t scene_digest源码
wasm源码TacoRenderStatus taco_render_session_apply_with_static_image_frames( TacoRenderSession *session, const uint8_t *batch, size_t batch_size, const TacoRenderStaticImageFrameSet *frame_set, TacoRenderUpdateReport *report ) noexcept原子地应用一个保留场景批次,并安装该候选代次精确的静态图片集合。除非整个事务成功,否则场景、图片缓存、待处理的脏区域和报告都保持不变。Portable/无 Skia 构建返回
CAPABILITY_UNAVAILABLE。frame_set->
expected_generation必须是应用批次之前的代次(否则返回STALE_GENERATION)。这些帧必须按资源 ID 升序、每个恰好一次地指定新场景使用的每个图片资源;缺少或多出的 ID 返回INVALID_SCENE。包含视频的场景返回CAPABILITY_UNAVAILABLE;这种场景请使用taco_render_session_apply_with_media_frames。由 TS 调用:
InteractiveRetainedBackend.exportCompiledScene,RenderCoreSession.applyWithStaticImageFrames实现者:
RetainedSession.state,SessionCache.applyWithStaticImageFrames,SessionCache.recordSceneUpdateTime,isValidUtf8
wasm源码TacoRenderStatus taco_render_session_apply_with_media_frames( TacoRenderSession *session, const uint8_t *batch, size_t batch_size, const TacoRenderMediaFrameSet *frame_set, TacoRenderUpdateReport *report ) noexcept原子地应用一个保留场景批次,并安装该候选代次精确的图片/视频混合帧集合。除非整个事务成功,否则不会发布任何场景、帧缓存、脏区域或报告状态。
规则与
taco_render_session_apply_with_static_image_frames相同,但帧可以是图片或视频(由每条记录的类型决定),并且合起来要指定新场景使用的每个媒体资源。Portable/无 Skia 构建返回CAPABILITY_UNAVAILABLE。由 TS 调用:
RenderCoreSession.applyWithMediaFrames实现者:
RetainedSession.state,SessionCache.applyWithMediaFrames,SessionCache.recordSceneUpdateTime
源码struct TacoRenderStaticImageFrameSetexpected_generation是应用该批次之前的当前代次。TypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t struct_size源码uint32_t reserved源码uint64_t expected_generation源码const TacoRenderStaticImageFrame *frames源码size_t frame_count源码
源码struct TacoRenderStaticImageFrame一个完整的、按逻辑资源 ID 去重的静态图片集合中的一个成员。
content_revision是由调用方持有的、稳定且非零的内容标识。REUSE_ACTIVE只提供标识符、kind 和 revision;所有像素字段都为零或 null,并且当前活动的缓存中必须包含相同的 revision。RGBA8888 提供紧密排列、非预乘的 RGBA8888 sRGB 像素。版本 1 要求记录大小与此完全一致、row_bytes== width * 4,并且byte_length精确匹配;外围数组没有独立的记录跨度(stride)。TypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t struct_size源码uint32_t disposition源码uint32_t kind源码uint32_t reserved源码const char *asset_id源码size_t asset_id_size源码uint64_t content_revision源码uint32_t width源码uint32_t height源码uint32_t row_bytes源码uint32_t reserved_v1源码const uint8_t *pixels源码size_t byte_length源码
wasm源码TacoRenderStatus taco_render_session_update_video_frames( TacoRenderSession *session, const TacoRenderMediaFrameSet *frame_set, TacoRenderDirtyBounds *dirty_bounds ) noexcept替换完整的视频帧集合,而不改变保留场景的标识。代次(generation)、摘要(digest)、历史和编辑权限都保持不变。成功时,
dirty_bounds包含所有使用了已变化视频资源的可见节点的并集。portable/no-Skia 构建返回CAPABILITY_UNAVAILABLE。每一帧都必须是视频帧,并且该集合必须恰好命名场景中的每个视频资源一次。它要求当前代次已有一个由
taco_render_session_apply_with_media_frames安装的当前混合集合;否则返回INVALID_SCENE。由 TS 调用:
RenderCoreSession.updateVideoFrames
场景查询
读回场景:它的尺寸和计数、单个节点的值和几何、所有节点的几何(一次性获取)、点命中、上次更新改动的区域,以及场景如何映射到视口中。
wasm源码TacoRenderStatus taco_render_session_get_scene_info( const TacoRenderSession *session, TacoRenderSceneInfo *info ) noexcept写出场景的尺寸、各项计数、代次和摘要。
由 TS 调用:
InteractiveRetainedBackend.getSceneInfo,RenderCoreSession.getSceneInfo由 TS 调用,位于这些条目的辅助函数中:
RenderCoreSession.updateVideoFrames,RenderCoreSession.getTextCarets,RenderCoreSession.getTextRangeGeometry,RenderCoreSession.hitTestText另有 11 项
RenderCoreSession.navigateText,RenderCoreSession.getTextLayoutMetrics,RenderCoreSession.getFontMetadata,RenderCoreSession.setTextEditingOverlay,RenderCoreSession.clearTextEditingOverlay,RenderCoreSession.getVectorGeometry,RenderCoreSession.hitTestVector,RenderCoreSession.setVectorEditingOverlay,RenderCoreSession.clearVectorEditingOverlay,PortableWasmRenderCoreSession.outlineStroke,RenderCoreSession.booleanVectorPaths由 TS 调用,经由
InteractiveRetainedBackend.getSceneInfo:InteractiveRenderSession.getSceneGeometrySnapshot,InteractiveRenderSession.getVectorGeometry,InteractiveRenderSession.hitTestVector,InteractiveRenderSession.loadDocument,InteractiveRenderSessionCoordinator.loadDocument,InteractiveRenderSession.applyDocumentUpdate,InteractiveRenderSessionCoordinator.applyDocumentUpdate,InteractiveRenderSession.setActivePage另有 18 项
InteractiveRenderSessionCoordinator.setActivePage,InteractiveRenderSessionCoordinator.getSceneGeometrySnapshot,InteractiveRenderSession.getTextGeometry,InteractiveRenderSessionCoordinator.getTextGeometry,InteractiveRenderSession.hitTestText,InteractiveRenderSessionCoordinator.hitTestText,InteractiveRenderSession.navigateText,InteractiveRenderSessionCoordinator.navigateText,InteractiveRenderSessionCoordinator.getVectorGeometry,InteractiveRenderSessionCoordinator.hitTestVector,InteractiveRenderSession.booleanVectorPaths,InteractiveRenderSessionCoordinator.booleanVectorPaths,InteractiveRenderSession.renderFrame,InteractiveRenderSessionCoordinator.renderFrame,InteractiveRenderSessionCoordinator.getSceneInfo,InteractiveRenderSessionCoordinator.getTextLayoutMetrics,InteractiveRenderSessionCoordinator.getFontMetadata,InteractiveRenderSessionCoordinator.resolveAccessibilityActionRouteV1由 TS 调用,经由
RenderCoreSession.getSceneInfo:outlineStrokesInThrowawaySession,measureExportFromLoadedSession由 TS 调用,经由
PortableWasmRenderCoreSession.outlineStroke:outlineStrokesInThrowawaySession由 TS 调用,经由
measureExportFromLoadedSession:exportFromLoadedSession
源码struct TacoRenderSceneInfo场景当前的尺寸(以场景单位计)、节点数与资源数、代次和摘要。由
taco_render_session_get_scene_info写入。TypeScript:
PORTABLE_WASM_ABI_LAYOUT,RenderSceneInfouint32_t struct_size源码uint32_t node_count源码uint32_t resource_count源码uint32_t reserved源码double width源码double height源码uint64_t generation源码uint64_t scene_digest源码
源码TacoRenderStatus taco_render_session_get_node_info( const TacoRenderSession *session, const char *node_id, size_t node_id_size, TacoRenderNodeInfo *info ) noexcept写出一个节点作者设置的类型、z 顺序、可见性、变换、不透明度和最宽描边。
node_id是node_id_size个字节的 UTF-8,不以 NUL 结尾,且不能为空。节点未知时返回NOT_FOUND。实现者:
RetainedSession.findNode,Node.kind,NodeStyle.maximumStrokeWidth
源码struct TacoRenderNodeInfo节点的设计值(由作者设置的值),由
taco_render_session_get_node_info写入。kind 是一个TacoRenderNodeKind值。transform 是节点自身的局部变换,形式为 (a, b, c, d, e, f),其中 x’ = a*x + c*y + e,y’ = b*x + d*y + f。stroke_width是节点所有描边中最宽的宽度;没有描边时为 0。uint32_t struct_size源码uint32_t kind源码int32_t z_order源码uint8_t visible源码uint8_t[3] reserved源码double[6] transform源码double opacity源码double stroke_width源码
wasm源码TacoRenderStatus taco_render_session_get_node_geometry( const TacoRenderSession *session, const char *node_id, size_t node_id_size, TacoRenderNodeGeometry *geometry ) noexcept写出一个节点计算得到的几何信息:世界变换,局部、世界和可见边界,绘制顺序以及有效不透明度。节点未知时返回
NOT_FOUND。由 TS 调用:
InteractiveRetainedBackend.getNodeGeometry,RenderCoreSession.getNodeGeometry由 TS 调用,经由
InteractiveRetainedBackend.getNodeGeometry:InteractiveRenderSession.getNodeGeometry,InteractiveRenderSessionCoordinator.getNodeGeometry由 TS 调用,经由
RenderCoreSession.getNodeGeometry:measureExportFromLoadedSession由 TS 调用,经由
measureExportFromLoadedSession:exportFromLoadedSession实现者:
RetainedSession.findNode,RetainedSession.geometrySnapshot
源码struct TacoRenderNodeGeometry译文已过期
A node’s computed geometry, written by
taco_render_session_get_node_geometry. Each has_* byte says whether the matching bounds are present.world_boundsare in scene coordinates;visible_world_boundsare also clipped by clipping ancestors and are absent when the node is not effectively visible.painter_orderis the node’s back-to-front paint position, andeffective_opacityandeffectively_visibleinclude every ancestor.subtree_visible_boundsjoins the node’s visible bounds with those of all its descendants, the way they are painted: children of a clipping frame are clipped to it, a masked sibling is clipped to its mask, and a node’s layer blur spreads around its descendants too. So it covers everything the subtree paints. Callers built before it was appended may pass the shorter struct_size; the tail is then left unwritten.TypeScript:
PORTABLE_WASM_ABI_LAYOUT,RenderNodeGeometryuint32_t struct_size源码uint32_t kind源码uint8_t has_local_bounds源码uint8_t has_world_bounds源码uint8_t has_visible_world_bounds源码uint8_t effectively_visible源码uint64_t painter_order源码double effective_opacity源码double[6] world_transform源码TacoRenderRect local_bounds源码TacoRenderRect world_bounds源码TacoRenderRect visible_world_bounds源码uint8_t has_subtree_visible_bounds源码uint8_t[7] reserved源码TacoRenderRect subtree_visible_bounds源码
wasm源码TacoRenderStatus taco_render_session_get_geometry_snapshot( const TacoRenderSession *session, TacoRenderGeometryRecord *records, size_t record_capacity, char *node_id_bytes, size_t node_id_capacity, uint64_t *generation, size_t *record_count, size_t *node_id_byte_count ) noexcept几何记录按绘制顺序从后到前返回。即使提供的缓冲区太小,也会写入代次和两个所需计数。在两个缓冲区都足够之前,不会写入任何记录或标识符字节。
任一缓冲区不足时返回
BUFFER_TOO_SMALL;可先传容量 0 查询所需大小。节点标识符在node_id_bytes中首尾相接地紧凑排列,每条记录都指向其中的位置。由 TS 调用:
InteractiveRetainedBackend.getGeometrySnapshot,RenderCoreSession.getGeometrySnapshot由 TS 调用,经由
InteractiveRetainedBackend.getGeometrySnapshot:InteractiveRenderSession.getSceneGeometrySnapshot,InteractiveRenderSessionCoordinator.getSceneGeometrySnapshot实现者:
RetainedSession.geometrySnapshot,RetainedSession.state
源码struct TacoRenderGeometryRecordtaco_render_session_get_geometry_snapshot中的一个节点。它包含与TacoRenderNodeGeometry相同的值,只是 has_* 字节被打包进 flags(TacoRenderGeometryFlags)。节点标识符是该调用的标识符缓冲区中,从node_id_offset开始的node_id_size个字节。TypeScript:
decodeWasmGeometryRecords,PORTABLE_WASM_ABI_LAYOUT,RenderNodeGeometryTypeScript,经由
decodeWasmGeometryRecords:RenderCoreSession.getGeometrySnapshotuint32_t struct_size源码uint32_t node_id_offset源码uint32_t node_id_size源码uint32_t kind源码uint32_t flags源码uint32_t reserved源码uint64_t painter_order源码double effective_opacity源码double[6] world_transform源码TacoRenderRect local_bounds源码TacoRenderRect world_bounds源码TacoRenderRect visible_world_bounds源码
wasm源码TacoRenderStatus taco_render_session_hit_test( const TacoRenderSession *session, double world_x, double world_y, double world_tolerance, TacoRenderHit *hits, size_t hit_capacity, char *node_id_bytes, size_t node_id_capacity, size_t *hit_count, size_t *node_id_byte_count ) noexcept查找场景点(
world_x,world_y)下的可见节点;对路径而言,距离在world_tolerance个场景单位以内也算命中。祖先节点的裁剪会生效。命中结果按从最上层到最下层的顺序返回。hit_count和node_id_byte_count总会收到所需的大小;任一缓冲区过小时,不会写入其他内容,调用返回BUFFER_TOO_SMALL。输入必须是有限值,容差必须非负。由 TS 调用:
InteractiveRetainedBackend.hitTest,RenderCoreSession.hitTest由 TS 调用,经由
InteractiveRetainedBackend.hitTest:InteractiveRenderSession.hitTest,InteractiveRenderSessionCoordinator.hitTest,InteractiveRenderSessionCoordinator.hitTestIncludingLocked
源码struct TacoRenderHit某点下方的一个节点,由
taco_render_session_hit_test写入。节点标识符是该调用的标识符缓冲区中,从node_id_offset开始的node_id_size个字节。kind 是一个TacoRenderNodeKind值。TypeScript:
decodeWasmHitRecords,PORTABLE_WASM_ABI_LAYOUT,RenderHitTypeScript,经由
decodeWasmHitRecords:RenderCoreSession.hitTestuint32_t struct_size源码uint32_t node_id_offset源码uint32_t node_id_size源码uint32_t kind源码uint32_t reserved源码uint64_t painter_order源码TacoRenderRect visible_world_bounds源码
wasm源码TacoRenderStatus taco_render_session_get_last_dirty_bounds( const TacoRenderSession *session, TacoRenderDirtyBounds *dirty_bounds ) noexcept写出最近一次成功的批次应用在场景空间中改变的区域,并标上那一次的代次。
由 TS 调用,位于这些条目的辅助函数中:
RenderCoreSession.apply,RenderCoreSession.applyWithStaticImageFrames,RenderCoreSession.applyWithMediaFrames由 TS 调用,经由
RenderCoreSession.apply:outlineStrokesInThrowawaySession
源码struct TacoRenderDirtyBounds一次更新所改变的场景空间区域:
old_bounds覆盖变化节点之前绘制的内容,new_bounds覆盖它们之后绘制的内容,combined_bounds覆盖两者。每个 has_* 字节表示对应矩形是否已设置。TypeScript:
PORTABLE_WASM_ABI_LAYOUT,RenderDirtyBoundsuint32_t struct_size源码uint8_t has_old_bounds源码uint8_t has_new_bounds源码uint8_t has_combined_bounds源码uint8_t reserved源码uint64_t generation源码TacoRenderRect old_bounds源码TacoRenderRect new_bounds源码TacoRenderRect combined_bounds源码
wasm源码TacoRenderStatus taco_render_session_map_viewport( const TacoRenderSession *session, const TacoRenderViewportOptions *options, TacoRenderViewportMapping *mapping ) noexcept按适应(fit)、填满(fill)或拉伸(stretch)方式,以给定的对齐方式,计算场景的宽高如何映射到视口中。它只做计算,不改变任何状态。选项无效时返回
INVALID_ARGUMENT;场景没有正尺寸或结果不是有限值时返回INVALID_SCENE。由 TS 调用:
RenderCoreSession.mapViewport
源码struct TacoRenderViewportOptionstaco_render_session_map_viewport的输入。mode 是一个TacoRenderViewportMode值。视口尺寸必须是有限的正数。align_x和align_y取值均为 0 到 1,用于在剩余空间中放置场景:0 表示左侧或顶部,0.5 表示居中,1 表示右侧或底部。TypeScript:
PORTABLE_WASM_ABI_LAYOUT,ViewportMappingOptionsuint32_t struct_size源码uint32_t mode源码double viewport_width源码double viewport_height源码double align_x源码double align_y源码
源码struct TacoRenderViewportMappingtaco_render_session_map_viewport的输出:场景到视口的仿射变换、其逆变换(两者都表示为 a, b, c, d, e, f),以及场景在视口中的位置。TypeScript:
PORTABLE_WASM_ABI_LAYOUT,ViewportMappinguint32_t struct_size源码uint32_t reserved源码double[6] scene_to_viewport源码double[6] viewport_to_scene源码TacoRenderRect scene_viewport_bounds源码
渲染与导出
把场景绘制到调用方持有的 RGBA 像素中,可以完整绘制,也可以只绘制发生变化的部分;或者把某个区域导出为 RGBA、PNG、SVG 或 PDF 字节。
wasm源码TacoRenderStatus taco_render_session_render_rgba( TacoRenderSession *session, const TacoRenderRgbaTarget *target ) noexcept把整个场景绘制到目标中,将场景的宽高缩放到目标的宽高。每个像素都会在白色背景上重新绘制。编辑叠加层、画布叠加层和选区框与控制柄绘制在场景之上。在 portable/no-Skia 构建中返回
CAPABILITY_UNAVAILABLE;场景含有媒体、但没有已安装的当前帧集合时,也返回该状态码。由 TS 调用:
RenderCoreSession.render实现者:
renderRgba
源码struct TacoRenderRgbaTarget渲染调用使用的、由调用方持有的预乘 alpha RGBA8888 像素。
row_bytes必须至少为 width * 4,byte_length必须至少为row_bytes* height。TypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t struct_size源码uint32_t width源码uint32_t height源码uint32_t row_bytes源码uint8_t *pixels源码size_t byte_length源码
wasm源码TacoRenderStatus taco_render_session_render_rgba_incremental( TacoRenderSession *session, const TacoRenderRgbaTarget *target, const TacoRenderIncrementalRenderOptions *options, TacoRenderIncrementalFrameReport *report ) noexcept与
taco_render_session_render_rgba类似,但当目标的像素指针、尺寸和行跨度(row stride)都未变化时,只重绘自上次成功渲染以来发生变化的区域。否则,或者传入TACO_RENDER_INCREMENTAL_RENDER_FORCE_FULL时,重绘全部内容。options->expected_generation不是当前代次时返回STALE_GENERATION。成功时(包括没有任何内容需要重绘的帧)写入报告。portable/no-Skia 构建返回CAPABILITY_UNAVAILABLE。
源码struct TacoRenderIncrementalRenderOptionstaco_render_session_render_rgba_incremental的输入。flags 是TacoRenderIncrementalRenderFlags的按位或;expected_generation必须是场景的当前代次。uint32_t struct_size源码uint32_t flags源码uint64_t expected_generation源码
源码struct TacoRenderIncrementalFrameReport耗时是由原生核心测得的有限毫秒数。CPU 渲染将
submit_ms报告为零。未来的增量 WebGPU 桥接层在把帧暴露给 TypeScript 之前,必须加上其队列提交耗时。报告只在渲染成功之后写入(包括没有任何脏区域、成功完成的帧)。uint32_t struct_size源码uint32_t flags源码uint32_t nodes_painted源码uint32_t nodes_considered源码uint64_t generation源码uint64_t scene_digest源码TacoRenderDeviceRect device_damage源码double scene_update_ms源码double layout_ms源码double paint_ms源码double submit_ms源码uint64_t retained_payload_bytes源码uint32_t decoded_font_entries源码uint32_t text_layout_entries源码
wasm源码TacoRenderStatus taco_render_session_export( TacoRenderSession *session, const TacoRenderExportRequest *request, TacoRenderExportResult *result ) noexcept导出一个场景区域。这些字节归会话所有,直到下一次导出或会话销毁为止;用
taco_render_session_copy_export_bytes把它们复制出来。导出失败时不保留任何字节。result 只在成功时写入;result->byte_length是要复制的大小。Portable/无 Skia 构建返回CAPABILITY_UNAVAILABLE。由 TS 调用:
InteractiveRetainedBackend.exportCompiledScene,PortableWasmRenderCoreSession.exportScene由 TS 调用,经由
PortableWasmRenderCoreSession.exportScene:exportFromLoadedSession实现者:
exportScene
源码struct TacoRenderExportRequesttaco_render_session_export的输入;format 是一个TacoRenderExportFormat值。TypeScript:
RenderExportRequestuint32_t struct_size源码uint32_t format源码double x源码导出区域,使用场景坐标。
double y源码double width源码double height源码double scale源码const char *root_node_id源码可选。非空时只绘制此节点及其后代,因此与之重叠的兄弟节点和祖先节点不会出现在导出结果中。
size_t root_node_id_size源码uint32_t image_sampling源码图片填充和媒体帧的重采样方式;取值为
TacoRenderExportImageSampling。为零时沿用屏幕显示所用的双线性采样。uint32_t flags源码TacoRenderExportFlags值的按位或。double pdf_raster_dpi源码仅限 PDF:对 PDF 无法表达的效果(模糊、阴影)进行光栅化时使用的分辨率,单位为每英寸点数(DPI)。为零表示 72。
源码struct TacoRenderExportResulttaco_render_session_export成功时的输出。TypeScript:
RenderExportResultuint32_t struct_size源码uint32_t pixel_width源码输出尺寸:ceil(region * scale)。光栅格式以像素为单位使用该值。
uint32_t pixel_height源码uint32_t row_bytes源码TACO_RENDER_EXPORT_RGBA的每行字节数;其他所有格式为零。size_t byte_length源码uint32_t request_struct_size源码此构建读取的请求结构体大小,宿主据此可以判断图片采样、flags 和 PDF 分辨率字段是否已被采用。
源码enum TacoRenderExportFormat场景导出。保留场景中的一个矩形区域,经由与屏幕显示相同的绘制器绘制到以下某种目标中。编辑叠加层从不导出,背景保持透明。
TypeScript:
RenderExportFormat
wasm源码size_t taco_render_session_copy_export_bytes( const TacoRenderSession *session, uint8_t *destination, size_t destination_size ) noexcept复制最近一次成功导出的最多
destination_size个字节,并返回实际复制的字节数。session 或 destination 为NULL时返回 0。由 TS 调用:
PortableWasmRenderCoreSession.exportScene由 TS 调用,经由
PortableWasmRenderCoreSession.exportScene:exportFromLoadedSession
文本查询与文本编辑叠加层
单个文本节点的光标、选区矩形、命中测试、光标移动和尺寸度量,读取自与绘制时相同的布局。叠加层在用户编辑时绘制选区、输入法组合文本和光标。
wasm源码TacoRenderStatus taco_render_session_get_text_carets( TacoRenderSession *session, const char *node_id, size_t node_id_size, const TacoRenderTextQuery *query, TacoRenderTextCaret *carets, size_t caret_capacity, TacoRenderTextBufferResult *result ) noexcept文本查询。它们读取与绘制时相同的缓存布局,使用文本节点的局部坐标,并遵循以下共同规则:节点必须是文本节点(否则返回
INVALID_ARGUMENT,节点不存在时返回NOT_FOUND),查询的expected_generation必须是当前代次(否则返回STALE_GENERATION),portable/无 Skia 构建返回CAPABILITY_UNAVAILABLE。本函数写出文本的每个光标位置。
caret_capacity太小时(传 0 可查询),返回BUFFER_TOO_SMALL,并且只写入 result->required_count。光标数超过TACO_RENDER_TEXT_QUERY_MAX_RECORDS时返回LIMIT_EXCEEDED。由 TS 调用:
InteractiveRetainedBackend.getTextGeometry,RenderCoreSession.getTextCarets实现者:
SessionCache.getTextCaretCount,RetainedSession.state,SessionCache.getTextCarets
wasm源码TacoRenderStatus taco_render_session_get_text_range_rects( TacoRenderSession *session, const char *node_id, size_t node_id_size, const TacoRenderTextRangeQuery *query, TacoRenderTextRect *rects, size_t rect_capacity, TacoRenderTextBufferResult *result ) noexcept写出 query->anchor 与 query->focus 之间的选区矩形。大小协商方式与
taco_render_session_get_text_carets相同。位于文本之外的位置返回INVALID_ARGUMENT。由 TS 调用:
InteractiveRetainedBackend.getTextGeometry,RenderCoreSession.getTextRangeGeometry
wasm源码TacoRenderStatus taco_render_session_hit_test_text( TacoRenderSession *session, const char *node_id, size_t node_id_size, const TacoRenderTextHitQuery *query, TacoRenderTextHitResult *result ) noexcept查找距离节点局部坐标点最近的光标位置。当该点位于已排版的文本之上时,result->inside 为 1。
由 TS 调用:
InteractiveRetainedBackend.hitTestText,RenderCoreSession.hitTestText按一个
TacoRenderTextNavigationOperation移动光标位置。光标无法移动时,result->has_result为 0。向上或向下移动一行时,把返回的preferred_local_x传回,以保持光标所在的列。由 TS 调用:
InteractiveRetainedBackend.navigateText,RenderCoreSession.navigateText
wasm源码TacoRenderStatus taco_render_session_get_text_layout_metrics( TacoRenderSession *session, const char *node_id, size_t node_id_size, const TacoRenderTextQuery *query, TacoRenderTextLayoutMetrics *metrics ) noexcept写出文本的画框尺寸和内容尺寸、其自动调整大小模式建议的画框尺寸,以及段落数、行数和光标数。
由 TS 调用:
InteractiveRetainedBackend.getTextLayoutMetrics,RenderCoreSession.getTextLayoutMetrics
源码struct TacoRenderTextBufferResult对于有上限的查询,result 在 OK 和
BUFFER_TOO_SMALL时写入。在BUFFER_TOO_SMALL时,required_count是精确值,记录缓冲区不会被改动。其他任何失败都不会改动 result 和记录缓冲区。TypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t struct_size源码uint32_t required_count源码uint64_t generation源码
源码struct TacoRenderTextPosition相对于段落的偏移量,按设计时文本的 UTF-16 码元计数。
TypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t paragraph_index源码uint32_t utf16_offset源码uint32_t affinity源码uint32_t reserved源码
wasm源码TacoRenderStatus taco_render_session_set_text_editing_overlay( TacoRenderSession *session, const char *node_id, size_t node_id_size, const TacoRenderTextEditingOverlay *overlay ) noexcept在一个文本节点上绘制文本编辑叠加层:从
selection_anchor到selection_focus的选区、可选的输入法(IME)组合范围(标志HAS_COMPOSITION)以及光标(标志CARET_VISIBLE)。它会替换之前的任何文本叠加层,从不导出,并在下一次改变代次的批次应用时被清除。校验规则与文本查询相同;未知标志或超出文本范围的位置返回INVALID_ARGUMENT。由 TS 调用:
InteractiveRetainedBackend.setOverlays,RenderCoreSession.setTextEditingOverlay由 TS 调用,经由
InteractiveRetainedBackend.setOverlays:InteractiveRenderSession.setOverlays,InteractiveRenderSessionCoordinator.setOverlays
wasm源码TacoRenderStatus taco_render_session_clear_text_editing_overlay( TacoRenderSession *session, const TacoRenderTextQuery *query ) noexcept移除文本编辑叠加层。query->
expected_generation不是当前代次时返回STALE_GENERATION,在 portable/无 Skia 构建中返回CAPABILITY_UNAVAILABLE。由 TS 调用:
InteractiveRetainedBackend.setOverlays,RenderCoreSession.clearTextEditingOverlay由 TS 调用,经由
InteractiveRetainedBackend.setOverlays:InteractiveRenderSession.setOverlays,InteractiveRenderSessionCoordinator.setOverlays实现者:
RetainedSession.state,SessionCache.clearTextEditingOverlay
源码struct TacoRenderTextEditingOverlaytaco_render_session_set_text_editing_overlay的输入。flags 是TacoRenderTextEditingOverlayFlags的按位或;只有设置了HAS_COMPOSITION时才会读取组合范围。TypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t struct_size源码uint32_t flags源码uint64_t expected_generation源码TacoRenderTextPosition selection_anchor源码TacoRenderTextPosition selection_focus源码TacoRenderTextPosition composition_anchor源码TacoRenderTextPosition composition_focus源码
Vector geometry, vector editing overlay, booleans and stroke outlines
Read a path’s vector network in screen space, hit test its parts, preview an edited network over the scene, combine two paths with a Boolean operation, and turn a stroke into the filled shape it paints.
wasm源码TacoRenderStatus taco_render_session_get_vector_geometry( const TacoRenderSession *session, const char *node_id, size_t node_id_size, const TacoRenderVectorQuery *query, TacoRenderVectorVertex *vertices, size_t vertex_capacity, TacoRenderVectorCubicHandle *handles, size_t handle_capacity, TacoRenderVectorSegment *segments, size_t segment_capacity, TacoRenderVectorRegion *regions, size_t region_capacity, char *identifier_bytes, size_t identifier_capacity, TacoRenderVectorBufferResult *result ) noexcept把路径节点的矢量网络读取为顶点、三次贝塞尔控制柄、线段和区域,每项都带有局部坐标和屏幕坐标。屏幕坐标使用 query->
document_to_screen,它必须是有限且可逆的。标识符紧凑排列在identifier_bytes中,每条记录都指向其中的位置。在 OK 和BUFFER_TOO_SMALL时,result 都包含所有计数(可传容量 0 查询)。节点不存在时返回NOT_FOUND,节点不是路径时返回INVALID_ARGUMENT,还可能返回STALE_GENERATION,超过TACO_RENDER_VECTOR_QUERY_MAX_RECORDS时返回LIMIT_EXCEEDED。适用于所有构建。由 TS 调用:
InteractiveRetainedBackend.getVectorGeometry,RenderCoreSession.getVectorGeometry实现者:
RetainedSession.state,RetainedSession.findNode,RetainedSession.geometrySnapshot,queryVectorGeometry
源码struct TacoRenderVectorQuery矢量几何在 CSS 屏幕空间中计算,使用调用方提供的这个文档到屏幕的仿射变换。该仿射变换必须是有限且非奇异的。
TypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t struct_size源码uint32_t reserved源码uint64_t expected_generation源码double[6] document_to_screen源码
源码struct TacoRenderVectorBufferResult在 OK 和
BUFFER_TOO_SMALL时,此结果会被写入,其中包含精确的所需大小。记录缓冲区和标识符缓冲区只在 OK 时、且所有缓冲区都容纳得下之后才会写入。其他失败不会改动任何输出。TypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t struct_size源码uint32_t vertex_count源码uint32_t handle_count源码uint32_t segment_count源码uint32_t region_count源码uint32_t identifier_byte_count源码uint32_t[2] reserved源码uint64_t generation源码
wasm源码TacoRenderStatus taco_render_session_hit_test_vector( const TacoRenderSession *session, const char *node_id, size_t node_id_size, const TacoRenderVectorHitQuery *query, TacoRenderVectorHit *hits, size_t hit_capacity, char *identifier_bytes, size_t identifier_capacity, TacoRenderVectorHitBufferResult *result ) noexcept查找路径节点上靠近某屏幕点、距离在
tolerance_css_px个 CSS 像素以内的矢量组成部分(顶点、控制柄、线段、区域)。状态码与大小规则同taco_render_session_get_vector_geometry。由 TS 调用:
InteractiveRetainedBackend.hitTestVector,RenderCoreSession.hitTestVector实现者:
RetainedSession.state,RetainedSession.findNode,RetainedSession.geometrySnapshot,hitTestVectorComponents
wasm源码TacoRenderStatus taco_render_session_set_vector_editing_overlay( TacoRenderSession *session, const char *node_id, size_t node_id_size, const TacoRenderVectorEditingOverlay *overlay, const uint8_t *network_bytes, size_t network_byte_count, const TacoRenderVectorEditingComponent *components, size_t component_count, const char *identifier_bytes, size_t identifier_byte_count ) noexcept译文已过期
Installs a transient, generation-stamped full-network preview. The accepted overlay is independent of canonical retained state and replaces prior vector-overlay state only after every byte, component, and owner check succeeds. Portable/no-Skia builds return
CAPABILITY_UNAVAILABLE.node_idnames the path node being edited.network_bytesis the edited network; components lists the selected parts, whose identifiers are packed intoidentifier_bytes.component_countandidentifier_byte_countmust equal the overlay’s fields.overlay_versionis read first, from the 8 bytes every version of the record starts with: a different version returnsUNSUPPORTED_VERSIONwhatever the record’s size, so a 104-byte version-1 record does. Astruct_sizeunder those 8 bytes, or under sizeof(TacoRenderVectorEditingOverlay) in a record of the current version, returnsINVALID_ARGUMENT. A differentnetwork_wire_versionreturnsUNSUPPORTED_VERSIONonce the rest of the record is valid; an oldexpected_generationreturnsSTALE_GENERATION. The overlay is never exported and is cleared by the next apply that changes the generation.由 TS 调用:
InteractiveRetainedBackend.setOverlays,RenderCoreSession.setVectorEditingOverlay由 TS 调用,经由
InteractiveRetainedBackend.setOverlays:InteractiveRenderSession.setOverlays,InteractiveRenderSessionCoordinator.setOverlays实现者:
RetainedSession.state,SessionCache.setVectorEditingOverlay
源码struct TacoRenderVectorEditingOverlay矢量网络字节载荷使用
TACO_RENDER_VECTOR_NETWORK_WIRE_VERSION,大小上限为TACO_RENDER_VECTOR_EDITING_OVERLAY_MAX_NETWORK_BYTES。CSS 视口值描述调用方所安装的确切视口;原生代码从保留场景推导出所属节点的局部到文档变换,并将其与此仿射变换组合,用于所有预览几何、选区强调显示、编辑用的控制框与控制柄,以及相关祖先节点的裁剪。每个仿射系数的绝对值最多为 16,777,216。CSS 尺寸和像素密度必须在闭区间 [1e-28, 16,777,216] 内。TypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t struct_size源码uint32_t overlay_version源码uint64_t expected_generation源码double[6] document_to_screen源码double screen_width_css_px源码double screen_height_css_px源码double screen_pixel_density源码uint32_t network_wire_version源码uint32_t component_count源码uint32_t identifier_byte_count源码uint32_t pending_handle_flags源码TacoRenderVectorEditingPendingHandleFlags; zero when no handle is pending.
uint32_t pending_handle_vertex_index源码Position of the handle’s vertex in the preview network’s vertex table.
uint32_t reserved源码double pending_handle_dx源码The handle’s offset from its vertex, in the owner’s local units.
double pending_handle_dy源码
wasm源码TacoRenderStatus taco_render_session_clear_vector_editing_overlay( TacoRenderSession *session, const TacoRenderVectorEditingOverlayQuery *query ) noexcept移除矢量编辑叠加层。query->
expected_generation不是当前代次时返回STALE_GENERATION,在 portable/无 Skia 构建中返回CAPABILITY_UNAVAILABLE。由 TS 调用:
InteractiveRetainedBackend.setOverlays,RenderCoreSession.clearVectorEditingOverlay由 TS 调用,经由
InteractiveRetainedBackend.setOverlays:InteractiveRenderSession.setOverlays,InteractiveRenderSessionCoordinator.setOverlays实现者:
RetainedSession.state,SessionCache.clearVectorEditingOverlay
wasm源码TacoRenderStatus taco_render_session_boolean_vector_paths( const TacoRenderSession *session, const char *primary_node_id, size_t primary_node_id_size, const char *secondary_node_id, size_t secondary_node_id_size, const char *result_id_namespace, size_t result_id_namespace_size, const TacoRenderVectorBooleanQuery *query, uint8_t *network_bytes, size_t network_capacity, TacoRenderVectorBooleanResult *result ) noexcept用一个 TacoRenderVectorBooleanOperation 组合两个不同的路径节点,并把结果以主路径的局部坐标写成一个独立的矢量网络。新组成部分的标识符以 result_id_namespace 开头(1 到 TACO_RENDER_VECTOR_BOOLEAN_MAX_NAMESPACE_BYTES 字节的 UTF-8)。network_capacity 太小时(传 0 可查询),返回 BUFFER_TOO_SMALL,并且只写入 result。节点不存在时返回 NOT_FOUND,任一节点不是路径时返回 INVALID_ARGUMENT,还可能返回 STALE_GENERATION。Portable/无 Skia 构建返回 CAPABILITY_UNAVAILABLE。
由 TS 调用:
InteractiveRetainedBackend.booleanVectorPaths,RenderCoreSession.booleanVectorPaths实现者:
RetainedSession.state,RetainedSession.findNode,RetainedSession.geometry,booleanVectorPaths,encodeVectorNetwork
源码struct TacoRenderVectorBooleanQuery对两条保留路径执行一次以渲染器结果为准的布尔运算。输出使用
TACO_RENDER_VECTOR_NETWORK_WIRE_VERSION,位于主路径的局部坐标空间中。该查询从不修改保留状态。TypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t struct_size源码uint32_t operation源码uint64_t expected_generation源码uint32_t[2] reserved源码
源码struct TacoRenderVectorBooleanResult在 OK 和
BUFFER_TOO_SMALL时,此结果会被写入,其中包含独立矢量网络所需的精确字节数。载荷缓冲区只在 OK 时、且能完整容纳之后才会写入。其他失败不会改动这两个输出。TypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t struct_size源码uint32_t network_byte_count源码uint64_t generation源码
wasm源码TacoRenderStatus taco_render_session_outline_stroke( const TacoRenderSession *session, const char *node_id, size_t node_id_size, const char *result_id_namespace, size_t result_id_namespace_size, const TacoRenderStrokeOutlineQuery *query, uint8_t *network_bytes, size_t network_capacity, TacoRenderStrokeOutlineResult *result ) noexceptWrites one stroke of a path or container node as a standalone vector network of the area the stroke paints, in the node’s local coordinates: closed loops grouped into even-odd regions, a ring being one region with a hole and each dash a region of its own. The geometry comes from the code that paints the stroke, so it follows the stroke’s width, position (inside, center, outside), join, miter limit, dashes and dash ends, per-side weights, rounded and smoothed corners, and a path’s end shapes. Offset curves lie within 1/32 of a local unit of the exact ones, and circle arcs become cubics within 0.01 of a local unit. The regions carry no fills. A stroke that paints nothing (no width, or a path without segments) gives a network without components.
New component identifiers start with result_id_namespace (1 to TACO_RENDER_STROKE_OUTLINE_MAX_NAMESPACE_BYTES of UTF-8). With too small a network_capacity (pass 0 to ask) it returns BUFFER_TOO_SMALL and writes only result. Returns NOT_FOUND for a missing node, INVALID_ARGUMENT for a text or media node or a stroke index past the node’s strokes, INVALID_SCENE when the stroke cannot be prepared or Skia PathOps cannot resolve its outline, LIMIT_EXCEEDED when the outline is too large for a network, and STALE_GENERATION. Portable/no-Skia builds return CAPABILITY_UNAVAILABLE. Since no capability flag announces it, a caller of an older library must check that the symbol exists.
由 TS 调用:
InteractiveRetainedBackend.outlineCompiledStrokes,PortableWasmRenderCoreSession.outlineStroke由 TS 调用,经由
PortableWasmRenderCoreSession.outlineStroke:outlineStrokesInThrowawaySession实现者:
RetainedSession.state,RetainedSession.findNode,outlineNodeStroke,encodeVectorNetwork
源码struct TacoRenderStrokeOutlineQueryAsks for one stroke of a retained path or container as the filled shape it paints.
stroke_indexcounts the node’s strokes in paint order, hidden ones included. The query never mutates retained state.A call whose buffer is too small (the sizing call) keeps the outline it made, and the next call for the same node, stroke, namespace and generation is answered from it, so the path is stroked and resolved once for the two calls. Any other outline query drops what was kept. Ask for the bytes right after sizing: a font or image that arrives between the two calls without a new generation is not seen by the second.
TypeScript:
RenderStrokeOutlineRequestuint32_t struct_size源码uint32_t stroke_index源码uint64_t expected_generation源码uint32_t[2] reserved源码
源码struct TacoRenderStrokeOutlineResultWritten as
TacoRenderVectorBooleanResultis: on OK andBUFFER_TOO_SMALLwith the exact standalone network byte requirement; other failures leave both outputs untouched.TypeScript:
RenderStrokeOutlineSnapshotuint32_t struct_size源码uint32_t network_byte_count源码uint64_t generation源码
选区框、控制柄与画布叠加层
绘制在场景之上但从不属于场景的编辑器图形:选区轮廓和控制柄,以及吸附线、参考线、测量和像素网格。两者都接收一种小型二进制格式,并在绘制时根据节点解析。画布叠加层格式 2 到 4 依次加入画框标题、标尺,以及自动布局间距控制柄的框、控制柄和胶囊标签;它们的文字使用 taco_render_session_set_canvas_overlay_font 设置的字体绘制。
wasm源码TacoRenderStatus taco_render_session_set_selection_chrome( TacoRenderSession *session, const uint8_t *bytes, size_t size ) noexcept译文已过期
Replaces the selection outlines and transform handles painted over the scene; size 0 clears them. They resolve against retained nodes at paint time, so they share a frame with the pixels they describe. Items naming a missing node are skipped, which lets the chrome outlive scene updates.
Little-endian bytes: u32 version (3 since wire version 20), u32 count, f32 device pixel ratio. Then per item: u32 kind (0 outline of a rect, 1 square handle, 2 round handle), u32 flags (1 hover, 2 dashed), u32 stroke RGBA, u32 fill RGBA (handles only), f64 x, y, width, height, f64 scene offset x, y, six f64 of a matrix, f64 angle, u32 node id size, node id bytes. x and y map through the item’s matrix, then (since wire version 21) through the named node’s transform; with an empty node id the matrix is local-to-scene, so identity makes them scene coordinates. A multi-selection box is anchored to a selected node this way, so it moves with the node. An outline is the rect (x, y, width, height) through its node’s transform, so a rotated node gets a rotated outline, and its angle is 0. A handle is finished by the editor, which also hit-tests it: (x, y) is its centre, width and height its size on screen in CSS pixels (width along the turned x direction) and angle its turn in radians, clockwise on screen. The renderer rounds the size to whole device pixels and keeps a handle at a whole number of quarter turns on whole device pixels.
Limits: at most 4096 items, a pixel ratio in (0, 16], handle sides in (0, 64] CSS pixels and node ids of at most 1024 bytes. Bytes that break these rules, are truncated or have bytes left over return
INVALID_ARGUMENTand keep the old chrome. Portable/no-Skia builds returnCAPABILITY_UNAVAILABLE.由 TS 调用:
encodeSelectionChrome,InteractiveRetainedBackend.setOverlays,RenderSelectionChrome,RenderCoreSession.setSelectionChrome由 TS 调用,经由
encodeSelectionChrome:RenderCoreSession.setSelectionChrome由 TS 调用,经由
InteractiveRetainedBackend.setOverlays:InteractiveRenderSession.setOverlays,InteractiveRenderSessionCoordinator.setOverlays
wasm源码TacoRenderStatus taco_render_session_set_canvas_overlay( TacoRenderSession *session, const uint8_t *bytes, size_t size ) noexcept替换编辑器绘制在场景之上的叠加线:吸附线和对齐线及其 x 标记、标尺参考线、option 拖动时的轮廓和测量值,以及像素网格。大小为 0 时清除它们。它们从不属于文档内容,从不导出,也从不改变保留场景,因此更新它们无需对场景重新编码。网格绘制在选区框与控制柄之下,每条线和每个标记都绘制在其之上。
每条直线都是整设备像素的填充,宽度为 max(1, round(dpr)),与选区轮廓一样用 std::round 取整:side 0(之后)覆盖 [round(p), round(p) + w),side 1(之前)覆盖 [round(p) - w, round(p)),side 2(居中)从 round(p - w / 2) 开始。线的两端分别取整为 round(start) 和 round(end)。x 标记以其两条交叉线所覆盖像素的中点为中心,并使用抗锯齿绘制。
小端序字节,版本 1 到 3:u32 version,f32 设备像素比,u32 锚点数量,然后每个锚点依次为 u32 节点 id 大小(1 到 1024)和 id 字节。接着是 u32 grid(0 或 1);有网格时:u32 锚点索引,u32 RGBA,f64 原点 x、y,f64 步长。接着是 u32 线条数量,u32 标记数量。每条线(56 字节):u32 axis(0 垂直,1 水平),u32 side,u32 flags(1 横跨整个目标,2 场景坐标,4 横跨锚点自身的框、从 0 到其宽度或高度,忽略 start 和 end),u32 RGBA,u32 锚点索引,u32 zero,f64 position,f64 start,f64 end,f32 dash 和 f32 gap(单位为 CSS 像素,实线时两者均为 0)。每个标记(40 字节):u32 RGBA,u32 sides(x 方向的 side 在位 0-1,y 方向的 side 在位 2-3),u32 flags(2 场景坐标),u32 锚点索引,f32 半尺寸(单位为 CSS 像素),u32 zero,f64 x,f64 y。
每项的坐标是相对其锚点节点的局部坐标,在绘制时经该节点的世界变换映射,因此在平移、移动或调整大小预览中,这些项与节点的像素在同一帧中跟随节点;画框自身的标尺参考线锚定到该画框并横跨其框。锚点必须是轴对齐的。锚点不在场景中的项会被跳过。
版本 2 追加画框标题:u32 标题数量(最多 4096),然后每个标题依次为 u32 锚点索引,u32 RGBA,u32 flags(0),f32 字号和 f32 间距(单位为 CSS 像素),u32 UTF-8 文本大小(1 到 4096)和文本字节。标题是绘制在顶层画框上方的名称。它位于锚点设备空间包围盒的左上角,其行框(高度等于字号)的底部在该包围盒上方
gap个 CSS 像素处,超出包围盒宽度的部分以省略号截断;连省略号都放不下的标题不绘制。标题使用taco_render_session_set_canvas_overlay_font设置的字体,逐字符回退到文档中已解码的字体,在设置该字体之前不绘制。版本 3 追加标尺:u32 flag(0 或 1);有标尺时:u32 锚点索引,u32 flags(0),f32 粗细(1 到 256)、f32 字号(1 到 256)和 f32 主刻度最小间距(1 到 4096),单位均为 CSS 像素,然后是背景、边框、刻度和数字、选区范围以及选区数值的 u32 RGBA。接着先 x(顶部标尺)后 y(左侧标尺),各为 u32 范围数量(最多 65536),然后每个范围为以锚点单位表示的 f64 起点和终点,已排序且互不相接(长度为零的范围标记单个数值)。接着是 u32 标签数量(最多 16),然后每个标签依次为 u32 axis(0 为 x,1 为 y),u32 背景 RGBA,u32 文字 RGBA,u32 保留(0),以锚点单位表示的 f64 位置:参考线的位置,以圆角标签的形式绘制在其标尺上。标尺在绘制这一帧时根据锚点的世界变换布置(主刻度步长按 1-2-5 选取,间距不小于最小间距,每个步长五个次刻度),因此它们在同一帧中随页面移动。它们绘制在其他所有内容之上,数字使用
taco_render_session_set_canvas_overlay_font设置的字体(设置之前不绘制数字)。锚点缺失或旋转时标尺留空。版本 4 追加框、控制柄和胶囊标签,用于自动布局的间距控制柄。它们的坐标是相对其锚点的局部坐标,经锚点完整的世界变换映射,因此与线条不同,它们也会跟随旋转的锚点。u32 框数量(最多 4096),然后每个框(56 字节)依次为 u32 锚点索引,u32 flags(1 填充,2 斜线填充,4 轮廓),u32 填充 RGBA,u32 斜线 RGBA,u32 轮廓 RGBA,u32 保留(0),f64 x、y、宽度和高度(尺寸为零或更大)。斜线填充是每隔 4 个 CSS 像素一条、宽一个 CSS 像素的对角条纹,裁剪到框内;轮廓位于框内一个 CSS 像素处。接着是 u32 控制柄数量(最多 4096),然后每个控制柄(40 字节)依次为 u32 锚点索引,u32 axis(0 沿锚点局部 x 轴,1 沿其局部 y 轴),u32 RGBA,u32 边框 RGBA,以 CSS 像素为单位的 f32 长度 (0 到 64] 和 f32 粗细 (0 到 16],其中心的 f64 x 和 y:一条两端为圆头、带一个 CSS 像素边框的刻度线。接着是 u32 胶囊标签数量(最多 16),然后每个标签依次为 u32 锚点索引,u32 背景 RGBA,u32 文字 RGBA,u32 保留(0),f64 x 和 y,以 CSS 像素为单位到标签左上角的 f32 x 和 y 偏移,f32 字号(1 到 64),u32 UTF-8 文本大小(1 到 256)和文本字节:一个使用叠加层字体、带一行文字的圆角胶囊标签(设置该字体之前不绘制)。框绘制在选区轮廓之上,控制柄在框之上,胶囊标签在控制柄之上,它们都位于画框标题和标尺之下。
不符合此布局的字节返回
INVALID_ARGUMENT,并保留原有叠加层。portable/no-Skia 构建返回CAPABILITY_UNAVAILABLE。由 TS 调用:
encodeCanvasOverlay,InteractiveRetainedBackend.setOverlays,RenderCoreSession.setCanvasOverlay由 TS 调用,经由
encodeCanvasOverlay:RenderCoreSession.setCanvasOverlay由 TS 调用,经由
InteractiveRetainedBackend.setOverlays:InteractiveRenderSession.setOverlays,InteractiveRenderSessionCoordinator.setOverlays
wasm源码TacoRenderStatus taco_render_session_set_canvas_overlay_font( TacoRenderSession *session, const uint8_t *bytes, size_t size ) noexcept设置画布叠加层绘制画框标题所用的字体:一个字体文件(TrueType、OpenType 或 WOFF2)的字节,会被复制。大小为 0 时移除字体,之后不再绘制标题。Skia 无法解码的字节返回
INVALID_ARGUMENT并保留原有字体。portable/no-Skia 构建返回CAPABILITY_UNAVAILABLE。
字体
读取场景中某个字体的特性和轴,或在任何文本使用之前从字体字节中复制出一张表。
wasm源码TacoRenderStatus taco_render_session_get_font_metadata( TacoRenderSession *session, const char *font_resource_id, size_t font_resource_id_size, const TacoRenderFontMetadataQuery *query, TacoRenderFontFeature *features, size_t feature_capacity, TacoRenderFontAxis *axes, size_t axis_capacity, TacoRenderFontMetadataResult *result ) noexcept列出场景中某个字体资源的 OpenType 特性(来自 GSUB 和 GPOS)和可变字体轴。没有该 ID 的字体资源时返回
NOT_FOUND,query->expected_generation不是当前代次时返回STALE_GENERATION。大小协商方式与文本查询相同:在 OK 和BUFFER_TOO_SMALL时,result 都包含两个计数。Portable/无 Skia 构建返回CAPABILITY_UNAVAILABLE。由 TS 调用:
InteractiveRetainedBackend.getFontMetadata,RenderCoreSession.getFontMetadata
源码struct TacoRenderFontMetadataResult在 OK 和
BUFFER_TOO_SMALL时,此结果包含精确的记录数量以及所查询的保留场景代次。特性和轴缓冲区仅在 OK 时、且两者都容纳得下之后才会写入。其他任何失败都不会改动任何输出。TypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t struct_size源码uint32_t feature_count源码uint32_t axis_count源码uint32_t reserved源码uint64_t generation源码
wasm源码TacoRenderStatus taco_render_copy_font_table( const uint8_t *font_bytes, size_t font_byte_count, uint32_t table_tag, uint8_t *table_bytes, size_t table_capacity, size_t *table_size ) noexcept从渲染器可解码的任意格式(TrueType、OpenType/CFF、WOFF 和 WOFF2)的字体字节中复制一张 OpenType 表,例如 ‘cmap’(0x636d6170)。它不需要会话,因此宿主可以在任何文本使用某字体之前读取该字体映射了哪些字符。
*table_size接收该表的字节数;当table_capacity更小时(传 0 可查询所需大小),不会复制任何内容,调用返回BUFFER_TOO_SMALL。字体没有该表时返回NOT_FOUND,字节不是可解码的字体时返回INVALID_SCENE,在 Portable/无 Skia 构建中返回CAPABILITY_UNAVAILABLE。实现者:
copyFontTable
Wasm 桥接
不含 Skia 的可移植 Wasm 构建导出这些函数,而不是 C ABI。它应用批次,并返回场景及其几何信息的 JSON 摘要。WebGPU 构建也会导出这四个版本和能力函数。
wasm源码uint32_t taco_render_wasm_abi_version() noexcept-
由 TS 调用,位于这些条目的辅助函数中:
PortableWasmRenderCoreModule.constructor,createOwnedWasmRenderCoreSession,attachPortableWasmRenderCoreSession
wasm源码uint32_t taco_render_wasm_wire_version() noexcept-
由 TS 调用,位于这些条目的辅助函数中:
PortableWasmRenderCoreModule.constructor,createOwnedWasmRenderCoreSession,attachPortableWasmRenderCoreSession
wasm源码uint32_t taco_render_wasm_vector_network_wire_version() noexcept返回 TACO_RENDER_VECTOR_NETWORK_WIRE_VERSION。
由 TS 调用,位于这些条目的辅助函数中:
PortableWasmRenderCoreModule.constructor,createOwnedWasmRenderCoreSession,attachPortableWasmRenderCoreSession
wasm源码uint32_t taco_render_wasm_portable_capabilities() noexcept返回能力位:保留场景、结构化路径、带样式文本和嵌入资源(位 0 到 3)。此构建从不绘制。
由 TS 调用,位于这些条目的辅助函数中:
PortableWasmRenderCoreModule.constructor,createOwnedWasmRenderCoreSession,attachPortableWasmRenderCoreSession
wasm源码PortableWasmSession *taco_render_wasm_session_create() noexcept创建一个空的 portable 会话;分配失败时返回 null。
wasm源码void taco_render_wasm_session_destroy(PortableWasmSession *session) noexcept释放一个 portable 会话。允许传入 null。
wasm源码uint32_t taco_render_wasm_session_apply( PortableWasmSession *session, const uint8_t *batch, size_t batch_size ) noexcept以全有或全无的方式应用一个批次,并返回
TacoRenderStatus。
wasm源码const char *taco_render_wasm_session_snapshot( PortableWasmSession *session ) noexcept返回场景的 JSON 摘要,包括其几何信息和绘制顺序;失败时返回
null。该字符串在下一次调用 snapshot 或 apply 之前一直有效。
wasm源码const char *taco_render_wasm_session_last_error( const PortableWasmSession *session ) noexcept返回最近一次的错误消息;成功应用后为空。
保留会话
每个会话背后的 C++ 场景。它解码批次,保存节点和资源,并为查询和绘制计算几何信息。
源码class taco::render::RetainedSessionC 会话背后的保留场景,不负责绘制。它解码 wire 批次,保存场景及其派生几何信息,并回答几何查询和命中查询。Skia 构建和可移植的 Wasm 构建都使用它。
RetainedSession()源码ApplyResult apply(std::span<const uint8_t> batch, ApplyTransaction *transaction)源码应用一个完整的批次。要么全部生效,要么全部不生效:失败时场景、几何信息和代次(generation)都保持不变。至少包含一条命令的批次会使代次加一。使用事务时,在事务提交之前该变更都可以撤销。
由 TS 调用:
RenderChangeBatchEncoderC ABI:
taco_render_session_applyconst SceneState &state() const源码C ABI:
taco_render_session_apply,taco_render_session_apply_with_static_image_frames,taco_render_session_apply_with_media_frames,taco_render_session_update_video_frames,taco_render_session_get_scene_info,taco_render_session_get_geometry_snapshot,taco_render_session_hit_test,taco_render_session_map_viewport另有 9 项
taco_render_session_get_text_carets,taco_render_session_get_text_range_rects,taco_render_session_clear_text_editing_overlay,taco_render_session_get_vector_geometry,taco_render_session_hit_test_vector,taco_render_session_set_vector_editing_overlay,taco_render_session_clear_vector_editing_overlay,taco_render_session_boolean_vector_paths,taco_render_session_outline_strokeconst Node *findNode(std::string_view id) const源码具有该 ID 的节点,或
null。C ABI:
taco_render_session_get_node_info,taco_render_session_get_node_geometry,taco_render_session_get_vector_geometry,taco_render_session_hit_test_vector,taco_render_session_boolean_vector_paths,taco_render_session_outline_strokeuint64_t digest() const源码场景内容的哈希值,缓存到下一次应用为止。
size_t retainedPayloadBytes() const源码const SessionApplyStats &applyStats() const源码const ApplyChangeSummary &lastApplyChanges() const源码bool sceneContainsMedia() const源码bool hasUnboundedVisibleText() const源码void resetApplyStats()源码const SceneGeometry &geometry() const源码std::shared_ptr<const SceneGeometry> geometrySnapshot() const源码C ABI:
taco_render_session_get_node_geometry,taco_render_session_get_geometry_snapshot,taco_render_session_get_vector_geometry,taco_render_session_hit_test_vectorconst PaintedStrokeCache &paintedStrokes() const源码What hit tests have kept for path strokes, for tests and measurements.
void setMaximumPaintedStrokeBytes(size_t maximum_bytes)源码Replaces the limit on what hit tests keep (
kMaximumPaintedStrokeBytes). Tests use a small one.std::vector<HitRecord> hitTest( double world_x, double world_y, double world_tolerance ) const源码位于场景中某点下方的可见节点,最上层的在前(参见
pointHitsNode)。C ABI:
taco_render_session_hit_testconst DirtyBounds &lastDirtyBounds() const源码最近一次成功应用所改变的区域。
源码class taco::render::ApplyTransaction让一次批量应用保持未决,使调用方可以在保留它之前再检查更多状态。
SessionCache.applyWithMediaFrames用它把帧和场景一起安装,要么都装上,要么都不装。ApplyTransaction()ApplyTransaction(const ApplyTransaction &) = delete源码ApplyTransaction(ApplyTransaction &&) noexcept~ApplyTransaction()源码void commit() noexcept源码保留已应用的会话状态。仍处于活动状态的事务在离开作用域时会自动回滚。
void rollback() noexcept源码
源码struct taco::render::ApplyResultRetainedSession.apply的结果:失败时为状态码加错误信息,成功时为命令数和脏区域边界。TacoRenderStatus status源码uint32_t commands_applied源码std::string error源码DirtyBounds dirty_bounds源码
源码struct taco::render::SceneState保留场景本身:尺寸、代次,以及按 ID 索引的节点和资源。
double width源码double height源码uint64_t generation源码std::map<std::string_view, std::shared_ptr<const Node>, std::less<>> nodes源码键是指向各个不可变值所拥有的 ID 的视图。为事务复制这些映射时,只复制树节点、字符串视图和共享指针;永远不会复制保留的标识符、矢量拓扑、文本或资源数据。
std::map<std::string_view, std::shared_ptr<const Resource>, std::less<>> resources源码
源码struct taco::render::Node一个保留节点:它的标识、父节点、层叠顺序、样式,以及对应其类型(路径、文本、容器或媒体)的载荷。
std::string id源码std::string parent_id源码int32_t z_order源码bool visible源码BlendMode blend_mode源码wire 版本 10 通过一个隔离图层来合成非 normal 的混合模式,并允许一个节点对其后续的兄弟节点施加蒙版,直到父节点结束或另一个蒙版开始新的范围。隐藏的蒙版不遮挡任何内容。
bool mask源码bool vertex_corners源码wire 版本 12 节点标志位 2:路径会追加其顶点圆角表。
bool stroke_caps源码wire 版本 13 节点标志位 4:路径会追加其两个描边端点样式。
Transform transform源码仅含变换的 wire 更新会刻意修改这个字段,而不可变的节点标识和载荷仍与绘制缓存共享。
NodeStyle style源码uint16_t source_wire_version源码std::variant<PathData, TextData, ContainerData, MediaData> data源码void setTransform(const Transform &value) const源码TacoRenderNodeKind kind() const源码
源码struct taco::render::SceneGeometry整个场景在某一代次下的派生几何信息。快照不可变且被共享,因此读取方可以在会话继续推进时保留它。
uint64_t generation源码size_t painter_order_id_bytes源码std::vector<std::shared_ptr<const Node>> retained_nodes源码几何标识符是指向保留节点的视图。所有权保存在这里,因此会话更新之后几何结果依然有效。在此快照构建之后,仅含变换的更新可能会修改保留节点的实时变换;要获取这个几何结果所捕获的变换,请使用
ComputedNodeGeometry::world_transform。std::map<std::string_view, ComputedNodeGeometry, std::less<>> nodes源码std::vector<std::string_view> painter_order源码SceneHitIndex hit_index源码std::map<std::string_view, std::string_view, std::less<>> mask_owners源码从被蒙版的节点 ID 映射到裁剪它的可见兄弟蒙版。它们是指向保留节点的视图,每次构建几何信息时都会完整重新计算。
源码struct taco::render::ComputedNodeGeometry为一个节点推导出的几何信息:局部空间、世界空间和裁剪后可见空间中的边界,世界变换,从后到前的绘制顺序(painter order),以及叠加所有祖先后的不透明度和可见性。
Bounds local_bounds源码Bounds world_bounds源码Bounds visible_world_bounds源码Bounds subtree_visible_bounds源码译文已过期
Everything this node and its descendants paint, after masks and with this node’s layer blur tail around all of it. The renderer uses this box as it is for the node’s compositing layer and for the area a layer blur repaints, so neither adds the tail a second time.
bool subtree_painted源码Whether the renderer paints this node or any of its descendants. A subtree can be painted and still show nothing, when a mask inside it hides all of it, so this is not the same as a valid subtree box.
Transform world_transform源码uint64_t painter_order源码bool effectively_visible源码double effective_opacity源码
源码struct taco::render::DirtyBounds一次更新在场景空间中改变的区域,分为更新前和更新后。C ABI 会把它复制到
TacoRenderDirtyBounds中。Bounds old_bounds源码Bounds new_bounds源码Bounds combined_bounds源码uint64_t generation源码
源码struct taco::render::HitRecordRetainedSession.hitTest命中的一个节点,附带其几何信息。std::shared_ptr<const Node> node源码ComputedNodeGeometry geometry源码
Stroke settings the session reads from the wire: end caps, corner joins and dash ends, in Figma’s terms.
源码enum class taco::render::StrokeCap : uint8_twire 版本 13 的描边端点样式,采用 Figma 的术语。没有显式端点样式的路径在两端都保留以往的圆头端点。
TypeScript:
RetainedStrokeCapkNone = 0源码kRound = 1源码kSquare = 2源码kLineArrow = 3源码kTriangleArrow = 4源码kReversedTriangle = 5源码kCircleArrow = 6源码kDiamondArrow = 7源码
源码enum class taco::render::StrokeJoin : uint8_tWire version 23 stroke joins and dash ends, in Figma’s terms.
TypeScript:
RetainedStrokeJoinkMiter = 0源码kBevel = 1源码kRound = 2源码
源码enum class taco::render::DashCap : uint8_tTypeScript:
RetainedDashCapkNone = 0源码kRound = 1源码kSquare = 2源码
Skia 适配器
SessionCache 保存单个会话的 Skia 状态,其后的函数通过它绘制保留场景。
源码class taco::render::skia_adapter::SessionCache为一个保留渲染器会话持有与后端无关的整形资源。其实现刻意只对 Skia 适配器可见,这样文本查询可以复用屏幕上实际绘制的段落,而不必通过共享的 C ABI 暴露 Skia 类型。
每个 C 会话在其
RetainedSession旁边持有一个该对象。它保存已解码的字体、文本布局和已准备的路径,已安装的图片帧和视频帧,文本和矢量编辑叠加层,选区框与控制柄以及画布叠加层,还有等待下一次增量渲染的脏区域。下面的渲染函数都通过它进行绘制。SessionCache()SessionCache(const SessionCache &) = delete源码SessionCache(SessionCache &&) = delete~SessionCache()源码TacoRenderStatus applyWithStaticImageFrames( RetainedSession *session, std::span<const uint8_t> batch, uint64_t expected_generation, std::span<const StaticImageFrame> frames, ApplyResult *result, std::string *error )源码通过保留会话上的一个事务进行应用,校验并准备完整的图片集合,然后一步提交会话和缓存。被拒绝的帧集合会让会话自动回滚。
TacoRenderStatus applyWithMediaFrames( RetainedSession *session, std::span<const uint8_t> batch, uint64_t expected_generation, std::span<const MediaFrame> frames, ApplyResult *result, std::string *error )源码与
applyWithStaticImageFrames类似,但针对图片帧和视频帧的混合集合,该集合必须与新场景的每个媒体资源一一对应。TacoRenderStatus updateVideoFrames( const RetainedSession &session, uint64_t expected_generation, std::span<const MediaFrame> frames, DirtyBounds *dirty_bounds, std::string *error )源码在不应用批次的情况下替换当前代次的视频帧,并写出像素发生变化的场景区域。需要该代次已通过
applyWithMediaFrames安装了混合集合。uint32_t lastVideoFrameUpdateIndexedAssetCountForTesting() const noexcept源码最近一次成功视频更新(tick)的原生冒烟测试诊断信息。它们只存在于私有的 C++ 适配器接口上,不扩展公共 ABI。
uint32_t lastVideoFrameUpdateSubmittedFrameCountForTesting() const noexcept源码uint32_t lastRgbaRollbackAllocationsForTesting() const noexcept源码TacoRenderStatus getTextCarets( const RetainedSession &session, std::string_view node_id, const TacoRenderTextQuery &query, std::vector<TacoRenderTextCaret> *carets, struct RenderStatistics *statistics, std::string *error )源码taco_render_session_*text* 系列函数背后的文本查询。每个查询都会检查其期望的代次,对节点进行布局(或复用缓存的布局),并以节点局部坐标给出结果。构建一个文本节点的所有光标记录。
TacoRenderStatus getTextCaretCount( const RetainedSession &session, std::string_view node_id, const TacoRenderTextQuery &query, uint32_t *caret_count, struct RenderStatistics *statistics, std::string *error )源码只统计光标数量而不构建它们,这样 C 函数可以先报告
BUFFER_TOO_SMALL。TacoRenderStatus getTextRangeRects( const RetainedSession &session, std::string_view node_id, const TacoRenderTextRangeQuery &query, std::vector<TacoRenderTextRect> *rects, struct RenderStatistics *statistics, std::string *error )源码构建两个文本位置之间的选区矩形。
TacoRenderStatus hitTestText( const RetainedSession &session, std::string_view node_id, const TacoRenderTextHitQuery &query, TacoRenderTextHitResult *result, struct RenderStatistics *statistics, std::string *error )源码查找离某个节点局部坐标点最近的光标位置。
按一次导航操作移动文本位置。
TacoRenderStatus getTextLayoutMetrics( const RetainedSession &session, std::string_view node_id, const TacoRenderTextQuery &query, TacoRenderTextLayoutMetrics *metrics, struct RenderStatistics *statistics, std::string *error )源码报告内容尺寸、建议的画框尺寸和行数。
TacoRenderStatus getFontMetadata( const RetainedSession &session, std::string_view font_resource_id, const TacoRenderFontMetadataQuery &query, std::vector<TacoRenderFontFeature> *features, std::vector<TacoRenderFontAxis> *axes, struct RenderStatistics *statistics, std::string *error )源码TacoRenderStatus setTextEditingOverlay( const RetainedSession &session, std::string_view node_id, const TacoRenderTextEditingOverlay &overlay, struct RenderStatistics *statistics, std::string *error )源码安装绘制在一个文本节点上的选区、输入法组合文本(composition)和光标,替换之前的任何文本叠加层。
void clearTextEditingOverlay(const RetainedSession &session) noexcept源码移除文本编辑叠加层,并把它所在的区域标记为需要重绘。
TacoRenderStatus setVectorEditingOverlay( const RetainedSession &session, std::string_view node_id, const TacoRenderVectorEditingOverlay &overlay, std::span<const uint8_t> network_bytes, std::span<const TacoRenderVectorEditingComponent> components, std::string_view identifier_bytes, struct RenderStatistics *statistics, std::string *error )源码在一个路径节点上安装正在编辑的矢量网络的预览及其选中的组成部分,替换之前的任何矢量叠加层。
void clearVectorEditingOverlay(const RetainedSession &session) noexcept源码移除矢量编辑叠加层,并把它所在的区域标记为需要重绘。
TacoRenderStatus setSelectionChrome( std::span<const uint8_t> bytes, std::string *error )源码替换绘制在场景之上的选区轮廓和控制柄。空字节会清除它们。指向不存在节点的条目会在绘制时跳过,因此选区框与控制柄无需代次检查即可在场景更新后继续保留。
由 TS 调用:
encodeSelectionChrome,RenderSelectionChrome由 TS 调用,经由
encodeSelectionChrome:RenderCoreSession.setSelectionChromeTacoRenderStatus setCanvasOverlay( std::span<const uint8_t> bytes, std::string *error )源码替换绘制在场景之上的编辑器叠加线(吸附线、标尺参考线、按住 Option 拖动时的测量线、像素网格)。空字节会清除它们。
由 TS 调用:
encodeCanvasOverlay由 TS 调用,经由
encodeCanvasOverlay:RenderCoreSession.setCanvasOverlayTacoRenderStatus setCanvasOverlayFont( std::span<const uint8_t> bytes, std::string *error )源码设置画布叠加层中画框标题所用的字体。空字节会移除字体,之后不再绘制标题。
void invalidateStaticImageFrames() noexcept源码与
invalidateMediaFrames相同。void invalidateMediaFrames() noexcept源码丢弃所有已安装的图片帧和视频帧。在普通的批次应用之后调用,因为这种应用不携带任何帧。
C ABI:
taco_render_session_applyvoid recordSuccessfulApply( const RetainedSession &session, const DirtyBounds &dirty_bounds, bool generation_changed ) noexcept源码在一次成功的批次应用之后更新缓存:记录脏区域,丢弃已变化节点的文本布局和路径,在字体资源变化时丢弃字体,并在代次变化时清除两个编辑叠加层。
C ABI:
taco_render_session_applyvoid recordSceneUpdateTime(double scene_update_ms) noexcept源码把应用耗时累加到下一份增量帧报告的
scene_update_ms中。负值或非有限值会被忽略。C ABI:
taco_render_session_apply,taco_render_session_apply_with_static_image_frames,taco_render_session_apply_with_media_frames
源码struct taco::render::skia_adapter::RenderStatisticsuint32_t nodes_considered源码uint32_t nodes_painted源码uint32_t paths_painted源码uint32_t vector_paths_prepared源码uint32_t vector_path_cache_hits源码uint32_t vector_region_tight_bounds_computes源码uint32_t vector_regions_visited源码uint32_t vector_regions_painted源码uint32_t vector_region_fills_painted源码uint32_t inherited_vector_region_fills_painted源码uint32_t explicit_vector_region_fills_painted源码uint32_t vector_region_gradient_fills_painted源码uint32_t vector_network_strokes_painted源码uint32_t vector_segments_stroked源码uint32_t vector_stroke_contours源码其节点已被绘制的作者文本段落数。空的作者段落也计入此处,尽管其私有行框文本不会暴露给查询。
uint32_t paragraphs_painted源码已绘制的整形后 SkParagraph 片段数。列表标记和拆分出的首行缩进会使这个值大于
authored_paragraphs_painted。uint32_t unresolved_glyphs源码uint32_t font_collection_cache_hits源码uint32_t font_collections_built源码uint32_t fonts_decoded源码uint32_t decoded_font_cache_hits源码uint32_t unicode_cache_hits源码uint32_t unicode_services_built源码uint32_t text_layout_cache_hits源码uint32_t text_layout_font_set_rebuilds源码uint32_t rgba_rollback_allocations源码uint32_t opacity_layer_unbounded_saves源码uint32_t ancestor_walk_vector_allocations源码uint32_t text_paragraph_copies源码uint32_t text_mapping_validations源码uint32_t text_layouts_built源码uint32_t text_layout_cache_invalidations源码uint32_t paragraphs_built源码double layout_ms源码double paint_ms源码
源码TacoRenderStatus taco::render::skia_adapter::renderRgba( const RetainedSession &session, SessionCache *cache, const TacoRenderRgbaTarget &target, RenderStatistics *statistics, std::string *error )把保留场景绘制到调用方拥有的预乘 alpha RGBA8888 CPU 缓冲区中。不使用任何平台字体管理器或 GPU 上下文。
源码TacoRenderStatus taco::render::skia_adapter::renderRgbaIncremental( const RetainedSession &session, SessionCache *cache, const TacoRenderRgbaTarget &target, const TacoRenderIncrementalRenderOptions &options, TacoRenderIncrementalFrameReport *report, std::string *error )当目标标识、尺寸、行跨度(stride)和场景映射都未改变时,复用调用方拥有的像素,只重绘累积的场景/叠加层脏区域。成功的调用(包括没有可见脏区域的调用)会确认累积的工作,并写入一份精确的帧报告。
源码TacoRenderStatus taco::render::skia_adapter::renderCanvas( const RetainedSession &session, SessionCache *cache, SkCanvas *canvas, uint32_t width, uint32_t height, RenderStatistics *statistics, std::string *error )把保留场景绘制到一个已有的 Skia 画布(canvas)中。由调用方决定该画布基于 CPU 还是 GPU;场景遍历、路径构建、文本整形、裁剪和绘制语义保持共享。
源码TacoRenderStatus taco::render::skia_adapter::renderCanvasIncremental( const RetainedSession &session, SessionCache *cache, SkCanvas *canvas, uint32_t width, uint32_t height, uintptr_t target_identity, const TacoRenderIncrementalRenderOptions &options, TacoRenderIncrementalFrameReport *report, RenderStatistics *statistics, std::string *error )复用一个由调用方标识的 SkCanvas 目标,只绘制累积的设备脏区域(damage)。在目标像素被保留期间,目标标识必须保持稳定;改变它会强制完整重绘。如果在此调用之后录制的工作无法成功提交,调用方必须使目标失效。成功的绘制只是处于已准备状态;调用方要在后端提交成功之后再确认它,这样待处理的脏区域和诊断信息才不会丢失。
源码void taco::render::skia_adapter::acknowledgeIncrementalRenderTarget( const RetainedSession &session, SessionCache *cache, uintptr_t target_identity, uint32_t width, uint32_t height ) noexcept在后端提交之后,确认一次已准备好的增量画布渲染。
源码void taco::render::skia_adapter::invalidateIncrementalRenderTarget( SessionCache *cache ) noexcept让下一次增量画布渲染重绘整个目标。
源码TacoRenderStatus taco::render::skia_adapter::exportScene( const RetainedSession &session, SessionCache *cache, const TacoRenderExportRequest &request, std::vector<uint8_t> *bytes, TacoRenderExportResult *result, std::string *error )通过共享的绘制器把场景中的一个区域绘制到光栅、SVG 或 PDF 目标中,并返回编码后的字节。编辑用的叠加层永远不会被导出,背景保持透明,非空的根节点只保留该节点的子树。构建版本无法编码的格式返回“能力不可用”(capability-unavailable)。
C ABI:
taco_render_session_export
源码TacoRenderStatus taco::render::skia_adapter::copyFontTable( std::span<const uint8_t> font_bytes, uint32_t table_tag, std::span<uint8_t> out, size_t *table_size )解码字体字节(TrueType、OpenType/CFF、WOFF 或 WOFF2),并把其中一张 OpenType 表复制到
out中。状态码见taco_render_copy_font_table。C ABI:
taco_render_copy_font_table
源码TacoRenderStatus taco::render::skia_adapter::preflightInstalledMediaFrames( const RetainedSession &session, const SessionCache *cache ) noexcept校验精确的保留媒体帧集合,不分配内存、不绘制、不录制 Graphite 命令,也不修改缓存或目标状态。WebGPU 在启用错误作用域或进入录制器清理路径之前调用它。
源码TacoRenderStatus taco::render::skia_adapter::buildVectorRegionPaths( const PathData &network, std::vector<SkPath> *region_paths, std::string *error )为每个规范化的
VectorRegion构建一个 SkPath。区域的绘制属性被忽略,而每个作者绘制的环路都使用与保留场景绘制相同的拓扑转换。不属于任何区域的边刻意不参与。
源码VectorBooleanResult taco::render::skia_path_ops::booleanVectorPaths( const PathData &primary, const Transform &primary_world, const PathData &secondary, const Transform &secondary_world, TacoRenderVectorBooleanOperation operation, std::string_view result_id_namespace )Applies pinned Skia PathOps to canonical VectorRegion geometry. The result is expressed in primary-local coordinates and owns deterministic IDs under result_id_namespace. Region paint and edges outside regions do not contribute.
源码struct taco::render::skia_path_ops::VectorBooleanResultTacoRenderStatus status源码PathData network源码std::string error源码
源码TacoRenderStatus taco::render::skia_adapter::buildNodeStrokeOutline( const Node &node, size_t stroke_index, SkPath *outline, std::string *error )Builds the area one stroke of a path or container covers, in the node’s local coordinates, as the non-overlapping closed contours Skia PathOps returns (even-odd).
stroke_indexcounts the node’s strokes in paint order, hidden ones included. The geometry comes from the code painting uses: the stroke’s width, position, join, miter limit, dashes and dash ends, per-side weights, rounded and smoothed corners, and a path’s end shapes. Offset curves are within 1/32 of a local unit of the exact ones; a stroke painted from a prepared outline (a path with end shapes) returns that outline. A stroke that paints nothing (no width, or no segments) leavesoutlineempty. Returns INVALID_ARGUMENT for a text or media node or an index past the strokes, and INVALID_SCENE when the stroke cannot be prepared or PathOps cannot resolve it.
源码VectorNetworkResult taco::render::skia_path_ops::vectorNetworkFromPath( const SkPath &path, std::string_view id_namespace )Converts a filled Skia path into a vector network: the one conversion from a Skia path to the editable model, for stroke outlines now and for any later command that ends in a PathOps result (flatten, Boolean groups).
pathmust hold the non-overlapping closed contours Skia PathOps (Op,Simplify) returns, filled even-odd; runSimplifyfirst on any other path. Each contour becomes one closed loop of vertices and segments:- lines stay lines and cubics stay cubics;
- a quadratic becomes the cubic that draws the same curve exactly;
- a conic of weight below one (a circle or ellipse arc) becomes the
fewest cubics within 0.01 of a path unit of it (one for a quarter circle of radius up to about 36), and a conic of weight above one becomes thirty-two quadratics.
Loops are grouped into even-odd regions by nesting: a contour inside an even number of others bounds its own region, and one inside an odd number is a hole in the region right around it. A ring is one region with two loops; separate pieces (the dashes of a stroke) are separate regions. Regions carry no fills, so they take the node’s. Identifiers start with
id_namespace(ns:v0,ns:s0,ns:s0:start,ns:r0) and the order of contours is deterministic. An empty path gives an empty network.Grouping compares every contour with every other, so a path of more than
kMaximumOutlineContourscontours is refused with TACO_RENDER_STATUS_LIMIT_EXCEEDED before any comparison, and so is one whose nesting would walk more thankMaximumOutlineContainmentSegmentssegments. A path that would become more segments thanmaximumOutlineNetworkSegmentsallows for the length ofid_namespaceis refused the same way, counted from its verbs before any arc is cut into cubics and before anything of the network is built.
源码VectorNetworkResult taco::render::skia_path_ops::outlineNodeStroke( const Node &node, size_t stroke_index, std::string_view result_id_namespace )One stroke of a retained path or container as a vector network of the area it paints, in the node’s local coordinates:
buildNodeStrokeOutlinefollowed byvectorNetworkFromPath. A stroke that paints nothing gives an empty network.
源码struct taco::render::skia_path_ops::VectorNetworkResultTacoRenderStatus status源码PathData network源码std::string error源码
Wire 读取器与几何辅助函数
有边界检查的 wire 字节读取,以及会话和查询共用的几何函数。
源码class taco::render::WireReader带边界检查地从字节区间(byte span)读取小端序值。读取越过末尾时返回
false,并记录MALFORMED_BATCH及一条消息;status()和error()保留第一次失败。批次解码器和叠加层解析器都使用它。TypeScript:
RenderChangeBatchEncoderWireReader(std::span<const uint8_t> bytes)源码size_t remaining() const源码size_t offset() const源码bool atEnd() const源码TacoRenderStatus status() const源码const std::string &error() const源码bool readU8(uint8_t *value)源码bool readU16(uint16_t *value)源码bool readU32(uint32_t *value)源码bool readI32(int32_t *value)源码bool readU64(uint64_t *value)源码bool readF32(float *value)源码bool readF64(double *value)源码bool readBytes(size_t count, std::span<const uint8_t> *value)源码bool readString(size_t maximum_bytes, bool allow_empty, std::string *value)源码bool readReservedZero(size_t count)源码bool readSubreader(size_t count, WireReader *value)源码bool requireCountFits( uint64_t count, size_t minimum_item_bytes, const char *context )源码bool requireEnd(const char *context)源码bool fail(TacoRenderStatus status, std::string message)源码
源码bool taco::render::isValidUtf8(std::span<const uint8_t> bytes)
源码SceneGeometry taco::render::computeSceneGeometry( const SceneState &state, GeometryBuildStats *stats )SceneGeometry taco::render::computeSceneGeometry( const SceneState &state, const ChildMap &children, GeometryBuildStats *stats )从头计算每个节点的几何信息:世界变换、边界、裁剪、绘制顺序、蒙版和命中索引。
源码SceneGeometry taco::render::computeIncrementalSceneGeometry( const SceneState &state, const SceneGeometry &previous, const std::set<std::string, std::less<>> &changed_ids, const ChildMap &children, GeometryBuildStats *stats, SceneGeometry *reusable_previous )与
computeSceneGeometry类似,但只重新计算发生变化的节点,其余部分复用previous中的结果。
源码bool taco::render::pointHitsNode( const SceneState &state, const SceneGeometry &geometry, std::string_view node_id, double world_x, double world_y, double world_tolerance, HitTestStats *stats, PaintedStrokeCache *painted_strokes )译文已过期
Whether a scene point hits a visible node, after ancestor clips: a path within
world_toleranceof its fill or stroke, the box of a text or media node, or a container that has a fill or stroke.A point outside the node’s visible bounds, which include its stroke, is a miss before anything is built from the path. With
painted_strokes, the rounded path and the stroke contours a path’s miter joins and square ends are read from are kept there and built once for a node; without it they are built for this call alone.
源码TacoRenderStatus taco::render::queryVectorGeometry( const PathData &path, const ComputedNodeGeometry &geometry, const Transform &document_to_screen, VectorGeometryQueryResult *result )
源码TacoRenderStatus taco::render::hitTestVectorComponents( const SceneState &state, const SceneGeometry &geometry, const Node &node, const Transform &document_to_screen, double screen_x, double screen_y, double tolerance_css_px, VectorHitQueryResult *result )
源码EncodeVectorNetworkResult taco::render::encodeVectorNetwork( const PathData &network, size_t maximum_bytes )在给定的上限内编码一个精确的独立 wire-v4
VectorNetwork。由 TS 调用:
decodeVectorNetworkRecord由 TS 调用,经由
decodeVectorNetworkRecord:PortableWasmRenderCoreSession.outlineStroke,RenderCoreSession.booleanVectorPathsC ABI:
taco_render_session_boolean_vector_paths,taco_render_session_outline_stroke
源码DecodeVectorNetworkResult taco::render::decodeVectorNetwork( std::span<const uint8_t> bytes, uint16_t wire_version )解码一个精确的独立 wire-v4
VectorNetwork,不修改任何会话。由 TS 调用:
encodeVectorNetworkRecord由 TS 调用,经由
encodeVectorNetworkRecord:decodeVectorNetworkRecord,RenderCoreSession.setVectorEditingOverlay
其他导出
尚未归入上述章节的条目,按字母顺序排列。
源码bool taco::render::anyRoundedVertex(const PathData &path)Whether any vertex of
pathhas a corner radius.
源码struct taco::render::ApplyChangeSummarybool all_nodes源码bool resources_changed源码std::set<std::string, std::less<>> node_ids源码
源码enum class taco::render::BlendMode : uint8_twire 版本 10 的混合模式,按 CSS mix-blend-mode 的顺序排列。节点从 wire 版本 10 起带有混合模式,paint 从 wire 版本 19 起带有混合模式。
TypeScript:
RetainedBlendModekNormal = 0源码kDarken = 1源码kMultiply = 2源码kColorBurn = 3源码kLighten = 4源码kScreen = 5源码kColorDodge = 6源码kOverlay = 7源码kSoftLight = 8源码kHardLight = 9源码kDifference = 10源码kExclusion = 11源码kHue = 12源码kSaturation = 13源码kColor = 14源码kLuminosity = 15源码
源码struct taco::render::Boundsbool valid源码double min_x源码double min_y源码double max_x源码double max_y源码
源码bool taco::render::branchJoinPair( const std::vector<double> &angles, size_t *first, size_t *second )Which two of the segment ends that meet at a vertex a solid stroke joins when three or more meet there: the two neighbours, going round the vertex, that leave more than half a turn open between them. Every other pair of neighbours overlaps on the inside of its corner, so that open side is the only place a join is missing.
anglesholds the direction each end leaves the vertex in, in radians asstd::atan2gives them;firstandsecondreceive the two ends’ places in it. False when no two ends are joined: fewer than three ends, or no side that open.buildStrokeContoursjoins the two this chooses; the renderer paints those contours and the hit test reads its joins from them. It passes only the ends that have a direction (segmentEndDirection).
源码ChildMap taco::render::buildChildMap( const SceneState &state, bool sort_siblings )
源码bool taco::render::buildStrokeContours( const PathData &path, bool joins_open_runs, StrokeContourOrder order, std::vector<StrokeContour> *contours, std::string *error )Fills
contourswith the contours a stroke ofpathis painted along, in the order the renderer adds them to its path.pathis the path as painted, with its rounded corners worked in (roundPathVertices).Region loops come first, in both orders. A loop none of whose segments an earlier loop used is one contour in loop order, closed unless the loop is stored open. Otherwise each run of its segments that no earlier loop used is a contour. Then come the segments outside every loop, as
ordersays;joins_open_runsisstrokesJoinOpenRunsfor the path’s style.This is the only place that decides which segment ends a stroke joins: the renderer builds its stroke paths from these contours and the hit test reads each join from them, so a join’s miter point is hit exactly where the stroke is painted with a join, and a square end exactly where a contour stops. False, with
errorset, when the path cannot be stroked: a loop that is empty or not connected, a missing segment or vertex, or a segment that would be painted twice or not at all.
源码typedef std::map<std::string_view, std::vector<const Node *>, std::less<>> taco::render::ChildMap
源码struct taco::render::Colorfloat red源码float green源码float blue源码float alpha源码
源码struct taco::render::ContainerDatadouble width源码double height源码bool clip源码std::array<double, 4> corner_radii源码wire 版本 11 标记带圆角的容器,并追加一个圆角半径和 0..1 范围内 Figma 风格的圆角平滑;wire 版本 14 可以改为追加四个半径。半径按左上、右上、右下、左下的顺序排列,使用时各自被限制在较短边的一半以内。半径为零表示直角。
double corner_smoothing源码bool rounded() const源码bool uniformCorners() const源码void setUniformCornerRadius(double radius)源码double effectiveCornerRadius(size_t corner) const源码某个角实际使用的半径:超过较短边一半的半径会被截断。
源码struct taco::render::DecodeVectorNetworkResultTacoRenderStatus status源码PathData network源码std::string error源码
源码struct taco::render::DrawnPointOne point of a path as the renderer draws it.
float x源码float y源码
源码struct taco::render::DrawnSegmentOne segment as the renderer draws it. The renderer builds its path from exactly these points, in this order or backwards when a contour runs through the segment from its end, and the hit test builds a join and a square end at the segment’s ends from the same points: at the end as drawn, along the direction the drawn segment leaves it in. So the two cannot work from different numbers there, and a segment is the same shape whichever way a contour runs through it. The rest of the hit test reads the stored numbers;
prepareDrawnSegmentsays how far apart the two are.Shape shape源码std::array<DrawnPoint, 9> points源码From the segment’s start to its end: a line’s two ends; a cubic’s start, two control points and end; an arc’s start, then a control point and an end for each of its one to four pieces.
size_t point_count源码float arc_piece_weight源码Each piece of an arc is a conic: a curve from one point to the next that bends toward a control point between them, by an amount this weight sets. Unlike a cubic, a conic can follow an ellipse exactly.
源码enum class taco::render::DrawnSegment::Shape : uint8_tkLine源码kCubic源码kArcPieces源码
源码enum class taco::render::DrawnSegmentProblem : uint8_tWhy a segment cannot be drawn.
kNone源码kVertexOutOfRange源码A number is not finite or is too large for single precision:
kControlPointOutOfRange源码A number is not finite or is too large for single precision:
kArcOutOfRange源码A number is not finite or is too large for single precision:
kUnsupportedKind源码A number is not finite or is too large for single precision:
源码struct taco::render::EncodeVectorNetworkResultTacoRenderStatus status源码std::vector<uint8_t> bytes源码std::string error源码
源码struct taco::render::FontVariationstd::array<char, 4> tag源码double value源码
源码void taco::render::forEachImageAssetReference( const Node &node, const std::function<void (std::string_view)> &visit )访问该节点引用的每个图片绘制资源 ID(包括媒体节点);每出现一次引用,
visit就会收到一次对应的 ID。
源码struct taco::render::GeometryBuildStatsuint64_t nodes_computed源码uint64_t path_bounds_index_builds源码std::vector<std::string_view> computed_node_ids源码
源码struct taco::render::GradientStopdouble offset源码Color color源码
源码struct taco::render::HitTestStatsuint64_t path_index_builds源码uint64_t segment_flatten_calls源码uint64_t clip_parent_string_copies源码uint64_t rounded_path_builds源码Calls of
roundPathVerticesand ofbuildStrokeContours.uint64_t stroke_contour_builds源码
源码bool taco::render::isUtf8Boundary(std::string_view text, size_t offset)
源码uint64_t taco::render::maximumOutlineNetworkSegments(size_t namespace_bytes)The most segments a stroke outline’s network may have when its identifiers start with a namespace of
namespace_bytesbytes.
源码double taco::render::maximumTransformScale(const Transform &transform)
源码struct taco::render::MediaCropdouble x源码double y源码double width源码double height源码
源码struct taco::render::MediaDataMediaKind kind源码MediaFit fit源码bool has_crop源码double width源码double height源码std::string asset_id源码MediaCrop crop源码
源码enum class taco::render::MediaFit : uint8_tTypeScript:
RetainedImagePaintFitkContain = 0源码kCover = 1源码kFill = 2源码
源码typedef StaticImageFrame taco::render::skia_adapter::MediaFrame
源码typedef StaticImageFrameDisposition taco::render::skia_adapter::MediaFrameDisposition混合媒体 ABI 刻意保留静态图片的物理记录。
源码enum class taco::render::MediaKind : uint8_tkImage = 1源码kVideo = 2源码
源码bool taco::render::nodeReferencesImageAsset(const Node &node)当节点的任一填充、描边绘制或显式的矢量区域填充是图片绘制时为 true,此时该节点需要一帧已解码的图片。
源码struct taco::render::NodeStyledouble opacity源码bool has_fill源码Color fill源码std::vector<RetainedPaint> fills源码std::vector<RetainedStroke> strokes源码在填充之后绘制的有序描边,第一项位于最底层。第一项使用紧凑的通用节点记录;wire 版本 7 把其余描边追加到外观尾部。
std::vector<RetainedShadow> shadows源码double layer_blur源码wire 版本 9 追加高斯模糊半径:图层模糊作为一个隔离图层作用于该节点及其后代,背景模糊作用于节点形状后方已经绘制的内容。零表示无模糊。
double background_blur源码bool hasStroke() const源码bool hasDropShadow() const源码bool hasInnerShadow() const源码double maximumStrokeWidth() const源码作者设置的最大描边宽度;没有描边时为零。
源码struct taco::render::OpenTypeFeaturestd::array<char, 4> tag源码uint32_t value源码
源码class taco::render::PaintedStrokeCacheWhat hit tests keep for each path node whose stroke has miter joins or square ends: the path as painted, with its rounded corners worked in (
roundPathVertices), and the contours its strokes are painted along (buildStrokeContours). Working these out visits every vertex and segment of the path, so it is done once for a node and not on every pointer move.Both are read from the node’s path and style alone. A retained
Nodenever changes either (an update that changes them puts a newNodein the scene; an update of the transform alone keeps the same one), so what is kept belongs to oneNodeobject and is used only for that object. Each entry holds its node, which keeps the object and the segments its contours point at alive.What is kept has a size limit in bytes. Each entry is measured after the hit test that built it or added to it, by the capacity of what it holds. When the entries together would pass the limit, the ones used longest ago are dropped first. An entry that is larger than the limit on its own is not kept: the hit test that built it uses it once, and the next hit test on that node builds it again.
PaintedStrokeCache(size_t maximum_bytes)源码PaintedStrokeCache(const PaintedStrokeCache &) = delete~PaintedStrokeCache()源码Entry &entryFor(const std::shared_ptr<const Node> &node)源码The entry for
node, empty when nothing is kept for this object yet, and now the most recently used one. An entry kept for another object with the same ID is dropped first. The entry stays in place untilsettleis called for it or for another entry.void settle(Entry *entry)源码Call once a hit test has built something into
entryand no longer reads it. Measures the entry, then drops the entries used longest ago until all of them fit the limit, orentryitself when it alone is larger than the limit.void dropUnless(std::string_view id, const Node *current)源码Drops the entry for the node with this ID unless it was built from
current, the object now in the scene (nullwhen the node is gone).void clear()源码void setMaximumBytes(size_t maximum_bytes)源码Changes the limit and drops the entries used longest ago until the rest fit it.
size_t maximumBytes() const源码size_t size() const源码bool holds(std::string_view id) const源码size_t bytes() const源码The size of all entries, as added up when each was last settled.
size_t measuredBytes() const源码The same size, found by measuring every entry again. Tests compare the two.
源码enum class taco::render::PaintKind : uint8_tTypeScript:
RetainedPaintRecordkSolid = 1源码kLinearGradient = 2源码kRadialGradient = 3源码wire 版本 8 新增下面三种类型。
kAngularGradient = 4源码wire 版本 8 新增下面三种类型。
kImage = 5源码wire 版本 8 新增下面三种类型。
源码struct taco::render::PathDatastd::vector<VectorVertex> vertices源码std::vector<VectorSegment> segments源码std::vector<VectorTangentConstraint> constraints源码std::vector<VectorRegion> regions源码bool explicit_stroke_caps源码wire 版本 13:显式端点样式作用于第一条作者绘制线段的起始顶点和最后一条线段的结束顶点,二者都是开放链的端点。没有显式端点样式时,每个描边端点都是圆头,与之前一致。
StrokeCap start_cap源码StrokeCap end_cap源码std::unique_ptr<std::pmr::monotonic_buffer_resource> identifier_arena源码标识符字节从一个单调增长的内存池(arena)中分配,因此解码路径时不会为每个不同的 wire 标识符各做一次堆分配。该内存池单独持有,因为当
PathData被移动到保留的 Node 中时,string_views必须仍然有效。std::unique_ptr<std::pmr::unsynchronized_pool_resource> identifier_index_pool源码查找索引是解码期间的状态。池分配让它的节点不进入通用堆,结束处理(finalization)时会释放它们。
std::unique_ptr<IdentifierIndex> identifier_index源码uint32_t identifier_reads源码bool identifier_index_finalized源码std::string_view internIdentifier(std::string_view value)源码void finalizeIdentifierInterning()源码PathData()源码
源码DrawnSegmentProblem taco::render::prepareDrawnSegment( const VectorSegment &segment, double start_x, double start_y, double end_x, double end_y, DrawnSegment *drawn )Fills
drawnwithsegmentas the renderer draws it between its own start and end vertices. Everything the renderer changes on the way from the stored numbers to the path happens here:- The two vertices and a cubic’s two control points (each a vertex plus
its handle) are rounded to single precision.
- An arc’s two radii lose their sign and are rounded to single precision,
and its rotation is rounded to single precision as well, in degrees and again in radians. A rotation of millions of degrees ends up at a different angle from the one the stored number means.
- An arc becomes a straight line when a rounded radius is zero, when its
rounded ends are one point, or when it sweeps less than a millionth of half a turn.
- Radii too small to reach from one end to the other are scaled up until
the arc is half an ellipse, and
large_arcandsweepchoose among the four arcs that fit. All of this is worked out in single precision, by the steps Skia’sSkPathBuilder::arcTotakes, so the pieces are the ones that call would make.- When an arc’s pieces are a quarter turn each and its radii and end are
whole numbers, the pieces’ points are rounded to whole numbers too, as Skia does to keep a rounded rectangle’s corners exact.
- Radii so small or so large beside the arc’s length that single precision
cannot work out an angle for it give a straight line. (Skia’s own call would add nothing for these and leave the path a segment short.)
How far the hit test is from this. A join’s miter point and a square end are built from the drawn segment. Everything else in the hit test works from the stored numbers in double precision: the stroke between a segment’s ends, arrow heads, fills, and the bounds, which the editor reads and outside which nothing is hit. Those sit as far from the painted shape as the steps above move it:
- Single precision numbers of size
mare at most m / 2^23 apart, about
m * 1.2e-7. Call that a step. A line’s ends and a cubic’s four points are each drawn within half a step of where they are stored, on each axis.
- An arc is worked out in single precision from start to finish. Its
points are drawn within about two steps of the stored arc, where
mis the larger of its coordinates and its radii.- An arc of nearly half a turn is drawn less exactly, because its centre
comes from the square root of a difference that rounding leaves uncertain. Within 15 degrees of half a turn the two steps no longer hold, and an arc of exactly half a turn, which is what an arc with radii too small becomes, was measured up to a 2000th of its radius from the stored arc.
- The whole-number rounding above moves an arc’s points by up to half a
unit on each axis, whatever the arc’s size, unless the stored arc has them on whole numbers already, as a rounded rectangle’s corner does.
Supported range: the painted stroke and the stroke the hit test covers agree to within 2.5% of the stroke width when, in the path’s own units,
- coordinates and arc radii are at most 50,000 times the stroke width,
- an arc’s rotation is within one turn,
- an arc within 15 degrees of half a turn has radii of at most 25 times
the stroke width, and
- an arc whose points are rounded to whole numbers has them on whole
numbers as stored. That is on top of the 0.05 of a unit, measured on the page, that the hit test allows itself when it splits a curve into straight pieces. The session test checks the range at its edge. Outside it the two drift apart in proportion. From 2^24 (16,777,216) units on, a step is 2 units or more, so a vertex is drawn up to a unit or more from where it is stored, and a stroke thinner than that can be painted wholly outside the place the hit test looks. Skia also works a stroke’s outline out in single precision, in the path’s own units, so by then the painted stroke is not exactly the stroke of the drawn segments either.
docs/render-core/futures.mdsays what closing this would take.
源码void taco::render::skia_path_ops::resetVectorPathOpsStats()
源码struct taco::render::Resourcestd::string id源码ResourceKind kind源码std::vector<uint8_t> bytes源码
源码enum class taco::render::ResourceKind : uint8_tTypeScript:
ResourceKindkFont = 1源码kImage = 2源码kBlob = 3源码
源码struct taco::render::RetainedPaintTypeScript:
RetainedPaintRecordPaintKind kind源码BlendMode blend_mode源码wire 版本 19:kind 之后的字节是该 paint 的混合模式,下一个字节的位 1 隐藏该 paint。隐藏的 paint 在列表中保留其位置但不绘制任何内容;设置了混合模式的 paint 与同一节点上位于其下方的 paint 混合,混合发生在节点自身的 paint 图层内。
double opacity源码Color color源码double angle源码线性渐变只使用
angle。径向渐变和角度渐变以形状边界的比例来确定中心;径向渐变额外以比例表示椭圆半径,角度渐变把angle复用为起始角度。double center_x源码double center_y源码double radius_x源码double radius_y源码std::vector<GradientStop> stops源码std::string asset_id源码图片绘制指定一个通过媒体帧集合附加的逻辑资源。
MediaFit image_fit源码bool isGradient() const源码
源码struct taco::render::RetainedShadow
源码struct taco::render::RetainedStrokeColor color源码double width源码StrokePosition position源码std::vector<double> dash源码bool has_paint源码wire 版本 6 可以携带完整的描边绘制。缺失时,以紧凑的
color为准。第一个之后的每个描边都携带一个。RetainedPaint paint源码bool has_sides源码wire 版本 18 可以为容器的描边按边设置各自的粗细,顺序为上、右、下、左;此时
width保存其中最大的一个。std::array<double, 4> sides源码bool has_style源码Wire version 23 can set the join, the ends of every dash and the miter limit together. Without them a path strokes with round joins and round dash ends and a container with miter joins (limit 4) and flat dash ends.
StrokeJoin join源码DashCap dash_cap源码double miter_limit源码
源码struct taco::render::RichTextRunuint32_t start_byte源码uint32_t end_byte源码uint32_t style_index源码
源码struct taco::render::RichTextStylestd::vector<std::string> font_resource_ids源码std::string language源码double font_size源码double line_height源码double letter_spacing源码uint16_t weight源码bool italic源码bool underline源码bool strikethrough源码Color color源码std::vector<OpenTypeFeature> open_type_features源码std::vector<FontVariation> font_variations源码
源码struct taco::render::RoundedPathDataA path with its rounded corners worked into its segments (
roundPathVertices).idsowns the identifiers of the vertices and segments a rounded corner adds.std::deque<std::string> ids源码PathData data源码
源码bool taco::render::roundPathVertices( const PathData &authored, RoundedPathData *out, std::string *error )Fills
outwithauthoredas the renderer paints it. A vertex with a corner radius is rounded when exactly two segment ends meet there, they belong to two different segments, both are lines or cubics with a direction at the vertex, and they are neither in one straight line nor folded back on each other. Each of the two segments is cut short and a corner segment joins the cuts. Every other vertex is left as stored, whatever its radius: the end of a path, a vertex three or more segment ends meet at, a vertex an arc meets, and a vertex whose two ends are one closed curve’s. No vertex ofouthas a corner radius. This is the only place that decides whether a corner is rounded: the renderer paintsoutand the hit test reads the stroke’s joins from it (buildStrokeContours), so a join is hit at exactly the vertices that are painted with one. False, witherrorset, when a segment or region names a missing vertex or segment.
源码struct taco::render::SceneHitIndexbool valid源码Bounds bounds源码std::array<std::vector<uint32_t>, kCellCount> cells源码std::vector<uint32_t> unbounded源码
源码enum class taco::render::SegmentDirection : uint8_tkForward = 0源码kReverse = 1源码
源码bool taco::render::segmentEndDirection( const VectorSegment &segment, double start_x, double start_y, double end_x, double end_y, bool at_start, double *away_x, double *away_y )The unit direction a segment leaves one of its ends in, pointing from that end into the segment: the direction the stroke has there, which its joins and square ends are built along.
startandendare the segment’s own start and end vertices;at_startpicks the end. The direction is read from the segment as drawn (prepareDrawnSegment): it points from the end toward the nearest drawn point that is not at the end itself. So a line leaves along itself; a cubic along its handle, however short, or toward its next control point when the handle is too short to move its control point off the vertex in single precision, or along its chord when that is too; and an arc toward the control point of its first or last piece, which lies on the ellipse’s tangent. False when there is no direction to take: when every drawn point is the same, when a line’s two drawn ends are withinkDrawnPointToleranceof each other, when the same holds for a cubic that has no bend to draw (at least two of its three steps from one point to the next have no length), and when the segment cannot be drawn at all. The renderer chooses which ends to join from this and the hit test builds the join from it, at the end as drawn, so both call this instead of measuring the curve in their own ways. This only reads the drawn points; what is painted is the drawn segment unchanged.Skia’s two stroke painters agree with this for a curve that bends. They differ from each other for a cubic whose control points all lie within about 0.3% of its length of one straight line, and for an arc that sweeps less than about half a degree: the one that runs on the processor paints either as straight lines, so a turn that small at an end does not move its join, while the one that runs on the graphics card follows the curve as this does (see
docs/render-core/futures.md).
源码enum class taco::render::SegmentKind : uint8_tkLine = 1源码kCubic = 2源码kEllipticalArc = 3源码
源码struct taco::render::SessionApplyStats应用/摘要开销的计数器。测试会断言复杂度上限;生产环境的调用方可以忽略它们。只有当
digest()真正遍历保留场景时,digest_walks才会递增。uint64_t digest_walks源码uint64_t payload_walks源码uint64_t geometry_nodes_computed源码uint64_t path_bounds_index_builds源码uint64_t dirty_nodes_visited源码uint64_t scene_nodes_validated源码uint64_t geometry_nodes_validated源码uint64_t hit_path_index_builds源码uint64_t hit_segment_flatten_calls源码uint64_t hit_clip_parent_string_copies源码uint64_t hit_rounded_path_builds源码How often a hit test worked out a path with its rounded corners (
roundPathVertices) and a path’s stroke contours (buildStrokeContours). Both are kept per node (PaintedStrokeCache), so hit tests on a node that has not changed add to these once, for as long as what is kept for the node fits that cache’s size limit.uint64_t hit_stroke_contour_builds源码uint64_t hit_test_traversals源码uint64_t hit_nodes_tested源码uint64_t scene_state_node_entries_copied源码
源码bool taco::render::singlePrecision(double value, float *rounded)Rounds
valueto single precision, the precision the renderer builds every path in. False whenvalueis not finite or is too large for single precision to hold. Every number that reaches a drawn path is rounded here and nowhere else.
源码struct taco::render::skia_adapter::StaticImageFrame内部调用方(包括 GPU 桥接层)可以提供已经创建好的 SkImage。替换用的图片可以基于光栅,也可以基于纹理;公共 C 边界在进入这条路径之前会构造自有的光栅图片。
std::string_view asset_id源码uint64_t content_revision源码uint32_t kind源码StaticImageFrameDisposition disposition源码sk_sp<SkImage> image源码
源码enum class taco::render::skia_adapter::StaticImageFrameDisposition : uint8_tkReuseActive源码kReplace源码
源码double taco::render::strokeCapReach(StrokeCap cap, double width)描边宽度为
width的端点样式绘制到的离端点最远的距离,包括描边自身在箭头两翼周围的半宽。
源码struct taco::render::StrokeContourOne run of segments a stroke is painted along without a break. The stroke has a join between each step and the next, and between the last and the first when
closed; the two ends of a contour that is not closed get the stroke’s ends instead. The renderer paints every step. Where a step is too short to have a direction (segmentEndDirection), the hit test reads the join from the steps on either side of it and a stroke’s end from the first or last step that has one.std::vector<StrokeContourStep> steps源码bool closed源码
源码StrokeContourOrder taco::render::strokeContourOrder( const NodeStyle &style, const PathData &path, const RetainedStroke &stroke )Which contours of a path the renderer paints
strokealong.pathis the path as stored, which says whether it has stroke caps.
源码enum class taco::render::StrokeContourOrder : uint8_tkStored源码Segments outside every region loop keep the order and direction they are stored in: a segment continues the contour of the one stored before it only when it starts where that one ends, at a vertex no other segment touches. A dashed stroke and a path with stroke caps are painted along these, because a dash pattern and a cap follow the stored order.
kJoined源码Segments outside every region loop are followed through every vertex where the stroke should join, whatever order and direction they are stored in: a vertex two segment ends touch joins those two, and a vertex three or more touch joins the two
branchJoinPairchooses among the ends that have a direction, or the only two that have one. A solid stroke that names its join is painted along these.
源码struct taco::render::StrokeContourStepOne segment of a stroke contour:
forwardwhen the contour runs through it from its start vertex to its end vertex.const VectorSegment *segment源码bool forward源码
源码StrokeOutlineStats &taco::render::skia_adapter::strokeOutlineStats()
源码struct taco::render::skia_adapter::StrokeOutlineStatsCounts for tests of
buildNodeStrokeOutline: how many strokes were turned into the area they cover (Skia made their dashes and stroked them), and how many of those went on to Skia PathOps (one refused for too many contours or too much work does not).capped_stroke_bodiescounts the lines of strokes with end shapes that were dashed and stroked, for painting and for outlines alike.dash_estimateis the last count of dashes made before dashing;path_ops_segmentsandpath_ops_workare the segments and the estimate of work last checked before PathOps (the work of a refused stroke is only counted until it passes the limit).uint64_t stroked_paths源码uint64_t path_ops_runs源码uint64_t capped_stroke_bodies源码double dash_estimate源码uint64_t path_ops_segments源码uint64_t path_ops_work源码
源码enum class taco::render::StrokePosition : uint8_tTypeScript:
RetainedStrokePositionkCenter = 0源码kInside = 1源码kOutside = 2源码
源码bool taco::render::strokesJoinOpenRuns(const NodeStyle &style)Whether any stroke of
stylenames its join (wire version 23). Only then do segments outside the region loops run on into each other; otherwise each is a contour of its own.
源码#define TACO_RENDER_EXTENDED_CAPABILITIES_VERSION_1 1u
源码#define TACO_RENDER_EXTENDED_CAPABILITIES_VERSION_1_SIZE 32u
源码#define TACO_RENDER_EXTENDED_CAPABILITIES_VERSION_2 2u
源码#define TACO_RENDER_EXTENDED_CAPABILITIES_VERSION_2_SIZE 40u
源码#define TACO_RENDER_EXTENDED_CAPABILITIES_VERSION_3 3u
源码#define TACO_RENDER_EXTENDED_CAPABILITIES_VERSION_3_SIZE 48u
源码#define TACO_RENDER_EXTENDED_CAPABILITIES_VERSION_4 4u
源码#define TACO_RENDER_EXTENDED_CAPABILITIES_VERSION_4_SIZE 56u
源码#define TACO_RENDER_EXTENDED_CAPABILITIES_VERSION_5 5u
源码#define TACO_RENDER_EXTENDED_CAPABILITIES_VERSION_5_SIZE 64u
源码#define TACO_RENDER_EXTENDED_CAPABILITIES_VERSION_6 6u
源码#define TACO_RENDER_EXTENDED_CAPABILITIES_VERSION_6_SIZE 72u
源码#define TACO_RENDER_EXTENDED_CAPABILITIES_VERSION_7 7u
源码#define TACO_RENDER_EXTENDED_CAPABILITIES_VERSION_7_SIZE 80u
源码#define TACO_RENDER_EXTENDED_CAPABILITIES_VERSION_8 8u
源码#define TACO_RENDER_EXTENDED_CAPABILITIES_VERSION_8_SIZE 88u
源码#define TACO_RENDER_FONT_METADATA_MAX_AXES 65535uTypeScript:
RENDER_FONT_METADATA_MAX_AXES
源码#define TACO_RENDER_FONT_METADATA_MAX_FEATURES 131070uTypeScript:
RENDER_FONT_METADATA_MAX_FEATURES
源码#define TACO_RENDER_FONT_METADATA_VERSION 1u
源码#define TACO_RENDER_INCREMENTAL_RENDER_VERSION 1u
源码#define TACO_RENDER_MEDIA_FRAME_MAX_BYTES TACO_RENDER_STATIC_IMAGE_FRAME_MAX_BYTES
源码#define TACO_RENDER_MEDIA_FRAME_MAX_COUNT TACO_RENDER_STATIC_IMAGE_FRAME_MAX_COUNT图片帧和视频帧共享同一个有上限的媒体预算,按解码后的等效大小计算。
源码#define TACO_RENDER_MEDIA_FRAME_MAX_DIMENSION TACO_RENDER_STATIC_IMAGE_FRAME_MAX_DIMENSION
源码#define TACO_RENDER_MEDIA_FRAME_REUSE_ACTIVE TACO_RENDER_STATIC_IMAGE_FRAME_REUSE_ACTIVE
源码#define TACO_RENDER_MEDIA_FRAME_RGBA8888 TACO_RENDER_STATIC_IMAGE_FRAME_RGBA8888
源码#define TACO_RENDER_STATIC_IMAGE_FRAME_MAX_BYTES (64u * 1024u * 1024u)
源码#define TACO_RENDER_STATIC_IMAGE_FRAME_MAX_COUNT 16u
源码#define TACO_RENDER_STATIC_IMAGE_FRAME_MAX_DIMENSION 32768u
源码#define TACO_RENDER_STATIC_IMAGE_FRAME_VERSION 1u
源码#define TACO_RENDER_STROKE_OUTLINE_MAX_NAMESPACE_BYTES TACO_RENDER_VECTOR_BOOLEAN_MAX_NAMESPACE_BYTES
源码#define TACO_RENDER_STROKE_OUTLINE_MAX_NETWORK_BYTES TACO_RENDER_VECTOR_BOOLEAN_MAX_NETWORK_BYTES
源码#define TACO_RENDER_TEXT_QUERY_MAX_RECORDS 65536u文本几何计算在这个固定上限以内是精确的。更大的光标集合,或者跨越的已选 UTF-8 字节数加段落分隔符数超过该上限的范围或叠加层,返回
LIMIT_EXCEEDED,且不写入任何内容。这使原生会话和 512 MiB 的 Wasm 会话的资源占用有可预期的上界。
源码#define TACO_RENDER_TEXT_QUERY_VERSION 1u
源码#define TACO_RENDER_VECTOR_BOOLEAN_MAX_NAMESPACE_BYTES 1008u
源码#define TACO_RENDER_VECTOR_BOOLEAN_MAX_NETWORK_BYTES (64u * 1024u * 1024u)
源码#define TACO_RENDER_VECTOR_BOOLEAN_VERSION 1u
源码#define TACO_RENDER_VECTOR_EDITING_OVERLAY_MAX_COMPONENTS 65536u
源码#define TACO_RENDER_VECTOR_EDITING_OVERLAY_MAX_NETWORK_BYTES (64u * 1024u * 1024u)
源码#define TACO_RENDER_VECTOR_EDITING_OVERLAY_VERSION 2u
源码#define TACO_RENDER_VECTOR_QUERY_MAX_IDENTIFIER_BYTES (16u * 1024u * 1024u)
源码#define TACO_RENDER_VECTOR_QUERY_MAX_RECORDS 65536u几何查询对每个记录数组分别应用此上限;命中结果只应用一次。
源码#define TACO_RENDER_VECTOR_QUERY_VERSION 1u
源码#define TACO_RENDER_VIDEO_FRAME_MAX_BYTES TACO_RENDER_MEDIA_FRAME_MAX_BYTES
源码#define TACO_RENDER_VIDEO_FRAME_MAX_COUNT TACO_RENDER_MEDIA_FRAME_MAX_COUNT
源码#define TACO_RENDER_VIDEO_FRAME_MAX_DIMENSION TACO_RENDER_MEDIA_FRAME_MAX_DIMENSION
源码#define TACO_RENDER_VIDEO_FRAME_VERSION 1u
源码struct TacoRenderDeviceRectuint32_t x源码uint32_t y源码uint32_t width源码uint32_t height源码
源码enum TacoRenderExportFlags
源码enum TacoRenderExportImageSamplingTypeScript:
RenderExportImageSampling
源码struct TacoRenderFontAxis来自所保留的那个 SkTypeface 的一个可变字体轴,已排序。
TypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t struct_size源码char[4] tag源码uint8_t[7] reserved源码double minimum源码double default_value源码double maximum源码
源码struct TacoRenderFontFeature来自 GSUB 或 GPOS 的一个 OpenType 特性标签:四字节、可打印、已排序且唯一。
TypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t struct_size源码char[4] tag源码
源码struct TacoRenderFontMetadataQueryTypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t struct_size源码uint32_t reserved源码uint64_t expected_generation源码
源码enum TacoRenderGeometryFlagsTACO_RENDER_GEOMETRY_FLAG_HAS_LOCAL_BOUNDS = 1源码TACO_RENDER_GEOMETRY_FLAG_HAS_WORLD_BOUNDS = 2源码TACO_RENDER_GEOMETRY_FLAG_HAS_VISIBLE_WORLD_BOUNDS = 4源码TACO_RENDER_GEOMETRY_FLAG_EFFECTIVELY_VISIBLE = 8源码
源码enum TacoRenderIncrementalFrameFlagsTACO_RENDER_INCREMENTAL_FRAME_HAS_DAMAGE = 1源码TACO_RENDER_INCREMENTAL_FRAME_FULL_PAINT = 2源码TACO_RENDER_INCREMENTAL_FRAME_REUSED_TARGET = 4源码
源码enum TacoRenderIncrementalRenderFlagsTACO_RENDER_INCREMENTAL_RENDER_FORCE_FULL = 1源码
源码typedef TacoRenderStaticImageFrame TacoRenderMediaFrame视频帧版本 1 有意复用已验证可靠的静态图片物理记录布局。kind 字段区分图片和视频的归属。混合集合按逻辑资源 ID 全局排序;视频更新集合只包含场景中确切的、去重后的视频资源集合。
源码typedef TacoRenderStaticImageFrameDisposition TacoRenderMediaFrameDisposition
源码enum TacoRenderMediaFrameKindTACO_RENDER_MEDIA_FRAME_STATIC_IMAGE = 1源码TACO_RENDER_MEDIA_FRAME_VIDEO = 2源码
源码typedef TacoRenderStaticImageFrameSet TacoRenderMediaFrameSet
源码enum TacoRenderNodeKind保留节点的类型,由节点查询和几何查询报告。
TACO_RENDER_NODE_PATH = 1源码TACO_RENDER_NODE_TEXT = 2源码TACO_RENDER_NODE_CONTAINER = 3源码TACO_RENDER_NODE_MEDIA = 4源码
源码struct TacoRenderRect轴对齐矩形:左上角加尺寸。
double x源码double y源码double width源码double height源码
源码enum TacoRenderStaticImageFrameDispositionTACO_RENDER_STATIC_IMAGE_FRAME_REUSE_ACTIVE = 1源码TACO_RENDER_STATIC_IMAGE_FRAME_RGBA8888 = 2源码
源码enum TacoRenderTextAffinityTypeScript:
RenderTextAffinityTACO_RENDER_TEXT_AFFINITY_UPSTREAM = 0源码TACO_RENDER_TEXT_AFFINITY_DOWNSTREAM = 1源码
源码enum TacoRenderTextAutoResizeTACO_RENDER_TEXT_AUTO_RESIZE_NONE = 0源码TACO_RENDER_TEXT_AUTO_RESIZE_HEIGHT = 1源码TACO_RENDER_TEXT_AUTO_RESIZE_WIDTH_AND_HEIGHT = 2源码
源码struct TacoRenderTextCaretTypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t struct_size源码uint32_t reserved源码TacoRenderTextPosition position源码TacoRenderRect local_bounds源码
源码enum TacoRenderTextEditingOverlayFlagsTACO_RENDER_TEXT_EDITING_OVERLAY_HAS_COMPOSITION = 1源码TACO_RENDER_TEXT_EDITING_OVERLAY_CARET_VISIBLE = 2源码
源码struct TacoRenderTextHitQueryTypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t struct_size源码uint32_t reserved源码uint64_t expected_generation源码double local_x源码double local_y源码
源码struct TacoRenderTextHitResultTypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t struct_size源码uint32_t inside源码uint64_t generation源码TacoRenderTextPosition position源码
源码struct TacoRenderTextLayoutMetricsTypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t struct_size源码uint32_t auto_resize源码uint64_t generation源码double frame_width源码double frame_height源码double content_width源码double content_height源码double suggested_width源码double suggested_height源码uint32_t paragraph_count源码uint32_t line_count源码uint32_t caret_count源码uint32_t reserved源码
TypeScript:
RenderTextNavigationOperationTypeScript:
PORTABLE_WASM_ABI_LAYOUTTypeScript:
PORTABLE_WASM_ABI_LAYOUT
源码struct TacoRenderTextQuery通用的文本查询输入:调用方预期的场景代次。reserved 必须为 0。
TypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t struct_size源码uint32_t reserved源码uint64_t expected_generation源码
源码struct TacoRenderTextRangeQueryTypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t struct_size源码uint32_t reserved源码uint64_t expected_generation源码TacoRenderTextPosition anchor源码TacoRenderTextPosition focus源码
源码struct TacoRenderTextRectTypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t struct_size源码uint32_t reserved源码TacoRenderRect local_bounds源码
源码enum TacoRenderVectorBooleanOperationTypeScript:
RenderVectorBooleanOperationTACO_RENDER_VECTOR_BOOLEAN_UNION = 1源码TACO_RENDER_VECTOR_BOOLEAN_INTERSECTION = 2源码TACO_RENDER_VECTOR_BOOLEAN_DIFFERENCE = 3源码TACO_RENDER_VECTOR_BOOLEAN_EXCLUSION = 4源码
源码enum TacoRenderVectorComponentKindTACO_RENDER_VECTOR_COMPONENT_VERTEX = 1源码TACO_RENDER_VECTOR_COMPONENT_CUBIC_HANDLE = 2源码TACO_RENDER_VECTOR_COMPONENT_SEGMENT = 3源码TACO_RENDER_VECTOR_COMPONENT_REGION = 4源码
源码struct TacoRenderVectorCubicHandleTypeScript:
decodeWasmVectorGeometry,PORTABLE_WASM_ABI_LAYOUTTypeScript,经由
decodeWasmVectorGeometry:RenderCoreSession.getVectorGeometryuint32_t struct_size源码uint32_t endpoint源码uint32_t id_offset源码uint32_t id_size源码uint32_t segment_id_offset源码uint32_t segment_id_size源码uint32_t vertex_id_offset源码uint32_t vertex_id_size源码double local_x源码double local_y源码double screen_x源码double screen_y源码
源码struct TacoRenderVectorEditingComponent临时矢量编辑叠加层中一个选中的组成部分。其标识是 (kind, identifier) 这一对值;不同 kind 之间的 identifier 可以相同。最多只能有一条记录带有 PRIMARY,并且该记录属于选区。
TypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t struct_size源码uint32_t kind源码uint32_t id_offset源码uint32_t id_size源码uint32_t flags源码uint32_t[3] reserved源码
源码enum TacoRenderVectorEditingComponentFlagsTACO_RENDER_VECTOR_EDITING_COMPONENT_PRIMARY = 1源码
源码struct TacoRenderVectorEditingOverlayQueryTypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t struct_size源码uint32_t reserved源码uint64_t expected_generation源码
源码enum TacoRenderVectorEditingPendingHandleFlagsA pending handle is a curve handle that no segment of the preview network owns yet: the one a Pen drag pulls out of a vertex for the segment drawn from it next. It is editing chrome only (a guide line and a knob) and never changes the painted preview. MIRRORED also draws its exact mirror about the vertex, for a vertex no segment arrives at. Without PRESENT every pending handle field is zero.
TACO_RENDER_VECTOR_EDITING_PENDING_HANDLE_PRESENT = 1源码TACO_RENDER_VECTOR_EDITING_PENDING_HANDLE_MIRRORED = 2源码
源码enum TacoRenderVectorEndpointTACO_RENDER_VECTOR_ENDPOINT_NONE = 0源码TACO_RENDER_VECTOR_ENDPOINT_START = 1源码TACO_RENDER_VECTOR_ENDPOINT_END = 2源码
源码struct TacoRenderVectorHitTypeScript:
decodeWasmVectorHits,PORTABLE_WASM_ABI_LAYOUTTypeScript,经由
decodeWasmVectorHits:RenderCoreSession.hitTestVectoruint32_t struct_size源码uint32_t kind源码uint32_t id_offset源码uint32_t id_size源码uint32_t priority源码uint32_t endpoint源码uint32_t reserved源码double distance_css_px源码
源码struct TacoRenderVectorHitBufferResultTypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t struct_size源码uint32_t hit_count源码uint32_t identifier_byte_count源码uint32_t reserved源码uint64_t generation源码
源码struct TacoRenderVectorHitQueryTypeScript:
PORTABLE_WASM_ABI_LAYOUTuint32_t struct_size源码uint32_t reserved源码uint64_t expected_generation源码double screen_x源码double screen_y源码double tolerance_css_px源码double[6] document_to_screen源码
源码struct TacoRenderVectorRegionTypeScript:
decodeWasmVectorGeometry,PORTABLE_WASM_ABI_LAYOUTTypeScript,经由
decodeWasmVectorGeometry:RenderCoreSession.getVectorGeometryuint32_t struct_size源码uint32_t winding_rule源码uint32_t id_offset源码uint32_t id_size源码uint32_t[3] reserved源码TacoRenderRect local_bounds源码TacoRenderRect screen_bounds源码
源码struct TacoRenderVectorSegmentTypeScript:
decodeWasmVectorGeometry,PORTABLE_WASM_ABI_LAYOUTTypeScript,经由
decodeWasmVectorGeometry:RenderCoreSession.getVectorGeometryuint32_t struct_size源码uint32_t kind源码uint32_t id_offset源码uint32_t id_size源码uint32_t start_vertex_id_offset源码uint32_t start_vertex_id_size源码uint32_t end_vertex_id_offset源码uint32_t end_vertex_id_size源码uint32_t start_handle_id_offset源码uint32_t start_handle_id_size源码uint32_t end_handle_id_offset源码uint32_t end_handle_id_size源码uint32_t flags源码TacoRenderRect local_bounds源码TacoRenderRect screen_bounds源码double radius_x源码double radius_y源码double x_axis_rotation源码
源码enum TacoRenderVectorSegmentFlagsTACO_RENDER_VECTOR_SEGMENT_LARGE_ARC = 1源码TACO_RENDER_VECTOR_SEGMENT_SWEEP = 2源码
源码enum TacoRenderVectorSegmentKindTACO_RENDER_VECTOR_SEGMENT_LINE = 1源码TACO_RENDER_VECTOR_SEGMENT_CUBIC = 2源码TACO_RENDER_VECTOR_SEGMENT_ELLIPTICAL_ARC = 3源码
源码struct TacoRenderVectorVertexTypeScript:
decodeWasmVectorGeometry,PORTABLE_WASM_ABI_LAYOUTTypeScript,经由
decodeWasmVectorGeometry:RenderCoreSession.getVectorGeometryuint32_t struct_size源码uint32_t id_offset源码uint32_t id_size源码uint32_t reserved源码double local_x源码double local_y源码double screen_x源码double screen_y源码
源码enum TacoRenderVectorWindingRuleTACO_RENDER_VECTOR_WINDING_NONZERO = 0源码TACO_RENDER_VECTOR_WINDING_EVENODD = 1源码
源码enum TacoRenderViewportModetaco_render_session_map_viewport如何把场景缩放到视口中。TACO_RENDER_VIEWPORT_FIT = 0源码等比缩放;整个场景完整放入视口内。
TACO_RENDER_VIEWPORT_FILL = 1源码等比缩放;场景铺满整个视口。
TACO_RENDER_VIEWPORT_STRETCH = 2源码x 和 y 分别缩放;场景与视口完全重合。
源码enum class taco::render::TangentConstraintMode : uint8_tkAngle = 0源码kAngleAndLength = 1源码
源码enum class taco::render::TextAlign : uint8_tkLeft = 0源码kCenter = 1源码kRight = 2源码kJustify = 3源码
源码enum class taco::render::TextAutoResize : uint8_tkNone = 0源码kHeight = 1源码kWidthAndHeight = 2源码
源码struct taco::render::TextDatadouble width源码double height源码double line_height源码TextWrap wrap源码TextAlign align源码std::string text源码std::vector<TextRun> runs源码TextVerticalAlign vertical_align源码TextOverflow overflow源码TextAutoResize auto_resize源码std::vector<RichTextStyle> styles源码std::vector<TextParagraph> paragraphs源码
源码enum class taco::render::TextDirection : uint8_tkAuto = 0源码kLtr = 1源码kRtl = 2源码
源码enum class taco::render::TextListKind : uint8_tkNone = 0源码kOrdered = 1源码kUnordered = 2源码
源码struct taco::render::TextListMarkerbool has_text源码std::string text源码bool has_style源码uint32_t style_index源码bool has_gap源码double gap源码
源码enum class taco::render::TextOverflow : uint8_tkClip = 0源码kVisible = 1源码
源码struct taco::render::TextParagraphTextDirection direction源码TextAlign align源码double spacing_before源码double spacing_after源码bool has_indent源码TextParagraphIndent indent源码TextParagraphList list源码std::string text源码std::vector<RichTextRun> runs源码
源码struct taco::render::TextParagraphIndentdouble left源码double right源码double first_line源码
源码struct taco::render::TextParagraphListTextListKind kind源码uint32_t level源码bool has_start源码uint32_t start源码bool has_marker源码TextListMarker marker源码
源码struct taco::render::TextRunuint32_t start_byte源码uint32_t end_byte源码std::string font_resource_id源码double font_size源码double letter_spacing源码uint16_t weight源码bool italic源码bool underline源码bool strikethrough源码Color color源码std::vector<OpenTypeFeature> open_type_features源码std::vector<FontVariation> font_variations源码
源码enum class taco::render::TextVerticalAlign : uint8_tkTop = 0源码kMiddle = 1源码kBottom = 2源码
源码enum class taco::render::TextWrap : uint8_tkNone = 0源码kWord = 1源码kCharacter = 2源码
源码TacoRenderRect taco::render::toRect(const Bounds &bounds)C ABI:
taco_render_session_hit_test,taco_render_session_get_last_dirty_bounds
源码struct taco::render::Transform以
values = [a, b, c, d, e, f]存储的仿射矩阵,布局与 TypeScript 的Transform相同。点的映射方式为 。std::array<double, 6> values源码
源码Bounds taco::render::unionBounds(const Bounds &first, const Bounds &second)
源码struct taco::render::VectorGeometryQueryResultstd::vector<TacoRenderVectorVertex> vertices源码std::vector<TacoRenderVectorCubicHandle> handles源码std::vector<TacoRenderVectorSegment> segments源码std::vector<TacoRenderVectorRegion> regions源码std::string identifiers源码
源码struct taco::render::VectorHandlestd::string_view id源码double dx源码double dy源码
源码struct taco::render::VectorHitQueryResultstd::vector<TacoRenderVectorHit> hits源码std::string identifiers源码
源码VectorPathOpsStats &taco::render::skia_path_ops::vectorPathOpsStats()
源码struct taco::render::skia_path_ops::VectorPathOpsStatsint id_concat_temporaries源码uint64_t contour_pair_checks源码Pairs of contours
vectorNetworkFromPathcompared to group contours into regions.uint64_t projected_segments源码Segments
vectorNetworkFromPathlast counted in a path before making any (counting stops just past the limit), and segments made from path verbs since the last reset: none when a path was refused by that count.uint64_t contour_segments源码
源码struct taco::render::VectorRegionstd::string_view id源码WindingRule winding_rule源码bool has_explicit_fills源码std::vector<RetainedPaint> fills源码std::vector<VectorRegionLoop> loops源码
源码struct taco::render::VectorRegionLoopbool implicit_close源码std::vector<VectorSegmentReference> segments源码
源码struct taco::render::VectorSegmentstd::string_view id源码std::string_view start_vertex_id源码std::string_view end_vertex_id源码SegmentKind kind源码VectorHandle start_handle源码VectorHandle end_handle源码double radius_x源码double radius_y源码double x_axis_rotation源码bool large_arc源码bool sweep源码
源码struct taco::render::VectorSegmentReferencestd::string_view segment_id源码SegmentDirection direction源码
源码struct taco::render::VectorTangentConstraintstd::string_view vertex_id源码std::array<std::string_view, 2> handle_ids源码TangentConstraintMode mode源码
源码struct taco::render::VectorVertexstd::string_view id源码double x源码double y源码double corner_radius源码Wire 版本 12:当该顶点恰好连接两条直线段或三次曲线段时,正的半径会在绘制时将其圆角化。设计时的位置仍作为编辑和查询所用的几何。
源码enum class taco::render::WindingRule : uint8_tkNonzero = 0源码kEvenodd = 1源码