@effing/canvas 0.43.0 → 0.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/image.ts","../src/lottie.ts","../src/jsx/draw/utils.ts","../src/jsx/style/compute.ts","../src/jsx/text/native.ts","../src/jsx/language.ts","../src/jsx/text/measure.ts","../src/jsx/text/white-space.ts","../src/jsx/text/index.ts","../src/jsx/draw/clip.ts","../src/jsx/draw/clip-path.ts","../src/jsx/draw/rect.ts","../src/jsx/draw/gradient.ts","../src/jsx/draw/group.ts","../src/jsx/draw/object-fit.ts","../src/jsx/draw/image.ts","../src/jsx/draw/svg/style.ts","../src/jsx/draw/svg/tree.ts","../src/jsx/draw/svg/defs.ts","../src/jsx/draw/svg/transform.ts","../src/jsx/draw/svg/path.ts","../src/jsx/draw/offscreen.ts","../src/jsx/draw/svg/filters.ts","../src/jsx/draw/svg/shapes.ts","../src/jsx/draw/svg/gradients.ts","../src/jsx/draw/svg/paint.ts","../src/jsx/draw/svg/traverse.ts","../src/jsx/draw/svg/index.ts","../src/jsx/draw/text.ts","../src/jsx/emoji.ts","../src/jsx/draw/index.ts","../src/jsx/font.ts","../src/jsx/style/expand.ts","../src/jsx/yoga.ts","../src/jsx/style/properties.ts","../src/jsx/layout.ts","../src/jsx/index.ts","../src/fit-text.ts"],"sourcesContent":["// Re-export canvas primitives from @effing/skia so consumers never need a\n// direct dependency on it (it's a dependency of this package, which pnpm does\n// not expose to the consuming project). Re-exporting also guarantees a single\n// native copy:\n// a Path2D from one copy of @effing/skia cannot be used with a context from\n// another.\nimport { createCanvas as _createCanvas } from \"@effing/skia\";\nexport {\n Canvas,\n type SKRSContext2D,\n GlobalFonts,\n Image,\n ImageData,\n Path2D,\n DOMMatrix,\n DOMPoint,\n DOMRect,\n PathOp,\n FillType,\n StrokeJoin,\n StrokeCap,\n} from \"@effing/skia\";\n\n// loadImage is wrapped (not re-exported) so remote URLs go through the same\n// fetch path as <img> sources — see ./image.ts.\nexport {\n loadImage,\n type ImageCache,\n type LoadImageOptions,\n type LoadImageSource,\n} from \"./image.ts\";\n\n// encode() needs no patching: it snapshots the canvas when called, so later\n// drawing can't reach a pending encode, and the Buffer it resolves with owns\n// its native memory until the Buffer itself is collected (see\n// ./encode.test.ts). This used to copy the result to the JS heap, to guard\n// against lifetime bugs in @napi-rs/canvas's async encode that were fixed\n// upstream (napi-rs/canvas#1314, #1323) before @effing/skia was forked.\nexport function createCanvas(width: number, height: number) {\n return _createCanvas(width, height);\n}\n\n// Lottie API\nexport { LottieAnimation, loadLottie, renderLottieFrame } from \"./lottie.ts\";\n\n// JSX API\nexport { renderReactElement } from \"./jsx/index.ts\";\n\n// Font management\nexport {\n registerFont,\n registerFontFromPath,\n registeredFamilies,\n} from \"./jsx/font.ts\";\n\n// Fit text\nexport {\n findLargestUsableFontSize,\n type FindLargestUsableFontSizeOptions,\n} from \"./fit-text.ts\";\n\n// Types\nexport type {\n FontData,\n RenderReactElementOptions,\n EmojiStyle,\n} from \"./types.ts\";\n","import type { Image } from \"@effing/skia\";\nimport { loadImage as nativeLoadImage } from \"@effing/skia\";\n\n/** Source types accepted by {@link loadImage}, mirroring @effing/skia. */\nexport type LoadImageSource = Parameters<typeof nativeLoadImage>[0];\n\n/** Options for {@link loadImage}. */\nexport interface LoadImageOptions {\n /**\n * User-Agent header sent on remote (http/https) fetches. Matches the\n * `userAgent` option of `renderReactElement`, so `loadImage(url)` and an\n * `<img src={url}>` behave identically. An empty string is sent as an\n * explicit empty header; values with CR/LF cause fetch to throw `TypeError`.\n * Ignored for non-remote sources (paths, Buffers, data URIs).\n */\n userAgent?: string;\n}\n\n/**\n * Load an image from a path, Buffer, data URI, or remote URL.\n *\n * Remote http/https URLs are fetched via global fetch() and passed to the\n * native loader as bytes — the same path `<img>` sources take in\n * `renderReactElement`. This keeps `loadImage(url)` and `<img src={url}>`\n * consistent: both honor a global dispatcher / proxy (undici's\n * setGlobalDispatcher) and the `userAgent` option. @effing/skia's own URL\n * loader uses Node's raw http modules, which bypass any dispatcher, so it is\n * only used for non-remote sources here.\n *\n * Note: @effing/skia's `maxRedirects` / `requestOptions` load options are\n * intentionally not exposed — they only configure its built-in URL loader,\n * which this wrapper bypasses. Control remote fetches via fetch/undici instead.\n */\nexport function loadImage(\n source: LoadImageSource,\n options?: LoadImageOptions,\n): Promise<Image> {\n const remoteUrl =\n typeof source === \"string\" && isRemoteUrl(source)\n ? source\n : source instanceof URL && isRemoteUrl(source.href)\n ? source.href\n : undefined;\n if (remoteUrl !== undefined) {\n return loadRemoteImage(remoteUrl, options?.userAgent);\n }\n return nativeLoadImage(source);\n}\n\n/**\n * Per-render cache of image load promises, keyed by source string.\n * Shared between layout and draw phases to avoid duplicate loads.\n */\nexport type ImageCache = Map<string, Promise<Image>>;\n\n/**\n * Load an image via {@link loadImage}, deduplicating by source string through\n * the cache. Buffer sources are never cached (no stable key). `userAgent`, when\n * set, is forwarded to remote (http/https) fetches. The cache key is the URL\n * alone — the userAgent of the first call for a given URL is the one that hits\n * the wire; a later call with a different userAgent reuses the cached promise.\n *\n * Failed loads are evicted, so only successful loads stay cached: callers\n * sharing one cache across many renders (`options.imageCache`) retry a\n * transiently-failed source on the next call instead of replaying the\n * rejection forever.\n */\nexport function cachedLoadImage(\n cache: ImageCache,\n src: string | Buffer,\n userAgent?: string,\n): Promise<Image> {\n if (Buffer.isBuffer(src)) return loadImage(src);\n let entry = cache.get(src);\n if (!entry) {\n const created = loadImage(\n src,\n userAgent === undefined ? undefined : { userAgent },\n );\n created.catch(() => {\n if (cache.get(src) === created) cache.delete(src);\n });\n cache.set(src, created);\n entry = created;\n }\n return entry;\n}\n\n/**\n * True for http/https URLs, which are loaded via fetch() rather than the\n * native loader. Scheme match is case-insensitive (RFC 3986 §3.1).\n */\nexport function isRemoteUrl(src: string): boolean {\n return /^https?:\\/\\//i.test(src);\n}\n\n/**\n * Fetch a remote image via global fetch() and decode the bytes with the native\n * loader. Routing through fetch (rather than @effing/skia's raw-http URL\n * loader) lets a global dispatcher / proxy and the `userAgent` apply.\n */\nexport async function loadRemoteImage(\n url: string,\n userAgent?: string,\n): Promise<Image> {\n const init: RequestInit | undefined =\n userAgent !== undefined\n ? { headers: { \"User-Agent\": userAgent } }\n : undefined;\n const response = await fetch(url, init);\n if (!response.ok) {\n throw new Error(\n `Failed to fetch image ${url}: ${response.status} ${response.statusText}`,\n );\n }\n const buffer = Buffer.from(await response.arrayBuffer());\n return nativeLoadImage(buffer);\n}\n","import { LottieAnimation } from \"@effing/skia\";\nimport type { SKRSContext2D } from \"@effing/skia\";\n\nexport { LottieAnimation };\n\n/**\n * Load a Lottie animation from a JSON string or Buffer.\n *\n * @param data - Lottie JSON string or Buffer\n * @param options - Optional resource path for external assets\n * @returns A `LottieAnimation` handle ready for rendering\n *\n * @example\n * ```ts\n * const anim = loadLottie(fs.readFileSync(\"animation.json\", \"utf-8\"));\n * ```\n */\nexport function loadLottie(\n data: string | Buffer,\n options?: { resourcePath?: string },\n): LottieAnimation {\n const jsonString = typeof data === \"string\" ? data : data.toString(\"utf-8\");\n return LottieAnimation.loadFromData(jsonString, {\n resourcePath: options?.resourcePath,\n });\n}\n\n/**\n * Render a specific frame of a Lottie animation to a canvas context.\n *\n * Seeks the animation to the given frame, then renders it onto the\n * provided context. The canvas dimensions determine the render size.\n *\n * @param ctx - Canvas 2D rendering context to draw into\n * @param animation - Lottie animation handle (from {@link loadLottie})\n * @param frame - Zero-based frame number to render\n *\n * @example\n * ```ts\n * import { createCanvas, loadLottie, renderLottieFrame } from \"@effing/canvas\";\n *\n * const canvas = createCanvas(1080, 1080);\n * const ctx = canvas.getContext(\"2d\");\n * const anim = loadLottie(jsonString);\n *\n * renderLottieFrame(ctx, anim, 0);\n * const png = canvas.encodeSync(\"png\");\n * ```\n */\nexport function renderLottieFrame(\n ctx: SKRSContext2D,\n animation: LottieAnimation,\n frame: number,\n): void {\n animation.seekFrame(frame);\n animation.render(ctx);\n}\n","/**\n * Shared CSS utility functions used by the draw system.\n */\n\nexport function parseCSSLength(value: string, referenceSize: number): number {\n if (value.endsWith(\"%\")) return (parseFloat(value) / 100) * referenceSize;\n return parseFloat(value);\n}\n\nexport function toNumber(v: unknown): number {\n if (typeof v === \"number\") return v;\n if (v === undefined || v === null) return 0;\n const n = parseFloat(String(v));\n return isNaN(n) ? 0 : n;\n}\n\n/**\n * Resolve a box-model value (padding, border-width) that may be a percentage.\n * Per CSS spec, percentage padding/border resolves against the element's width\n * (even for top/bottom).\n */\nexport function resolveBoxValue(v: unknown, referenceWidth: number): number {\n if (typeof v === \"number\") return v;\n if (v === undefined || v === null) return 0;\n const s = String(v);\n if (s.endsWith(\"%\")) return (parseFloat(s) / 100) * referenceWidth;\n const n = parseFloat(s);\n return isNaN(n) ? 0 : n;\n}\n\n/**\n * Format a number for embedding in a CSS string. `String(n)` switches to\n * exponent notation for very small or large magnitudes (`1e-7`), which CSS\n * parsers reject, so round to six decimals and print positionally.\n */\nexport function formatCSSNumber(n: number): string {\n const fixed = n.toFixed(6).replace(/\\.?0+$/, \"\");\n return fixed === \"-0\" || fixed === \"\" ? \"0\" : fixed;\n}\n","// This file contains code adapted from Satori (https://github.com/vercel/satori)\n// Licensed under the Mozilla Public License 2.0 (MPL-2.0)\n// See NOTICE.md in the package root for details.\n\nimport { formatCSSNumber } from \"../draw/utils.ts\";\n\n/**\n * Style after shorthand expansion but before unit resolution.\n * Properties like fontSize may still contain CSS unit strings (e.g. \"4em\").\n */\nexport type ExpandedStyle = Omit<ComputedStyle, \"fontSize\"> & {\n fontSize?: number | string;\n};\n\n/**\n * Normalized, computed CSS style after shorthand expansion.\n * All dimension values are numbers (pixels) or percentage strings.\n */\nexport type ComputedStyle = {\n // Display & layout\n display?: \"flex\" | \"none\";\n flexDirection?: \"row\" | \"column\" | \"row-reverse\" | \"column-reverse\";\n justifyContent?:\n | \"flex-start\"\n | \"flex-end\"\n | \"center\"\n | \"space-between\"\n | \"space-around\"\n | \"space-evenly\";\n alignItems?: \"flex-start\" | \"flex-end\" | \"center\" | \"stretch\" | \"baseline\";\n alignSelf?:\n \"auto\" | \"flex-start\" | \"flex-end\" | \"center\" | \"stretch\" | \"baseline\";\n alignContent?:\n | \"flex-start\"\n | \"flex-end\"\n | \"center\"\n | \"stretch\"\n | \"space-between\"\n | \"space-around\";\n flexWrap?: \"nowrap\" | \"wrap\" | \"wrap-reverse\";\n flexGrow?: number;\n flexShrink?: number;\n flexBasis?: number | string;\n\n // Dimensions\n width?: number | string;\n height?: number | string;\n minWidth?: number | string;\n minHeight?: number | string;\n maxWidth?: number | string;\n maxHeight?: number | string;\n\n // Position\n position?: \"relative\" | \"absolute\";\n top?: number | string;\n right?: number | string;\n bottom?: number | string;\n left?: number | string;\n\n // Margin\n marginTop?: number | string;\n marginRight?: number | string;\n marginBottom?: number | string;\n marginLeft?: number | string;\n\n // Padding\n paddingTop?: number | string;\n paddingRight?: number | string;\n paddingBottom?: number | string;\n paddingLeft?: number | string;\n\n // Border\n borderTopWidth?: number | string;\n borderRightWidth?: number | string;\n borderBottomWidth?: number | string;\n borderLeftWidth?: number | string;\n borderTopColor?: string;\n borderRightColor?: string;\n borderBottomColor?: string;\n borderLeftColor?: string;\n borderTopStyle?: string;\n borderRightStyle?: string;\n borderBottomStyle?: string;\n borderLeftStyle?: string;\n borderTopLeftRadius?: number | string;\n borderTopRightRadius?: number | string;\n borderBottomRightRadius?: number | string;\n borderBottomLeftRadius?: number | string;\n\n // Gap\n rowGap?: number;\n columnGap?: number;\n\n // Overflow\n overflow?: string;\n overflowX?: string;\n overflowY?: string;\n\n // Colors & background\n backgroundColor?: string;\n color?: string;\n opacity?: number;\n backgroundImage?: string;\n backgroundSize?: string;\n backgroundRepeat?:\n \"repeat\" | \"no-repeat\" | \"repeat-x\" | \"repeat-y\" | \"space\" | \"round\";\n\n // Typography\n fontSize?: number;\n fontFamily?: string;\n fontWeight?: number | string;\n fontStyle?: \"normal\" | \"italic\";\n textAlign?: \"left\" | \"center\" | \"right\" | \"justify\";\n textDecoration?: string;\n textTransform?: \"none\" | \"uppercase\" | \"lowercase\" | \"capitalize\";\n lineHeight?: number | string;\n letterSpacing?: number | string;\n whiteSpace?: \"normal\" | \"nowrap\" | \"pre\" | \"pre-wrap\" | \"pre-line\";\n wordBreak?: \"normal\" | \"break-all\" | \"break-word\" | \"keep-all\";\n overflowWrap?: \"normal\" | \"break-word\" | \"anywhere\";\n textOverflow?: \"clip\" | \"ellipsis\";\n lineClamp?: number;\n\n // Box shadow\n boxShadow?: string;\n textShadow?: string;\n\n // Transform\n transform?: string;\n transformOrigin?: string;\n\n // Image\n objectFit?: \"contain\" | \"cover\" | \"fill\" | \"none\" | \"scale-down\";\n\n // Filter\n filter?: string;\n backdropFilter?: string;\n\n // Clipping\n clipPath?: string;\n\n // Text box trim\n textBoxTrim?: \"none\" | \"trim-start\" | \"trim-end\" | \"trim-both\";\n textBoxEdge?: string;\n\n // Text stroke\n WebkitTextStrokeWidth?: number | string;\n WebkitTextStrokeColor?: string;\n};\n\nconst ROOT_FONT_SIZE = 16;\n\n/**\n * Default font family. Uses concrete system font names so @effing/skia\n * resolves real font metrics instead of generic ratios for unnamed families.\n */\nexport const DEFAULT_FONT_FAMILY = \"Helvetica, Arial, sans-serif\";\n\n/**\n * Default styles for the root element.\n */\nexport const DEFAULT_STYLE: ComputedStyle = {\n display: \"flex\",\n flexDirection: \"row\",\n flexWrap: \"nowrap\",\n flexGrow: 0,\n flexShrink: 0,\n alignItems: \"stretch\",\n justifyContent: \"flex-start\",\n position: \"relative\",\n fontSize: ROOT_FONT_SIZE,\n fontWeight: 400,\n fontStyle: \"normal\",\n fontFamily: DEFAULT_FONT_FAMILY,\n color: \"black\",\n lineHeight: \"normal\",\n textAlign: \"left\",\n whiteSpace: \"normal\",\n wordBreak: \"normal\",\n textOverflow: \"clip\",\n opacity: 1,\n overflow: \"visible\",\n};\n\n/**\n * CSS properties that are inherited by child elements.\n */\nconst INHERITABLE_PROPS: (keyof ComputedStyle)[] = [\n \"color\",\n \"fontSize\",\n \"fontFamily\",\n \"fontWeight\",\n \"fontStyle\",\n \"textAlign\",\n \"textTransform\",\n \"textDecoration\",\n \"lineHeight\",\n \"letterSpacing\",\n \"whiteSpace\",\n \"wordBreak\",\n \"overflowWrap\",\n \"textOverflow\",\n \"lineClamp\",\n \"textBoxTrim\",\n \"textBoxEdge\",\n \"textShadow\",\n \"WebkitTextStrokeWidth\",\n \"WebkitTextStrokeColor\",\n];\n\n/**\n * Resolve the computed style for a node, inheriting from parent where appropriate.\n */\nexport function resolveStyle(\n rawStyle: ExpandedStyle | undefined,\n parentStyle: ComputedStyle,\n): ComputedStyle {\n const style = { ...rawStyle };\n\n // Apply inherited properties\n for (const prop of INHERITABLE_PROPS) {\n if (style[prop] === undefined && parentStyle[prop] !== undefined) {\n (style as Record<string, unknown>)[prop] = parentStyle[prop];\n }\n }\n\n // Resolve fontSize (ensure it's a number, respecting em/rem/etc units)\n if (typeof style.fontSize === \"string\") {\n const parentFontSize =\n typeof parentStyle.fontSize === \"number\"\n ? parentStyle.fontSize\n : ROOT_FONT_SIZE;\n const resolved = resolveUnit(\n style.fontSize,\n 0,\n 0,\n parentFontSize,\n ROOT_FONT_SIZE,\n );\n style.fontSize = typeof resolved === \"number\" ? resolved : parentFontSize;\n }\n\n // Resolve lineHeight: parse string values to numbers but keep multipliers\n // as-is so they're recalculated per-element in text layout (using each\n // element's own fontSize rather than the parent's).\n if (typeof style.lineHeight === \"string\") {\n const str = style.lineHeight;\n if (str.endsWith(\"%\")) {\n style.lineHeight = parseFloat(str) / 100;\n } else {\n const parsed = parseFloat(str);\n if (!isNaN(parsed)) {\n style.lineHeight = parsed;\n }\n }\n }\n\n // Resolve letterSpacing (respecting em/rem/etc units)\n if (typeof style.letterSpacing === \"string\") {\n const currentFontSize =\n typeof style.fontSize === \"number\"\n ? style.fontSize\n : typeof parentStyle.fontSize === \"number\"\n ? parentStyle.fontSize\n : ROOT_FONT_SIZE;\n const resolved = resolveUnit(\n style.letterSpacing,\n 0,\n 0,\n currentFontSize,\n ROOT_FONT_SIZE,\n );\n if (typeof resolved === \"number\") {\n style.letterSpacing = resolved;\n }\n }\n\n return style as ComputedStyle;\n}\n\n/**\n * Dimension properties that may contain CSS units needing resolution.\n */\nconst DIMENSION_PROPS: (keyof ComputedStyle)[] = [\n \"width\",\n \"height\",\n \"minWidth\",\n \"minHeight\",\n \"maxWidth\",\n \"maxHeight\",\n \"top\",\n \"right\",\n \"bottom\",\n \"left\",\n \"marginTop\",\n \"marginRight\",\n \"marginBottom\",\n \"marginLeft\",\n \"paddingTop\",\n \"paddingRight\",\n \"paddingBottom\",\n \"paddingLeft\",\n \"rowGap\",\n \"columnGap\",\n \"flexBasis\",\n \"borderTopWidth\",\n \"borderRightWidth\",\n \"borderBottomWidth\",\n \"borderLeftWidth\",\n \"borderTopLeftRadius\",\n \"borderTopRightRadius\",\n \"borderBottomRightRadius\",\n \"borderBottomLeftRadius\",\n \"WebkitTextStrokeWidth\",\n];\n\n/**\n * Resolve a single CSS dimension string to a pixel number.\n * Returns the original value for `%` and `auto` (Yoga handles those),\n * and for values that are already numbers or unrecognised strings.\n */\nexport function resolveUnit(\n value: string,\n viewportWidth: number,\n viewportHeight: number,\n fontSize: number,\n rootFontSize: number,\n): number | string {\n // Percentages and auto are handled downstream by Yoga\n if (value.endsWith(\"%\") || value === \"auto\") return value;\n\n // Viewport-relative units\n if (value.endsWith(\"vmin\")) {\n const n = parseFloat(value);\n return isNaN(n)\n ? value\n : (n / 100) * Math.min(viewportWidth, viewportHeight);\n }\n if (value.endsWith(\"vmax\")) {\n const n = parseFloat(value);\n return isNaN(n)\n ? value\n : (n / 100) * Math.max(viewportWidth, viewportHeight);\n }\n if (value.endsWith(\"vw\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : (n / 100) * viewportWidth;\n }\n if (value.endsWith(\"vh\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : (n / 100) * viewportHeight;\n }\n\n // Font-relative units\n if (value.endsWith(\"rem\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * rootFontSize;\n }\n if (value.endsWith(\"em\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * fontSize;\n }\n\n // Absolute units (CSS reference pixel = 1/96 inch)\n if (value.endsWith(\"px\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n;\n }\n if (value.endsWith(\"pt\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * (96 / 72);\n }\n if (value.endsWith(\"pc\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * 16;\n }\n if (value.endsWith(\"in\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * 96;\n }\n if (value.endsWith(\"cm\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * (96 / 2.54);\n }\n if (value.endsWith(\"mm\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * (96 / 25.4);\n }\n\n return value;\n}\n\n/**\n * Resolve CSS units (vw, vh, vmin, vmax, em, rem, px, pt, pc, in, cm, mm)\n * in a style object to pixel values. Percentages and `auto` pass through\n * unchanged for Yoga to handle.\n */\nexport function resolveUnits(\n style: ComputedStyle,\n viewportWidth: number,\n viewportHeight: number,\n rootFontSize: number = ROOT_FONT_SIZE,\n): ComputedStyle {\n const fontSize =\n typeof style.fontSize === \"number\" ? style.fontSize : rootFontSize;\n\n for (const prop of DIMENSION_PROPS) {\n const value = style[prop];\n if (typeof value !== \"string\") continue;\n const resolved = resolveUnit(\n value,\n viewportWidth,\n viewportHeight,\n fontSize,\n rootFontSize,\n );\n if (resolved !== value) {\n (style as Record<string, unknown>)[prop] = resolved;\n }\n }\n\n // Resolve CSS length units inside transform, clip-path and backdrop-filter\n // strings so that by draw time values are either bare numbers or `%` (which\n // need element dimensions).\n for (const [prop, suffix] of LENGTH_STRING_PROPS) {\n const value = style[prop];\n if (typeof value !== \"string\") continue;\n (style as Record<string, unknown>)[prop] = resolveLengthUnits(\n value,\n viewportWidth,\n viewportHeight,\n fontSize,\n rootFontSize,\n suffix,\n );\n }\n\n return style;\n}\n\n/**\n * String-valued properties whose embedded CSS lengths are resolved to pixels,\n * with the suffix the resolved numbers are written with. The transform parser\n * takes bare numbers; clip-path and filter strings keep an explicit `px` so\n * they stay valid CSS for the parsers downstream (Skia's filter parser\n * rejects a unitless `blur(6)`).\n */\nconst LENGTH_STRING_PROPS: [keyof ComputedStyle, string][] = [\n [\"transform\", \"\"],\n [\"transformOrigin\", \"\"],\n [\"clipPath\", \"px\"],\n [\"filter\", \"px\"],\n [\"backdropFilter\", \"px\"],\n];\n\n/**\n * Resolve CSS length units (vw, vh, em, rem, px, etc.) inside a string value\n * such as a transform, clip-path or filter. Percentages and angle units (deg,\n * rad, turn) are left untouched — percentages need element dimensions\n * (available at draw time) and angle units are not lengths.\n */\nfunction resolveLengthUnits(\n transform: string,\n viewportWidth: number,\n viewportHeight: number,\n fontSize: number,\n rootFontSize: number,\n suffix = \"\",\n): string {\n return transform.replace(\n // The lookbehind keeps a number from being matched mid-token (`1e1em`).\n /(?<![\\w.])(-?\\d*\\.?\\d+)(vw|vh|vmin|vmax|em|rem|px|pt|pc|in|cm|mm)\\b/g,\n (match) => {\n const resolved = resolveUnit(\n match,\n viewportWidth,\n viewportHeight,\n fontSize,\n rootFontSize,\n );\n return typeof resolved === \"number\"\n ? `${formatCSSNumber(resolved)}${suffix}`\n : match;\n },\n );\n}\n\n/**\n * Resolve a dimension value (width, height, margin, etc.) to pixels.\n * Percentage values are resolved relative to the provided container size.\n */\nexport function resolveDimension(\n value: number | string | undefined,\n containerSize: number,\n): number | undefined {\n if (value === undefined || value === \"auto\") return undefined;\n if (typeof value === \"number\") return value;\n const s = String(value);\n if (s.endsWith(\"%\")) {\n return (parseFloat(s) / 100) * containerSize;\n }\n const n = parseFloat(s);\n return isNaN(n) ? undefined : n;\n}\n","// Native paragraph layout through @effing/skia's `Paragraph`: Skia breaks,\n// shapes and paints the text in one place, instead of this package measuring\n// it word by word across the native boundary. The paragraph follows the CSS\n// line model (every line box exactly `lineHeight` tall, baseline placed by\n// half-leading from the font's hhea metrics) and paints unhinted, unsnapped\n// glyphs.\n\nimport { Paragraph } from \"@effing/skia/extensions\";\nimport type {\n ParagraphLine,\n ParagraphPlaceholder,\n ParagraphStyle,\n} from \"@effing/skia/extensions\";\n\nimport type { ComputedStyle } from \"../style/compute.ts\";\nimport { DEFAULT_FONT_FAMILY } from \"../style/compute.ts\";\nimport { isEmoji } from \"../language.ts\";\nimport { measureTrimMetrics, quoteFontFamilies } from \"./measure.ts\";\nimport type { PlacedEmoji, TextLayoutResult, TextSegment } from \"./index.ts\";\n\nexport type NativeParagraph = Paragraph;\n\nfunction toWeight(weight: number | string | undefined): number {\n if (typeof weight === \"number\") return weight;\n if (weight === \"bold\") return 700;\n const parsed = parseInt(String(weight ?? \"400\"), 10);\n return isNaN(parsed) ? 400 : parsed;\n}\n\nfunction toFontStyle(\n fontStyle: string | undefined,\n): ParagraphStyle[\"fontStyle\"] {\n if (fontStyle?.startsWith(\"italic\")) return \"italic\";\n if (fontStyle?.startsWith(\"oblique\")) return \"oblique\";\n return \"normal\";\n}\n\nconst TEXT_ALIGNS = new Set([\n \"left\",\n \"right\",\n \"center\",\n \"justify\",\n \"start\",\n \"end\",\n]);\n\nfunction toTextAlign(\n textAlign: string | undefined,\n): ParagraphStyle[\"textAlign\"] {\n return textAlign !== undefined && TEXT_ALIGNS.has(textAlign)\n ? (textAlign as ParagraphStyle[\"textAlign\"])\n : \"left\";\n}\n\n/** CSS `word-break`, as the paragraph's `wordBreak`. */\nfunction toWordBreak(style: ComputedStyle): ParagraphStyle[\"wordBreak\"] {\n const { wordBreak } = style;\n return wordBreak === \"break-all\" || wordBreak === \"keep-all\"\n ? wordBreak\n : \"normal\";\n}\n\n/**\n * CSS `overflow-wrap`, as the paragraph's `overflowWrap`. The deprecated\n * `word-break: break-word` is `overflow-wrap: anywhere`, which breaks an\n * overlong word as `break-word` does (it only adds to min-content). The\n * legacy `word-wrap` arrives as `overflowWrap` (see `expandStyle`).\n */\nfunction toOverflowWrap(style: ComputedStyle): ParagraphStyle[\"overflowWrap\"] {\n const { overflowWrap, wordBreak } = style;\n return overflowWrap === \"break-word\" ||\n overflowWrap === \"anywhere\" ||\n wordBreak === \"break-word\"\n ? \"break-word\"\n : \"normal\";\n}\n\n// Skia treats a width of 0 as unbounded; a box with no room wraps at every\n// opportunity instead.\nconst MIN_WIDTH = 0.01;\n\n// A paragraph needs a font size > 0. CSS draws `font-size: 0` text as\n// nothing, in line boxes of no height under `line-height: normal`.\nconst MIN_FONT_SIZE = 1e-3;\n\n/**\n * Where an emoji drawn as an image sits on its line: its bottom 0.1em below\n * the baseline, as CSS `vertical-align: -0.1em`. That's where Chrome draws an\n * emoji glyph (Apple Color Emoji's 🌍 ink spans 0.115em below the baseline to\n * 0.865em above it, at any line height), and what twemoji's own stylesheet\n * gives its images.\n */\nconst EMOJI_DROP = 0.1;\n\n// A paragraph's native memory (some 20 KB) is released by a finalizer, and\n// Node only runs finalizers on a later turn of the event loop. A frame loop\n// that awaits nothing but microtasks never gets there, and would grow by every\n// paragraph it has built. So they are counted per turn, and a render that\n// finds too many outstanding yields one turn itself.\nconst MAX_PENDING_PARAGRAPHS = 2000;\nlet pendingParagraphs = 0;\nlet turnWatched = false;\n\nfunction countParagraph(): void {\n pendingParagraphs++;\n if (turnWatched) return;\n turnWatched = true;\n // Runs once the event loop turns, by whoever's doing.\n setImmediate(() => {\n pendingParagraphs = 0;\n turnWatched = false;\n });\n}\n\n/**\n * Give Node a turn of the event loop to release the paragraphs built so far,\n * if enough have piled up since the last one.\n */\nexport async function releaseParagraphs(): Promise<void> {\n if (pendingParagraphs < MAX_PENDING_PARAGRAPHS) return;\n await new Promise<void>((resolve) => setImmediate(resolve));\n}\n\nconst graphemeSegmenter = new Intl.Segmenter(undefined, {\n granularity: \"grapheme\",\n});\n\n/**\n * The text as a paragraph's content, with every emoji grapheme an inline\n * placeholder for its image.\n */\ntype Content = {\n items: (string | ParagraphPlaceholder)[];\n /** The emoji, in the order of their placeholders. */\n emoji: string[];\n /**\n * Maps a UTF-16 index in the paragraph's text, where a placeholder counts\n * as one unit, to one in `text`; undefined when they're the same.\n */\n toTextIndex?: (index: number) => number;\n};\n\nfunction splitEmoji(\n text: string,\n fontSize: number,\n letterSpacing: number,\n): Content {\n const items: (string | ParagraphPlaceholder)[] = [];\n const emoji: string[] = [];\n // Paragraph index → text index, at the start of each emoji and after it.\n const marks: [number, number][] = [];\n let run = \"\";\n let paragraphIndex = 0;\n let textIndex = 0;\n for (const { segment } of graphemeSegmenter.segment(text)) {\n if (!isEmoji(segment)) {\n run += segment;\n paragraphIndex += segment.length;\n textIndex += segment.length;\n continue;\n }\n if (run) items.push(run);\n run = \"\";\n items.push({\n // Letter spacing follows every character, an emoji too, but a\n // paragraph doesn't add it to a placeholder.\n width: Math.max(0, fontSize + letterSpacing),\n height: fontSize,\n verticalAlign: \"baseline\",\n baselineOffset: fontSize * (1 - EMOJI_DROP),\n // Lines break around it as around an emoji, not an inline-block: it\n // stays with the punctuation next to it, so \"Hi 🎉! ok\" breaks as\n // \"Hi | 🎉! | ok\" and \"(🎉)\" stays whole, as in browsers.\n lineBreak: \"emoji\",\n });\n emoji.push(segment);\n marks.push([paragraphIndex, textIndex]);\n paragraphIndex += 1;\n textIndex += segment.length;\n marks.push([paragraphIndex, textIndex]);\n }\n if (run) items.push(run);\n if (emoji.length === 0) return { items: [text], emoji };\n return {\n items,\n emoji,\n toTextIndex: (index) => {\n // The last mark at or before `index`; text runs map one to one.\n let mark: [number, number] = [0, 0];\n for (const m of marks) {\n if (m[0] > index) break;\n mark = m;\n }\n return mark[1] + (index - mark[0]);\n },\n };\n}\n\n/**\n * Lay out already-transformed text natively: one segment per line, CSS\n * half-leading line boxes from the font's hhea metrics, an ellipsis for\n * nowrap + text-overflow and for line-clamp, and text-box-trim.\n *\n * @param lineHeight - Line box height in px, or undefined for `normal`\n * @param emojiEnabled - Whether emoji are drawn as images, each in an inline\n * box of its own\n */\nexport function layoutTextNative(\n text: string,\n style: ComputedStyle,\n maxWidth: number,\n lineHeight: number | undefined,\n emojiEnabled?: boolean,\n): TextLayoutResult {\n const styledFontSize = style.fontSize ?? 16;\n const fontSize = Number.isFinite(styledFontSize)\n ? Math.max(styledFontSize, MIN_FONT_SIZE)\n : 16;\n const fontFamily = style.fontFamily ?? DEFAULT_FONT_FAMILY;\n const fontWeight = style.fontWeight ?? 400;\n const fontStyle = style.fontStyle ?? \"normal\";\n const letterSpacing =\n typeof style.letterSpacing === \"number\" &&\n Number.isFinite(style.letterSpacing)\n ? style.letterSpacing\n : 0;\n const whiteSpace = style.whiteSpace ?? \"normal\";\n const noWrap = whiteSpace === \"nowrap\" || whiteSpace === \"pre\";\n const lineClamp =\n style.lineClamp && style.lineClamp >= 1\n ? Math.floor(style.lineClamp)\n : undefined;\n const ellipsis =\n lineClamp !== undefined || (noWrap && style.textOverflow === \"ellipsis\")\n ? \"…\"\n : undefined;\n const width = maxWidth > 0 ? maxWidth : MIN_WIDTH;\n\n const content = emojiEnabled\n ? splitEmoji(text, fontSize, letterSpacing)\n : { items: [text], emoji: [] };\n\n // Skia keeps its own cache of shaped text, so building a paragraph for text\n // it has seen (the next frame of a video, or Yoga measuring a node again)\n // only breaks the lines anew.\n const paragraph = new Paragraph(content.items, {\n fontFamily: quoteFontFamilies(fontFamily),\n fontSize,\n fontWeight: toWeight(fontWeight),\n fontStyle: toFontStyle(fontStyle),\n letterSpacing,\n lineHeight,\n textAlign: toTextAlign(style.textAlign),\n noWrap,\n maxLines: lineClamp,\n ellipsis,\n // `pre` and `pre-wrap` keep the spaces before a line break in the line.\n keepTrailingWhitespace: whiteSpace === \"pre\" || whiteSpace === \"pre-wrap\",\n wordBreak: toWordBreak(style),\n overflowWrap: toOverflowWrap(style),\n });\n countParagraph();\n const layout = paragraph.layout(width);\n\n // An empty paragraph has no lines, where CSS keeps one empty line box.\n const lines: ParagraphLine[] =\n layout.lines.length > 0\n ? layout.lines\n : [\n {\n left: 0,\n width: 0,\n // As Skia places a baseline: by half-leading in the line box.\n baseline: (layout.lineHeight + layout.ascent - layout.descent) / 2,\n startIndex: 0,\n endIndex: 0,\n hardBreak: true,\n },\n ];\n const toTextIndex = content.toTextIndex ?? ((index: number) => index);\n const segments: TextSegment[] = lines.map((line, i) => ({\n // A line that ends the text at a newline reports the newline as its text.\n text: text\n .slice(toTextIndex(line.startIndex), toTextIndex(line.endIndex))\n .replace(/\\n/g, \"\"),\n x: line.left,\n y: line.baseline,\n width: line.width,\n height: layout.lineHeight,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n color: style.color ?? \"black\",\n ascent: layout.ascent,\n textDecoration: style.textDecoration,\n letterSpacing,\n lineIndex: i,\n }));\n\n const emoji: PlacedEmoji[] = [];\n layout.placeholders.forEach((box, i) => {\n // A placeholder that line-clamp or an ellipsis cut off has no box.\n if (!box) return;\n emoji.push({\n grapheme: content.emoji[i]!,\n x: box.x,\n y: box.y,\n size: fontSize,\n baseline: lines[box.line]!.baseline,\n });\n });\n\n let height = lines.length * layout.lineHeight;\n if (lineHeight === undefined) {\n // Round auto line-height boxes up so Yoga's integer rounding never clips\n // a descender. Text of no font size, laid out at MIN_FONT_SIZE, has line\n // boxes of no height, as in CSS.\n const noFontSize = Number.isFinite(styledFontSize) && styledFontSize <= 0;\n height = noFontSize ? 0 : Math.ceil(height);\n }\n\n let paragraphOffsetY = 0;\n const textBoxTrim = style.textBoxTrim;\n if (textBoxTrim && textBoxTrim !== \"none\") {\n const trim = measureTrimMetrics(\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n layout.lineHeight,\n style.textBoxEdge ?? \"text\",\n layout.ascent,\n layout.descent,\n );\n if (textBoxTrim === \"trim-start\" || textBoxTrim === \"trim-both\") {\n for (const seg of segments) seg.y -= trim.overTrim;\n for (const e of emoji) {\n e.y -= trim.overTrim;\n e.baseline -= trim.overTrim;\n }\n height -= trim.overTrim;\n paragraphOffsetY = -trim.overTrim;\n }\n if (textBoxTrim === \"trim-end\" || textBoxTrim === \"trim-both\") {\n height -= trim.underTrim;\n }\n }\n\n return {\n segments,\n width: segments.reduce((w, s) => Math.max(w, s.width), 0),\n height,\n paragraph,\n paragraphOffsetY,\n emoji,\n };\n}\n","// This file contains code adapted from Satori (https://github.com/vercel/satori)\n// Licensed under the Mozilla Public License 2.0 (MPL-2.0)\n// See NOTICE.md in the package root for details.\n\n/**\n * Detect the primary script/language of a text string.\n * Used for font selection and line-breaking behavior.\n */\nexport function detectLanguageCode(text: string): string | undefined {\n for (const char of text) {\n const cp = char.codePointAt(0);\n if (cp === undefined) continue;\n\n // CJK Unified Ideographs\n if (cp >= 0x4e00 && cp <= 0x9fff) return \"zh\";\n // CJK Extension A\n if (cp >= 0x3400 && cp <= 0x4dbf) return \"zh\";\n // Hiragana\n if (cp >= 0x3040 && cp <= 0x309f) return \"ja\";\n // Katakana\n if (cp >= 0x30a0 && cp <= 0x30ff) return \"ja\";\n // Hangul Syllables\n if (cp >= 0xac00 && cp <= 0xd7af) return \"ko\";\n // Hangul Jamo\n if (cp >= 0x1100 && cp <= 0x11ff) return \"ko\";\n // Thai\n if (cp >= 0x0e00 && cp <= 0x0e7f) return \"th\";\n // Arabic\n if (cp >= 0x0600 && cp <= 0x06ff) return \"ar\";\n // Hebrew\n if (cp >= 0x0590 && cp <= 0x05ff) return \"he\";\n // Devanagari\n if (cp >= 0x0900 && cp <= 0x097f) return \"hi\";\n // Bengali\n if (cp >= 0x0980 && cp <= 0x09ff) return \"bn\";\n // Tamil\n if (cp >= 0x0b80 && cp <= 0x0bff) return \"ta\";\n // Telugu\n if (cp >= 0x0c00 && cp <= 0x0c7f) return \"te\";\n // Kannada\n if (cp >= 0x0c80 && cp <= 0x0cff) return \"kn\";\n // Malayalam\n if (cp >= 0x0d00 && cp <= 0x0d7f) return \"ml\";\n }\n\n return undefined;\n}\n\n// Which graphemes are drawn as emoji images, following UTS #51: every emoji\n// character, with or without U+FE0F, except the few that are text by default\n// in every font (©, ®, ™, digits, # and *). Browsers draw the other\n// text-default emoji characters in the BMP, such as ❤ or ☎, as monochrome\n// text through system font fallback; canvas has no such fallback, so an\n// image beats tofu.\n\n/**\n * A code point reserved for emoji that this runtime's Unicode doesn't know\n * yet: every emoji added since Unicode 9 is presented as one by default.\n */\nexport const UNASSIGNED_PICTOGRAPHIC = String.raw`(?=\\p{Cn})\\p{Extended_Pictographic}`;\n\n/** A character with an emoji form, \\p{Emoji} or \\p{Extended_Pictographic}. */\nconst EMOJI_CHAR = String.raw`[\\p{Emoji}\\p{Extended_Pictographic}]`;\n\n/**\n * A keycap base: a digit, # or *. On its own, even before U+FE0F, it's text,\n * as in Chrome; only a keycap sequence makes it an emoji.\n */\nconst KEYCAP_BASE = \"[0-9#*]\";\n\n/**\n * An emoji character that stays text on its own: a keycap base (digits, # and\n * *), text unless a keycap follows it, and ©, ® and ™, text unless U+FE0F\n * follows them.\n */\nconst TEXT_EMOJI_CHAR = String.raw`[0-9#*\\u00A9\\u00AE\\u2122]`;\n\n/** A tag sequence's tags, as in a subdivision flag such as 🏴󠁧󠁢󠁥󠁮󠁧󠁿. */\nconst TAGS = String.raw`[\\u{E0020}-\\u{E007E}]+\\u{E007F}`;\n\n/** An emoji element drawn as an emoji, also when it stands alone. */\nconst PRESENTED_EMOJI = [\n // Keycap: 1️⃣, and the unqualified 1⃣.\n String.raw`${KEYCAP_BASE}\\uFE0F?\\u20E3`,\n // Flag: a pair of regional indicators.\n String.raw`\\p{Regional_Indicator}{2}`,\n // Emoji presentation sequence (©️), modifier sequence (👍🏽, ☝🏽) or tag\n // sequence (🏴󠁧󠁢󠁥󠁮󠁧󠁿).\n String.raw`(?!${KEYCAP_BASE})${EMOJI_CHAR}(?:\\uFE0F|\\p{Emoji_Modifier}|${TAGS})`,\n // An emoji character on its own, emoji presentation by default (🌍, ⭐) or\n // text (❤, ☎, 🕵), but not one that stays text.\n String.raw`(?!${TEXT_EMOJI_CHAR})\\p{Emoji}`,\n UNASSIGNED_PICTOGRAPHIC,\n].join(\"|\");\n\n/**\n * An element of a ZWJ sequence: any emoji element, or a character with an\n * emoji form that isn't one on its own (the © in ©‍®), but no bare keycap\n * base.\n */\nconst ZWJ_ELEMENT = `(?:${PRESENTED_EMOJI}|(?!${KEYCAP_BASE})${EMOJI_CHAR})`;\n\nconst EMOJI_RE = new RegExp(\n `^(?:${PRESENTED_EMOJI}|${ZWJ_ELEMENT}(?:\\\\u200D${ZWJ_ELEMENT})+)$`,\n \"u\",\n);\n\n/**\n * Whether a grapheme cluster is an emoji, to draw as an image: an emoji\n * character with or without U+FE0F (©, ®, ™ only with it, and digits, # and\n * * only in a keycap), a keycap, a flag, a modifier or tag sequence, or a ZWJ sequence of emoji\n * (UTS #51). U+FE0E keeps an emoji character text. A ZWJ between anything\n * else (the joiner in Arabic or Indic text, or a lone one) doesn't make an\n * emoji, and neither do symbols with no emoji form, such as ✓ or ●.\n *\n * @param grapheme - One grapheme cluster, as `Intl.Segmenter` splits text\n */\nexport function isEmoji(grapheme: string): boolean {\n return EMOJI_RE.test(grapheme);\n}\n","import { createCanvas } from \"@effing/skia\";\nimport type { SKRSContext2D } from \"@effing/skia\";\n\n// Scratch canvas for measuring glyphs\nlet scratchCtx: SKRSContext2D | null = null;\n\nfunction getScratchCtx(): SKRSContext2D {\n if (!scratchCtx) {\n scratchCtx = createCanvas(1, 1).getContext(\"2d\");\n }\n return scratchCtx;\n}\n\nconst GENERIC_FAMILIES = new Set([\n \"serif\",\n \"sans-serif\",\n \"monospace\",\n \"cursive\",\n \"fantasy\",\n \"system-ui\",\n \"ui-serif\",\n \"ui-sans-serif\",\n \"ui-monospace\",\n \"ui-rounded\",\n \"math\",\n \"emoji\",\n \"fangsong\",\n]);\n\nfunction quoteFontFamily(family: string): string {\n if (!family || GENERIC_FAMILIES.has(family)) return family;\n return `\"${family}\"`;\n}\n\n/** A font-family list with every non-generic family name quoted. */\nexport function quoteFontFamilies(fontFamily: string): string {\n return fontFamily\n .split(\",\")\n .map((f) => quoteFontFamily(f.trim()))\n .join(\", \");\n}\n\n/**\n * Set font properties on a canvas context.\n */\nexport function setFont(\n ctx: SKRSContext2D,\n fontSize: number,\n fontFamily: string,\n fontWeight: number | string = 400,\n fontStyle: string = \"normal\",\n): void {\n ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${quoteFontFamilies(fontFamily)}`;\n}\n\n/**\n * Measure how many pixels to trim from the top (overTrim) and bottom\n * (underTrim) of a line box based on `text-box-edge` keywords.\n *\n * The trim amount is the difference between the full line-height half-leading\n * and the target metric for each edge.\n *\n * @param fontAscent - The font's hhea ascent in px\n * @param fontDescent - The font's hhea descent in px\n */\nexport function measureTrimMetrics(\n fontSize: number,\n fontFamily: string,\n fontWeight: number | string,\n fontStyle: string,\n lineHeight: number,\n edge: string,\n fontAscent: number,\n fontDescent: number,\n): { overTrim: number; underTrim: number } {\n const c = getScratchCtx();\n // Unhinted, as text is laid out and drawn.\n const measure = (text: string) => {\n setFont(c, fontSize, fontFamily, fontWeight, fontStyle);\n const previous = c.textRendering;\n c.textRendering = \"geometricPrecision\";\n try {\n return c.measureText(text);\n } finally {\n c.textRendering = previous;\n }\n };\n\n // Parse edge into over-edge and under-edge keywords\n const parts = edge.trim().split(/\\s+/);\n const overEdge = parts[0] ?? \"text\";\n const underEdge = parts.length > 1 ? parts[1]! : overEdge;\n\n // Resolve over-edge keyword → target ascent\n let targetAscent: number;\n switch (overEdge) {\n case \"cap\": {\n const capMetrics = measure(\"H\");\n targetAscent = capMetrics.actualBoundingBoxAscent ?? fontSize * 0.7;\n break;\n }\n case \"ex\": {\n const exMetrics = measure(\"x\");\n targetAscent = exMetrics.actualBoundingBoxAscent ?? fontSize * 0.5;\n break;\n }\n case \"ideographic\":\n case \"ideographic-ink\":\n case \"text\":\n default:\n targetAscent = fontAscent;\n break;\n }\n\n // Resolve under-edge keyword → target descent\n let targetDescent: number;\n switch (underEdge) {\n case \"alphabetic\":\n targetDescent = 0;\n break;\n case \"ideographic\":\n case \"ideographic-ink\":\n case \"text\":\n default:\n targetDescent = fontDescent;\n break;\n }\n\n const halfLeading = (lineHeight - (fontAscent + fontDescent)) / 2;\n const overTrim = halfLeading + (fontAscent - targetAscent);\n const underTrim = halfLeading + (fontDescent - targetDescent);\n\n return {\n overTrim: Math.max(0, overTrim),\n underTrim: Math.max(0, underTrim),\n };\n}\n","// White space processing, CSS Text 3 §4.1: the collapsing of phase I and the\n// removal of collapsible spaces at the start and end of a line of phase II,\n// for the `white-space` values that collapse spaces. Canvas lays out each run\n// of text between elements as a flex item of its own, as a flex container\n// has it, so the text of one text node is all there is to collapse across.\n\nimport type { ComputedStyle } from \"../style/compute.ts\";\n\ntype WhiteSpace = NonNullable<ComputedStyle[\"whiteSpace\"]>;\n\n/**\n * Whether `text` is nothing but white space: spaces, tabs, segment breaks,\n * form feeds and vertical tabs, the ASCII white space Chrome checks for. CSS\n * doesn't render a run of text in a flex container that is, under any\n * `white-space` (CSS Flexbox §4), as Chrome confirms.\n */\nexport function isWhiteSpaceOnly(text: string): boolean {\n return /^[ \\t\\n\\r\\f\\v]*$/.test(text);\n}\n\n/**\n * Process the white space of a text box's text as CSS does, before it's\n * transformed and laid out (CSS Text 3 §1.3). Under `normal`, `nowrap` and\n * `pre-line`:\n *\n * - a CRLF is one segment break, and a lone CR a space, as Chrome has them;\n * - tabs are spaces;\n * - the spaces around a segment break are removed;\n * - under `normal` and `nowrap`, a run of segment breaks is one space, where\n * `pre-line` keeps each one as a forced break;\n * - a run of spaces is one space;\n * - the spaces at the start and end of the text, which start and end a line,\n * are removed.\n *\n * The paragraph hangs the space at a line's soft wrap, as CSS does, so the\n * spaces at the start and end of the other lines take care of themselves.\n * Only ASCII white space collapses: a no-break space, say, is kept.\n *\n * `pre` and `pre-wrap` keep the spaces and tabs. They drop a lone CR, which\n * Chrome lays out with no width and no break opportunity, where the paragraph\n * would draw a missing glyph for it. Under every value, a CRLF is one segment\n * break, as in Chrome (the paragraph would keep the CR in the line too, and\n * draw it before an ellipsis), and:\n *\n * - A segment break at the very end of the text ends the last line, rather\n * than starting an empty one, as in Chrome. This relies on the paragraph\n * (`@effing/skia`'s `Paragraph`) starting an empty line after a hard break\n * that ends its text: only one final break is removed, so that \"a\\n\\n\"\n * keeps the one that gives it its second, empty line, as in Chrome.\n * - The paragraph breaks the line at a line or paragraph separator (U+2028,\n * U+2029), a form feed or a vertical tab, where Chrome doesn't. Chrome sets\n * a separator as a space that neither collapses nor hangs, with a break\n * opportunity after it: a no-break space and a zero-width space are that\n * to the paragraph. A form feed or a vertical tab is removed. Chrome draws\n * a form feed as nothing under `pre` and `pre-wrap`; otherwise, and for a\n * vertical tab under any value, it draws a fallback font's glyph for the\n * control character, which this leaves out.\n */\nexport function collapseWhiteSpace(\n text: string,\n whiteSpace: WhiteSpace | undefined,\n): string {\n let result = text.replace(/[\\v\\f]/g, \"\").replace(/\\r\\n/g, \"\\n\");\n if (whiteSpace === \"pre\" || whiteSpace === \"pre-wrap\") {\n result = result.replace(/\\r/g, \"\");\n } else if (/[\\t\\n\\r]| {2}|^ | $/.test(result)) {\n // Most text has nothing to collapse: no tab, newline, CR, or space that\n // could be leading, trailing or doubled.\n result = result.replace(/[\\t\\r]/g, \" \").replace(/ *\\n */g, \"\\n\");\n if (whiteSpace !== \"pre-line\") result = result.replace(/\\n+/g, \" \");\n result = result.replace(/ {2,}/g, \" \").replace(/^ | $/g, \"\");\n }\n return result.replace(FINAL_BREAK, \"\").replace(SEPARATORS, SEPARATOR_SPACE);\n}\n\nconst FINAL_BREAK = /\\n$/;\n\nconst SEPARATORS = /[\\u2028\\u2029]/g;\n\n/**\n * A space that neither collapses nor hangs (a no-break space), followed by a\n * break opportunity (a zero-width space).\n */\nconst SEPARATOR_SPACE = \"\\u00a0\\u200b\";\n","// This file contains code adapted from Satori (https://github.com/vercel/satori)\n// Licensed under the Mozilla Public License 2.0 (MPL-2.0)\n// See NOTICE.md in the package root for details.\n\nimport type { ComputedStyle } from \"../style/compute.ts\";\nimport { resolveUnit } from \"../style/compute.ts\";\nimport { layoutTextNative } from \"./native.ts\";\nimport type { NativeParagraph } from \"./native.ts\";\nimport { collapseWhiteSpace } from \"./white-space.ts\";\n\nexport type TextSegment = {\n text: string;\n x: number;\n y: number;\n width: number;\n height: number;\n fontSize: number;\n fontFamily: string;\n fontWeight: number | string;\n fontStyle: string;\n color: string;\n ascent: number;\n textDecoration?: string;\n letterSpacing: number;\n lineIndex: number;\n textStrokeWidth?: number;\n textStrokeColor?: string;\n};\n\nexport type TextLayoutResult = {\n segments: TextSegment[];\n width: number;\n height: number;\n /**\n * The paragraph to paint. The segments describe its lines, for\n * decorations.\n */\n paragraph: NativeParagraph;\n /** Vertical offset to paint `paragraph` at, relative to the text box. */\n paragraphOffsetY: number;\n /** Emoji to draw as images, in the inline boxes the paragraph left them. */\n emoji: PlacedEmoji[];\n};\n\n/** An emoji drawn as an image, at its inline box in the text box. */\nexport type PlacedEmoji = {\n /** The emoji's grapheme cluster. */\n grapheme: string;\n /** Top-left corner of its box. */\n x: number;\n y: number;\n /** The image's width and height. */\n size: number;\n /** Baseline of its line, to draw the emoji as text when there's no image. */\n baseline: number;\n};\n\n/**\n * Lay out text content into positioned lines, as one native paragraph that\n * Skia breaks, shapes and paints (see `./native.ts`). White space collapses\n * as `white-space` has it, before `text-transform` applies, as in CSS.\n *\n * @param text - The text to lay out\n * @param style - Computed style\n * @param maxWidth - Maximum width for wrapping\n * @param emojiEnabled - Whether emoji are drawn as images\n * @returns Text segments with positions and total dimensions, and the\n * paragraph to paint\n */\nexport function layoutText(\n text: string,\n style: ComputedStyle,\n maxWidth: number,\n emojiEnabled?: boolean,\n): TextLayoutResult {\n const fontSize = style.fontSize ?? 16;\n const result = layoutTextNative(\n applyTextTransform(collapseWhiteSpace(text, style.whiteSpace), style),\n style,\n maxWidth,\n resolveLineHeight(style.lineHeight, fontSize),\n emojiEnabled,\n );\n const textStrokeWidth = resolveTextStrokeWidth(style, fontSize);\n for (const seg of result.segments) {\n seg.textStrokeWidth = textStrokeWidth;\n seg.textStrokeColor = style.WebkitTextStrokeColor;\n }\n return result;\n}\n\nfunction resolveTextStrokeWidth(\n style: ComputedStyle,\n fontSize: number,\n): number | undefined {\n const raw = style.WebkitTextStrokeWidth;\n if (raw === undefined) return undefined;\n if (typeof raw === \"number\") return raw;\n const resolved = resolveUnit(String(raw), 0, 0, fontSize, 16);\n return typeof resolved === \"number\" ? resolved : undefined;\n}\n\nfunction applyTextTransform(text: string, style: ComputedStyle): string {\n if (style.textTransform === \"uppercase\") return text.toUpperCase();\n if (style.textTransform === \"lowercase\") return text.toLowerCase();\n if (style.textTransform === \"capitalize\") {\n return text.replace(/\\b\\w/g, (c) => c.toUpperCase());\n }\n return text;\n}\n\n/**\n * The line box height in px, or undefined for `normal`, which the paragraph\n * takes from the font. A height of 0 collapses the line boxes, as in CSS.\n */\nfunction resolveLineHeight(\n lineHeight: number | string | undefined,\n fontSize: number,\n): number | undefined {\n if (lineHeight === undefined || lineHeight === \"normal\") return undefined;\n let px: number;\n if (typeof lineHeight === \"number\") {\n // Already resolved to px in compute.ts if > 5, else multiplier\n px = lineHeight > 5 ? lineHeight : lineHeight * fontSize;\n } else {\n px = parseFloat(lineHeight);\n }\n // A negative line height is invalid in CSS, as is anything unparsable:\n // `normal` it is.\n return Number.isFinite(px) && px >= 0 ? px : undefined;\n}\n\n/**\n * Sizes a text node for Yoga, and lays its text out for drawing at the width\n * Yoga finally gives it.\n *\n * Yoga measures a node at whatever widths its algorithm needs, and may size\n * the node (or its ancestors) from a measurement at a width other than the\n * final one — a flex basis at the available width, say, before the node\n * shrinks. Laid out again at the final width, the text can then take more or\n * fewer lines than the box was sized for. `settle` catches that: it lays the\n * text out at the final width and, when Yoga saw a different height, pins\n * every later measurement to the height drawn, for the caller to compute the\n * layout again. The widths Yoga is given, which decide the line breaks, are\n * unchanged by the pin, so the next layout normally keeps the node's width.\n */\nexport class TextMeasure {\n /** Yoga's measurements by width (Infinity for unbounded). */\n private readonly sizes = new Map<number, { width: number; height: number }>();\n /** The heights reported to Yoga since the last `settle`. */\n private readonly reported = new Set<number>();\n private pinnedHeight: number | undefined;\n private settled: { width: number; result: TextLayoutResult } | undefined;\n private readonly measureStyle: ComputedStyle;\n\n constructor(\n private readonly text: string,\n private readonly style: ComputedStyle,\n private readonly emojiEnabled?: boolean,\n ) {\n // Strip textOverflow during measurement so ellipsis truncation doesn't\n // shrink the reported width below the Yoga constraint. The draw phase\n // still uses the original style (with textOverflow) for rendering.\n this.measureStyle = { ...style, textOverflow: \"clip\" };\n }\n\n /**\n * Measure the text for Yoga.\n *\n * @param maxWidth - The width available, Infinity for unbounded\n */\n measure(maxWidth: number): { width: number; height: number } {\n let size = this.sizes.get(maxWidth);\n if (!size) {\n const result = layoutText(\n this.text,\n this.measureStyle,\n maxWidth,\n this.emojiEnabled,\n );\n // When text wraps to multiple lines, report the constraint width (like\n // CSS block layout), so that the node is drawn at the width its lines\n // were broken at.\n const wrapped = result.segments.length > 1 && maxWidth < Infinity;\n size = {\n width: wrapped ? maxWidth : Math.min(result.width, maxWidth),\n height: result.height,\n };\n this.sizes.set(maxWidth, size);\n }\n const height = this.pinnedHeight ?? size.height;\n this.reported.add(height);\n return { width: size.width, height };\n }\n\n /**\n * Lay the text out for drawing at the node's final content width, and\n * check it against the heights Yoga was given since the last call.\n *\n * @param pin - Whether to pin later measurements to the drawn height when\n * they disagree\n * @returns Whether Yoga sized the node from another height. If `pin`, the\n * node's measurements are now pinned to the drawn height, and the caller\n * should mark the node dirty and compute the layout again.\n */\n settle(width: number, pin: boolean): boolean {\n if (this.settled?.width !== width) {\n this.settled = {\n width,\n result: layoutText(this.text, this.style, width, this.emojiEnabled),\n };\n }\n const { height } = this.settled.result;\n const agrees =\n this.reported.size === 0 ||\n (this.reported.size === 1 && this.reported.has(height));\n this.reported.clear();\n if (agrees) return false;\n if (pin) this.pinnedHeight = height;\n return true;\n }\n\n /**\n * Drop the pinned height, so that Yoga sees the measured heights again.\n *\n * @returns Whether there was a pin\n */\n unpin(): boolean {\n const pinned = this.pinnedHeight !== undefined;\n this.pinnedHeight = undefined;\n this.reported.clear();\n return pinned;\n }\n\n /** The text as laid out by the last `settle`. */\n get layout(): TextLayoutResult | undefined {\n return this.settled?.result;\n }\n}\n","import type { SKRSContext2D } from \"@effing/skia\";\n\n/**\n * Apply overflow:hidden clipping to a canvas context.\n * Creates a rectangular clip path with optional border-radius.\n */\nexport function applyClip(\n ctx: SKRSContext2D,\n x: number,\n y: number,\n width: number,\n height: number,\n borderRadius?: {\n topLeft: number;\n topRight: number;\n bottomRight: number;\n bottomLeft: number;\n },\n): void {\n ctx.beginPath();\n\n if (borderRadius && hasRadius(borderRadius)) {\n const { topLeft, topRight, bottomRight, bottomLeft } = borderRadius;\n roundedRect(\n ctx,\n x,\n y,\n width,\n height,\n topLeft,\n topRight,\n bottomRight,\n bottomLeft,\n );\n } else {\n ctx.rect(x, y, width, height);\n }\n\n ctx.clip();\n}\n\n/**\n * Draw a rounded rectangle path on the context.\n */\nexport function roundedRect(\n ctx: SKRSContext2D,\n x: number,\n y: number,\n w: number,\n h: number,\n tl: number,\n tr: number,\n br: number,\n bl: number,\n): void {\n const maxR = maxCornerRadius(w, h);\n tl = Math.min(tl, maxR);\n tr = Math.min(tr, maxR);\n br = Math.min(br, maxR);\n bl = Math.min(bl, maxR);\n\n ctx.moveTo(x + tl, y);\n ctx.lineTo(x + w - tr, y);\n if (tr > 0) ctx.arcTo(x + w, y, x + w, y + tr, tr);\n ctx.lineTo(x + w, y + h - br);\n if (br > 0) ctx.arcTo(x + w, y + h, x + w - br, y + h, br);\n ctx.lineTo(x + bl, y + h);\n if (bl > 0) ctx.arcTo(x, y + h, x, y + h - bl, bl);\n ctx.lineTo(x, y + tl);\n if (tl > 0) ctx.arcTo(x, y, x + tl, y, tl);\n ctx.closePath();\n}\n\n/**\n * The largest corner radius a `w` × `h` box is drawn with: every radius is\n * clamped to half the shorter side. Anything that needs to line up with the\n * element's painted corners (`clip-path` geometry boxes, overflow clips) must\n * apply the same clamp.\n */\nexport function maxCornerRadius(w: number, h: number): number {\n return Math.min(w, h) / 2;\n}\n\nexport function hasRadius(r: {\n topLeft: number;\n topRight: number;\n bottomRight: number;\n bottomLeft: number;\n}): boolean {\n return (\n r.topLeft > 0 || r.topRight > 0 || r.bottomRight > 0 || r.bottomLeft > 0\n );\n}\n","import { Path2D } from \"@effing/skia\";\nimport type { SKRSContext2D } from \"@effing/skia\";\n\nimport type { ComputedStyle } from \"../style/compute.ts\";\nimport { maxCornerRadius } from \"./clip.ts\";\nimport { getBorderRadiusFromStyle } from \"./rect.ts\";\nimport { parseCSSLength, resolveBoxValue } from \"./utils.ts\";\n\n/**\n * CSS `clip-path` support: basic shapes (`inset()`, `circle()`, `ellipse()`,\n * `polygon()`, `path()`, `rect()`, `xywh()`), the newer `shape()` function and\n * an optional geometry box (`border-box`, `padding-box`, `content-box`,\n * `margin-box`). Lengths other than `%` are already resolved to pixels by the\n * style pipeline; percentages resolve against the reference box here.\n *\n * `url(#id)` references and `calc()` are not supported — an unrecognised value\n * leaves the element unclipped, matching how a browser drops an invalid\n * declaration.\n */\n\nexport type FillRule = \"nonzero\" | \"evenodd\";\n\ntype Point = [number, number];\n\n/** Per-corner elliptical radii, in the order tl, tr, br, bl. */\nexport type CornerRadii = [Point, Point, Point, Point];\n\nexport type ReferenceBox = {\n x: number;\n y: number;\n width: number;\n height: number;\n};\n\n/**\n * A resolved clip shape in absolute canvas coordinates.\n */\nexport type ClipShape =\n | { kind: \"none\" }\n | {\n kind: \"rect\";\n x: number;\n y: number;\n width: number;\n height: number;\n radii: CornerRadii | null;\n }\n | { kind: \"circle\"; cx: number; cy: number; r: number }\n | { kind: \"ellipse\"; cx: number; cy: number; rx: number; ry: number }\n | { kind: \"polygon\"; points: Point[]; fillRule: FillRule }\n | { kind: \"path\"; d: string; dx: number; dy: number; fillRule: FillRule };\n\nconst GEOMETRY_BOXES = new Set([\n \"border-box\",\n \"padding-box\",\n \"content-box\",\n \"margin-box\",\n \"fill-box\",\n \"stroke-box\",\n \"view-box\",\n]);\n\nconst H_KEYWORDS = new Map<string, number>([\n [\"left\", 0],\n [\"x-start\", 0],\n [\"center\", 0.5],\n [\"right\", 1],\n [\"x-end\", 1],\n]);\n\nconst V_KEYWORDS = new Map<string, number>([\n [\"top\", 0],\n [\"y-start\", 0],\n [\"center\", 0.5],\n [\"bottom\", 1],\n [\"y-end\", 1],\n]);\n\nconst ARC_OPTIONS = new Set([\"of\", \"cw\", \"ccw\", \"large\", \"small\", \"rotate\"]);\n\n/**\n * Clip the context to the element's `clip-path`. Must be called after the\n * element's transform has been applied (clip-path lives in the element's own\n * coordinate space) and before anything of the element is painted — box-shadow\n * included, since clip-path clips the element's entire rendering.\n */\nexport function applyClipPath(\n ctx: SKRSContext2D,\n clipPath: string,\n style: ComputedStyle,\n x: number,\n y: number,\n width: number,\n height: number,\n): void {\n const shape = parseClipPath(clipPath, style, { x, y, width, height });\n if (!shape || shape.kind === \"none\") return;\n const path = clipShapeToPath(shape);\n if (path) ctx.clip(path, shapeFillRule(shape));\n}\n\nfunction shapeFillRule(shape: ClipShape): FillRule {\n return shape.kind === \"polygon\" || shape.kind === \"path\"\n ? shape.fillRule\n : \"nonzero\";\n}\n\n/**\n * Parse a `clip-path` value into a resolved shape in absolute coordinates.\n * `box` is the element's border box; `style` supplies the border, padding and\n * margin widths used for the other geometry boxes. Returns `null` for values\n * that can't be parsed.\n */\nexport function parseClipPath(\n value: string,\n style: ComputedStyle,\n box: ReferenceBox,\n): ClipShape | null {\n const trimmed = value.trim();\n if (trimmed === \"none\") return { kind: \"none\" };\n\n // Split into an optional shape function and an optional geometry box, in\n // either order: `circle(50%) padding-box` or `padding-box circle(50%)`.\n let fn: { name: string; args: string } | null = null;\n let geometryBox = \"border-box\";\n const fnMatch = trimmed.match(/^(.*?)([a-z]+)\\((.*)\\)(.*)$/s);\n let keywords: string[];\n if (fnMatch) {\n fn = { name: fnMatch[2]!, args: fnMatch[3]! };\n keywords = [fnMatch[1]!, fnMatch[4]!]\n .join(\" \")\n .split(/\\s+/)\n .filter(Boolean);\n } else {\n keywords = trimmed.split(/\\s+/).filter(Boolean);\n }\n for (const kw of keywords) {\n if (!GEOMETRY_BOXES.has(kw)) return null;\n geometryBox = kw;\n }\n if (!fn && keywords.length === 0) return null;\n\n const ref = resolveReferenceBox(geometryBox, style, box);\n const { width: w, height: h } = ref;\n\n if (!fn) {\n // A bare geometry box clips to that box, following the border radius\n // (reduced by the border/padding widths for the inner boxes).\n return {\n kind: \"rect\",\n x: ref.x,\n y: ref.y,\n width: w,\n height: h,\n radii: referenceBoxRadii(geometryBox, style, box, ref),\n };\n }\n\n switch (fn.name) {\n case \"inset\":\n return parseInset(fn.args, ref);\n case \"rect\":\n return parseRect(fn.args, ref);\n case \"xywh\":\n return parseXywh(fn.args, ref);\n case \"circle\":\n return parseCircle(fn.args, ref);\n case \"ellipse\":\n return parseEllipse(fn.args, ref);\n case \"polygon\":\n return parsePolygon(fn.args, ref);\n case \"path\":\n return parsePath(fn.args, ref);\n case \"shape\":\n return parseShape(fn.args, ref);\n default:\n return null;\n }\n}\n\n/**\n * Build a `Path2D` for a resolved clip shape. Returns `null` when the shape\n * is a `path()` whose data Skia cannot parse — treated like an invalid\n * declaration (the element is left unclipped) rather than a render failure.\n */\nexport function clipShapeToPath(shape: ClipShape): Path2D | null {\n const p = new Path2D();\n switch (shape.kind) {\n case \"none\":\n break;\n case \"rect\":\n if (shape.radii && shape.width > 0 && shape.height > 0) {\n roundedRectPath(\n p,\n shape.x,\n shape.y,\n shape.width,\n shape.height,\n shape.radii,\n );\n } else {\n p.rect(\n shape.x,\n shape.y,\n Math.max(0, shape.width),\n Math.max(0, shape.height),\n );\n }\n break;\n case \"circle\":\n if (shape.r > 0) p.arc(shape.cx, shape.cy, shape.r, 0, Math.PI * 2);\n break;\n case \"ellipse\":\n if (shape.rx > 0 && shape.ry > 0) {\n p.ellipse(shape.cx, shape.cy, shape.rx, shape.ry, 0, 0, Math.PI * 2);\n }\n break;\n case \"polygon\":\n if (shape.points.length >= 3) {\n const [first, ...rest] = shape.points;\n p.moveTo(first![0], first![1]);\n for (const [px, py] of rest) p.lineTo(px, py);\n p.closePath();\n }\n break;\n case \"path\": {\n let inner: Path2D;\n try {\n inner = new Path2D(shape.d);\n } catch {\n return null;\n }\n if (shape.dx === 0 && shape.dy === 0) return inner;\n p.addPath(inner, { a: 1, b: 0, c: 0, d: 1, e: shape.dx, f: shape.dy });\n break;\n }\n }\n return p;\n}\n\n// ---------------------------------------------------------------------------\n// Reference boxes\n// ---------------------------------------------------------------------------\n\nfunction resolveReferenceBox(\n geometryBox: string,\n style: ComputedStyle,\n box: ReferenceBox,\n): ReferenceBox {\n const { x, y, width, height } = box;\n switch (geometryBox) {\n case \"padding-box\": {\n const t = resolveBoxValue(style.borderTopWidth, width);\n const r = resolveBoxValue(style.borderRightWidth, width);\n const b = resolveBoxValue(style.borderBottomWidth, width);\n const l = resolveBoxValue(style.borderLeftWidth, width);\n return {\n x: x + l,\n y: y + t,\n width: width - l - r,\n height: height - t - b,\n };\n }\n case \"content-box\": {\n const t =\n resolveBoxValue(style.borderTopWidth, width) +\n resolveBoxValue(style.paddingTop, width);\n const r =\n resolveBoxValue(style.borderRightWidth, width) +\n resolveBoxValue(style.paddingRight, width);\n const b =\n resolveBoxValue(style.borderBottomWidth, width) +\n resolveBoxValue(style.paddingBottom, width);\n const l =\n resolveBoxValue(style.borderLeftWidth, width) +\n resolveBoxValue(style.paddingLeft, width);\n return {\n x: x + l,\n y: y + t,\n width: width - l - r,\n height: height - t - b,\n };\n }\n case \"margin-box\": {\n const t = marginValue(style.marginTop, width);\n const r = marginValue(style.marginRight, width);\n const b = marginValue(style.marginBottom, width);\n const l = marginValue(style.marginLeft, width);\n return {\n x: x - l,\n y: y - t,\n width: width + l + r,\n height: height + t + b,\n };\n }\n default:\n return box;\n }\n}\n\nfunction marginValue(v: unknown, referenceWidth: number): number {\n if (v === \"auto\") return 0;\n return resolveBoxValue(v, referenceWidth);\n}\n\n/**\n * Border radii of a geometry box: the element's border-radius for the border\n * box (and margin box, grown by the margin), reduced by the border and padding\n * widths for the inner boxes. Returns `null` when every corner is square.\n *\n * The base radii are clamped the way the element's own corners are painted\n * (see `maxCornerRadius`) so a bare `border-box` clip traces exactly the\n * painted rounded corner instead of a different arc.\n */\nfunction referenceBoxRadii(\n geometryBox: string,\n style: ComputedStyle,\n box: ReferenceBox,\n ref: ReferenceBox,\n): CornerRadii | null {\n const br = getBorderRadiusFromStyle(style, box.width, box.height);\n const maxR = maxCornerRadius(box.width, box.height);\n const base = [br.topLeft, br.topRight, br.bottomRight, br.bottomLeft].map(\n (r) => Math.min(Math.max(0, r), maxR),\n ) as [number, number, number, number];\n if (base.every((r) => r <= 0)) return null;\n\n // Horizontal / vertical insets from the border box to the reference box, per\n // corner: (left, top), (right, top), (right, bottom), (left, bottom).\n const left = ref.x - box.x;\n const top = ref.y - box.y;\n const right = box.x + box.width - (ref.x + ref.width);\n const bottom = box.y + box.height - (ref.y + ref.height);\n const insets: [Point, Point, Point, Point] = [\n [left, top],\n [right, top],\n [right, bottom],\n [left, bottom],\n ];\n\n const radii = base.map((r, i) => {\n const [ix, iy] = insets[i]!;\n return [adjustRadius(r, ix), adjustRadius(r, iy)] as Point;\n }) as CornerRadii;\n if (radii.every(([rx, ry]) => rx <= 0 || ry <= 0)) return null;\n return normalizeRadii(radii, ref.width, ref.height);\n}\n\n/**\n * Move a border radius inward by `inset` (CSS Backgrounds: the inner radius\n * is the outer one minus the border, floored at zero) or, for a negative\n * inset, outward (CSS Shapes `margin-box`: a square corner stays square, a\n * radius `r >= m` grows to `r + m`, and a smaller one is eased between the\n * two so the corner keeps its shape).\n */\nfunction adjustRadius(r: number, inset: number): number {\n if (inset >= 0) return Math.max(0, r - inset);\n if (r <= 0) return 0;\n const m = -inset;\n if (r >= m) return r + m;\n const ratio = r / m - 1;\n return r + m * (1 + ratio * ratio * ratio);\n}\n\n// ---------------------------------------------------------------------------\n// Basic shapes\n// ---------------------------------------------------------------------------\n\nfunction parseInset(args: string, ref: ReferenceBox): ClipShape | null {\n const [insetPart, roundPart] = splitRound(args);\n const values = tokenize(insetPart);\n if (values.length < 1 || values.length > 4) return null;\n const [t, r, b, l] = expandSides(values);\n const top = parseCSSLength(t, ref.height);\n const right = parseCSSLength(r, ref.width);\n const bottom = parseCSSLength(b, ref.height);\n const left = parseCSSLength(l, ref.width);\n if ([top, right, bottom, left].some(isNaN)) return null;\n return makeRect(\n ref.x + left,\n ref.y + top,\n ref.width - left - right,\n ref.height - top - bottom,\n roundPart,\n ref,\n );\n}\n\nfunction parseRect(args: string, ref: ReferenceBox): ClipShape | null {\n const [rectPart, roundPart] = splitRound(args);\n const values = tokenize(rectPart);\n if (values.length !== 4) return null;\n const [t, r, b, l] = values as [string, string, string, string];\n const top = t === \"auto\" ? 0 : parseCSSLength(t, ref.height);\n const right = r === \"auto\" ? ref.width : parseCSSLength(r, ref.width);\n const bottom = b === \"auto\" ? ref.height : parseCSSLength(b, ref.height);\n const left = l === \"auto\" ? 0 : parseCSSLength(l, ref.width);\n if ([top, right, bottom, left].some(isNaN)) return null;\n // Per spec, right/bottom are clamped so they never precede left/top.\n const x2 = Math.max(left, right);\n const y2 = Math.max(top, bottom);\n return makeRect(\n ref.x + left,\n ref.y + top,\n x2 - left,\n y2 - top,\n roundPart,\n ref,\n );\n}\n\nfunction parseXywh(args: string, ref: ReferenceBox): ClipShape | null {\n const [xywhPart, roundPart] = splitRound(args);\n const values = tokenize(xywhPart);\n if (values.length !== 4) return null;\n const [xs, ys, ws, hs] = values as [string, string, string, string];\n const x = parseCSSLength(xs, ref.width);\n const y = parseCSSLength(ys, ref.height);\n const w = parseCSSLength(ws, ref.width);\n const h = parseCSSLength(hs, ref.height);\n if ([x, y, w, h].some(isNaN)) return null;\n return makeRect(\n ref.x + x,\n ref.y + y,\n Math.max(0, w),\n Math.max(0, h),\n roundPart,\n ref,\n );\n}\n\n/**\n * Build a rect shape with optional `round` radii. Percentage radii resolve\n * against the reference box (CSS Shapes 1 §3), not the rectangle itself.\n */\nfunction makeRect(\n x: number,\n y: number,\n width: number,\n height: number,\n roundPart: string | undefined,\n ref: ReferenceBox,\n): ClipShape | null {\n const w = Math.max(0, width);\n const h = Math.max(0, height);\n let radii: CornerRadii | null = null;\n if (roundPart !== undefined) {\n const parsed = parseRadii(roundPart, ref.width, ref.height, w, h);\n if (parsed === undefined) return null;\n radii = parsed;\n }\n return { kind: \"rect\", x, y, width: w, height: h, radii };\n}\n\nfunction parseCircle(args: string, ref: ReferenceBox): ClipShape | null {\n const [radiusPart, posPart] = splitAt(args);\n const radiusTokens = tokenize(radiusPart);\n if (radiusTokens.length > 1) return null;\n const pos = resolvePosition(tokenize(posPart ?? \"\"), ref.width, ref.height);\n if (!pos) return null;\n const [cx, cy] = pos;\n const closest = Math.min(cx, cy, ref.width - cx, ref.height - cy);\n const farthest = Math.max(cx, cy, ref.width - cx, ref.height - cy);\n const percentBase = Math.hypot(ref.width, ref.height) / Math.SQRT2;\n const r = resolveRadius(radiusTokens[0], closest, farthest, percentBase);\n if (r === undefined) return null;\n return { kind: \"circle\", cx: ref.x + cx, cy: ref.y + cy, r: Math.max(0, r) };\n}\n\nfunction parseEllipse(args: string, ref: ReferenceBox): ClipShape | null {\n const [radiusPart, posPart] = splitAt(args);\n const radiusTokens = tokenize(radiusPart);\n if (radiusTokens.length !== 0 && radiusTokens.length !== 2) return null;\n const pos = resolvePosition(tokenize(posPart ?? \"\"), ref.width, ref.height);\n if (!pos) return null;\n const [cx, cy] = pos;\n const rx = resolveRadius(\n radiusTokens[0],\n Math.min(cx, ref.width - cx),\n Math.max(cx, ref.width - cx),\n ref.width,\n );\n const ry = resolveRadius(\n radiusTokens[1],\n Math.min(cy, ref.height - cy),\n Math.max(cy, ref.height - cy),\n ref.height,\n );\n if (rx === undefined || ry === undefined) return null;\n return {\n kind: \"ellipse\",\n cx: ref.x + cx,\n cy: ref.y + cy,\n rx: Math.max(0, rx),\n ry: Math.max(0, ry),\n };\n}\n\nfunction parsePolygon(args: string, ref: ReferenceBox): ClipShape | null {\n const parts = splitArgs(args);\n let fillRule: FillRule = \"nonzero\";\n const first = parts[0]?.trim();\n if (first === \"nonzero\" || first === \"evenodd\") {\n fillRule = first;\n parts.shift();\n }\n const points: Point[] = [];\n for (const part of parts) {\n const pair = tokenize(part);\n if (pair.length !== 2) return null;\n const px = parseCSSLength(pair[0]!, ref.width);\n const py = parseCSSLength(pair[1]!, ref.height);\n if (isNaN(px) || isNaN(py)) return null;\n points.push([ref.x + px, ref.y + py]);\n }\n if (points.length === 0) return null;\n return { kind: \"polygon\", points, fillRule };\n}\n\nfunction parsePath(args: string, ref: ReferenceBox): ClipShape | null {\n const parts = splitArgs(args);\n let fillRule: FillRule = \"nonzero\";\n const first = parts[0]?.trim();\n if (first === \"nonzero\" || first === \"evenodd\") {\n fillRule = first;\n parts.shift();\n }\n if (parts.length !== 1) return null;\n const d = unquote(parts[0]!.trim());\n if (!d) return null;\n return { kind: \"path\", d, dx: ref.x, dy: ref.y, fillRule };\n}\n\n// ---------------------------------------------------------------------------\n// shape()\n// ---------------------------------------------------------------------------\n\n/**\n * Parse the `shape()` function into SVG path data. Coordinates are resolved\n * against the reference box; the resulting path is positioned at the box\n * origin via `dx`/`dy`.\n *\n * Grammar (CSS Shapes 2): `shape([<fill-rule>]? from <x> <y>, <command>#)`\n * with commands `move`, `line`, `hline`, `vline`, `curve`, `smooth`, `arc`\n * and `close`, each using `to` (absolute) or `by` (relative to the current\n * point).\n */\nfunction parseShape(args: string, ref: ReferenceBox): ClipShape | null {\n const { width: w, height: h } = ref;\n const parts = splitArgs(args);\n const first = parts.shift()?.trim();\n if (!first) return null;\n\n const startMatch = first.match(/^(?:(nonzero|evenodd)\\s+)?from\\s+(.+)$/s);\n if (!startMatch) return null;\n const fillRule = (startMatch[1] ?? \"nonzero\") as FillRule;\n\n let current = resolvePoint(tokenize(startMatch[2]!), w, h);\n if (!current) return null;\n let subpathStart = current;\n let d = `M${fmtPoint(current)}`;\n\n for (const part of parts) {\n const tokens = tokenize(part);\n const command = tokens.shift();\n\n switch (command) {\n case \"close\": {\n if (tokens.length) return null;\n d += \" Z\";\n current = subpathStart;\n break;\n }\n case \"move\":\n case \"line\": {\n const end = resolveEndpoint(tokens, current, w, h);\n if (!end) return null;\n d += ` ${command === \"move\" ? \"M\" : \"L\"}${fmtPoint(end)}`;\n current = end;\n if (command === \"move\") subpathStart = end;\n break;\n }\n case \"hline\":\n case \"vline\": {\n const [mode, token, ...rest] = tokens;\n if ((mode !== \"to\" && mode !== \"by\") || !token || rest.length) {\n return null;\n }\n const axis = command === \"hline\" ? 0 : 1;\n const base = axis === 0 ? w : h;\n const keywords = axis === 0 ? H_KEYWORDS : V_KEYWORDS;\n const kw = keywords.get(token);\n const resolved =\n mode === \"to\" && kw !== undefined\n ? kw * base\n : parseCSSLength(token, base);\n if (isNaN(resolved)) return null;\n const next: Point = [current[0], current[1]];\n next[axis] = mode === \"by\" ? current[axis] + resolved : resolved;\n d += axis === 0 ? ` H${fmt(next[0])}` : ` V${fmt(next[1])}`;\n current = next;\n break;\n }\n case \"curve\":\n case \"smooth\": {\n const withIndex = tokens.indexOf(\"with\");\n const endTokens =\n withIndex === -1 ? tokens : tokens.slice(0, withIndex);\n const controlTokens =\n withIndex === -1 ? [] : tokens.slice(withIndex + 1);\n const mode = endTokens[0];\n const end = resolveEndpoint(endTokens, current, w, h);\n if (!end) return null;\n if (command === \"curve\" && withIndex === -1) return null;\n\n const controls: Point[] = [];\n for (const control of splitAtSlash(controlTokens)) {\n const point = resolveControlPoint(control, mode, current, end, w, h);\n if (!point) return null;\n controls.push(point);\n }\n\n if (command === \"curve\") {\n if (controls.length === 1) {\n d += ` Q${fmtPoint(controls[0]!)} ${fmtPoint(end)}`;\n } else if (controls.length === 2) {\n d += ` C${fmtPoint(controls[0]!)} ${fmtPoint(controls[1]!)} ${fmtPoint(end)}`;\n } else {\n return null;\n }\n } else if (controls.length === 0) {\n d += ` T${fmtPoint(end)}`;\n } else if (controls.length === 1) {\n d += ` S${fmtPoint(controls[0]!)} ${fmtPoint(end)}`;\n } else {\n return null;\n }\n current = end;\n break;\n }\n case \"arc\": {\n const optionIndex = tokens.findIndex((t) => ARC_OPTIONS.has(t));\n const endTokens =\n optionIndex === -1 ? tokens : tokens.slice(0, optionIndex);\n const options = optionIndex === -1 ? [] : tokens.slice(optionIndex);\n const end = resolveEndpoint(endTokens, current, w, h);\n if (!end) return null;\n\n let rx = 0;\n let ry = 0;\n let rotation = 0;\n let large = 0;\n let sweep = 0;\n for (let i = 0; i < options.length; i++) {\n const option = options[i]!;\n if (option === \"of\") {\n const r1 = options[++i];\n if (!r1) return null;\n const r2 = options[i + 1];\n const hasSecond = r2 !== undefined && !ARC_OPTIONS.has(r2);\n if (hasSecond) {\n i++;\n rx = parseCSSLength(r1, w);\n ry = parseCSSLength(r2!, h);\n } else {\n rx = ry = parseCSSLength(r1, Math.hypot(w, h) / Math.SQRT2);\n }\n if (isNaN(rx) || isNaN(ry)) return null;\n } else if (option === \"cw\" || option === \"ccw\") {\n sweep = option === \"cw\" ? 1 : 0;\n } else if (option === \"large\" || option === \"small\") {\n large = option === \"large\" ? 1 : 0;\n } else if (option === \"rotate\") {\n const angle = options[++i];\n if (!angle) return null;\n rotation = parseAngleDegrees(angle);\n if (isNaN(rotation)) return null;\n } else {\n return null;\n }\n }\n d += ` A${fmt(Math.abs(rx))} ${fmt(Math.abs(ry))} ${fmt(rotation)} ${large} ${sweep} ${fmtPoint(end)}`;\n current = end;\n break;\n }\n default:\n return null;\n }\n }\n\n return { kind: \"path\", d, dx: ref.x, dy: ref.y, fillRule };\n}\n\nfunction resolveEndpoint(\n tokens: string[],\n current: Point,\n w: number,\n h: number,\n): Point | null {\n const mode = tokens[0];\n if (mode !== \"to\" && mode !== \"by\") return null;\n const point = resolvePoint(tokens.slice(1), w, h);\n if (!point) return null;\n return mode === \"by\" ? [current[0] + point[0], current[1] + point[1]] : point;\n}\n\n/**\n * A control point: `<x> <y> [from start | end | origin]?`. Without `from`,\n * `by` commands measure from the segment start and `to` commands from the\n * reference box origin.\n */\nfunction resolveControlPoint(\n tokens: string[],\n mode: string | undefined,\n start: Point,\n end: Point,\n w: number,\n h: number,\n): Point | null {\n let origin: \"start\" | \"end\" | \"origin\" = mode === \"by\" ? \"start\" : \"origin\";\n let coords = tokens;\n const fromIndex = tokens.indexOf(\"from\");\n if (fromIndex !== -1) {\n const ref = tokens[fromIndex + 1];\n if (\n (ref !== \"start\" && ref !== \"end\" && ref !== \"origin\") ||\n tokens.length !== fromIndex + 2\n ) {\n return null;\n }\n origin = ref;\n coords = tokens.slice(0, fromIndex);\n }\n const point = resolvePoint(coords, w, h);\n if (!point) return null;\n const base: Point =\n origin === \"start\" ? start : origin === \"end\" ? end : [0, 0];\n return [base[0] + point[0], base[1] + point[1]];\n}\n\n/** Resolve a `<coordinate-pair>` (lengths, percentages or position keywords). */\nfunction resolvePoint(tokens: string[], w: number, h: number): Point | null {\n if (tokens.length !== 2) return null;\n const x = resolveAxis(tokens[0]!, w, H_KEYWORDS);\n const y = resolveAxis(tokens[1]!, h, V_KEYWORDS);\n if (isNaN(x) || isNaN(y)) return null;\n return [x, y];\n}\n\n// ---------------------------------------------------------------------------\n// Shared helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve a CSS `<position>` (as used after `at`) to a point relative to the\n * reference box. Defaults to the center.\n */\nfunction resolvePosition(tokens: string[], w: number, h: number): Point | null {\n if (tokens.length === 0) return [w / 2, h / 2];\n\n if (tokens.length === 1) {\n const t = tokens[0]!;\n if (V_KEYWORDS.has(t) && !H_KEYWORDS.has(t)) {\n return [w / 2, V_KEYWORDS.get(t)! * h];\n }\n const x = resolveAxis(t, w, H_KEYWORDS);\n return isNaN(x) ? null : [x, h / 2];\n }\n\n if (tokens.length === 2) {\n let [a, b] = tokens as [string, string];\n // Two keywords may come in either order (\"top left\" == \"left top\"); with\n // a length in the pair the order is fixed, so \"top 30px\" is invalid and\n // falls through to the NaN check below.\n const bothKeywords =\n (H_KEYWORDS.has(a) || V_KEYWORDS.has(a)) &&\n (H_KEYWORDS.has(b) || V_KEYWORDS.has(b));\n if (\n bothKeywords &&\n ((V_KEYWORDS.has(a) && !H_KEYWORDS.has(a)) ||\n (H_KEYWORDS.has(b) && !V_KEYWORDS.has(b)))\n ) {\n [a, b] = [b, a];\n }\n const x = resolveAxis(a, w, H_KEYWORDS);\n const y = resolveAxis(b, h, V_KEYWORDS);\n return isNaN(x) || isNaN(y) ? null : [x, y];\n }\n\n // 3–4 tokens: edge keywords with optional offsets, e.g. \"right 10px bottom 20px\".\n let x = w / 2;\n let y = h / 2;\n for (let i = 0; i < tokens.length; i++) {\n const t = tokens[i]!;\n const next = tokens[i + 1];\n const hasOffset =\n next !== undefined && !H_KEYWORDS.has(next) && !V_KEYWORDS.has(next);\n if (t === \"left\" || t === \"right\") {\n const off = hasOffset ? parseCSSLength(next!, w) : 0;\n if (isNaN(off)) return null;\n x = t === \"left\" ? off : w - off;\n } else if (t === \"top\" || t === \"bottom\") {\n const off = hasOffset ? parseCSSLength(next!, h) : 0;\n if (isNaN(off)) return null;\n y = t === \"top\" ? off : h - off;\n } else if (t !== \"center\") {\n return null;\n }\n if (hasOffset) i++;\n }\n return [x, y];\n}\n\nfunction resolveAxis(\n token: string,\n size: number,\n keywords: Map<string, number>,\n): number {\n const kw = keywords.get(token);\n if (kw !== undefined) return kw * size;\n return parseCSSLength(token, size);\n}\n\nfunction resolveRadius(\n token: string | undefined,\n closestSide: number,\n farthestSide: number,\n percentBase: number,\n): number | undefined {\n if (token === undefined || token === \"closest-side\") return closestSide;\n if (token === \"farthest-side\") return farthestSide;\n const r = parseCSSLength(token, percentBase);\n return isNaN(r) ? undefined : r;\n}\n\n/**\n * Parse `border-radius`-style radii (`r1 r2 r3 r4 / v1 v2 v3 v4`) into\n * per-corner elliptical radii. Percentages resolve against `refW` × `refH`;\n * the result is scaled down per the CSS overlap rule for a `w` × `h` box.\n * Returns `undefined` for unparsable input and `null` when all corners are\n * square.\n */\nfunction parseRadii(\n value: string,\n refW: number,\n refH: number,\n w: number,\n h: number,\n): CornerRadii | null | undefined {\n const [hPart, vPart] = value.split(\"/\");\n const hTokens = tokenize(hPart ?? \"\");\n const vTokens = vPart === undefined ? hTokens : tokenize(vPart);\n if (\n hTokens.length < 1 ||\n hTokens.length > 4 ||\n vTokens.length < 1 ||\n vTokens.length > 4\n ) {\n return undefined;\n }\n const hs = expandSides(hTokens).map((t) => parseCSSLength(t, refW));\n const vs = expandSides(vTokens).map((t) => parseCSSLength(t, refH));\n if ([...hs, ...vs].some(isNaN)) return undefined;\n const radii = hs.map((rx, i) => [\n Math.max(0, rx),\n Math.max(0, vs[i]!),\n ]) as CornerRadii;\n if (radii.every(([rx, ry]) => rx <= 0 || ry <= 0)) return null;\n return normalizeRadii(radii, w, h);\n}\n\n/**\n * CSS border-radius overlap rule: if adjacent radii along any side sum to more\n * than that side's length, scale every radius by the same factor.\n */\nfunction normalizeRadii(radii: CornerRadii, w: number, h: number): CornerRadii {\n const [tl, tr, br, bl] = radii;\n let f = 1;\n const consider = (sum: number, length: number) => {\n if (sum > 0 && length / sum < f) f = length / sum;\n };\n consider(tl[0] + tr[0], w);\n consider(bl[0] + br[0], w);\n consider(tl[1] + bl[1], h);\n consider(tr[1] + br[1], h);\n if (f >= 1) return radii;\n return radii.map(([rx, ry]) => [rx * f, ry * f]) as CornerRadii;\n}\n\n/**\n * Append a rounded rectangle with per-corner elliptical radii to a path.\n */\nfunction roundedRectPath(\n p: Path2D,\n x: number,\n y: number,\n w: number,\n h: number,\n radii: CornerRadii,\n): void {\n const [tl, tr, br, bl] = radii;\n const round = (r: Point) => r[0] > 0 && r[1] > 0;\n const HALF = Math.PI / 2;\n\n p.moveTo(x + (round(tl) ? tl[0] : 0), y);\n p.lineTo(x + w - (round(tr) ? tr[0] : 0), y);\n if (round(tr)) {\n p.ellipse(x + w - tr[0], y + tr[1], tr[0], tr[1], 0, -HALF, 0);\n }\n p.lineTo(x + w, y + h - (round(br) ? br[1] : 0));\n if (round(br)) {\n p.ellipse(x + w - br[0], y + h - br[1], br[0], br[1], 0, 0, HALF);\n }\n p.lineTo(x + (round(bl) ? bl[0] : 0), y + h);\n if (round(bl)) {\n p.ellipse(x + bl[0], y + h - bl[1], bl[0], bl[1], 0, HALF, Math.PI);\n }\n p.lineTo(x, y + (round(tl) ? tl[1] : 0));\n if (round(tl)) {\n p.ellipse(x + tl[0], y + tl[1], tl[0], tl[1], 0, Math.PI, 3 * HALF);\n }\n p.closePath();\n}\n\nfunction expandSides(values: string[]): [string, string, string, string] {\n const [a, b, c, d] = values;\n switch (values.length) {\n case 1:\n return [a!, a!, a!, a!];\n case 2:\n return [a!, b!, a!, b!];\n case 3:\n return [a!, b!, c!, b!];\n default:\n return [a!, b!, c!, d!];\n }\n}\n\n/** Split `... round <radii>` into the shape part and the optional radii part. */\nfunction splitRound(args: string): [string, string | undefined] {\n const m = args.match(/^(.*?)\\bround\\b(.*)$/s);\n if (!m) return [args, undefined];\n return [m[1]!, m[2]!];\n}\n\n/** Split `<radius> at <position>` into the radius part and the position part. */\nfunction splitAt(args: string): [string, string | undefined] {\n const m = args.match(/^(.*?)\\bat\\b(.*)$/s);\n if (!m) return [args, undefined];\n return [m[1]!, m[2]!];\n}\n\n/** Split on top-level commas, respecting parentheses and quoted strings. */\nfunction splitArgs(content: string): string[] {\n const parts: string[] = [];\n let current = \"\";\n let depth = 0;\n let quote: string | null = null;\n for (const char of content) {\n if (quote) {\n if (char === quote) quote = null;\n current += char;\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n current += char;\n continue;\n }\n if (char === \"(\") depth++;\n if (char === \")\") depth--;\n if (char === \",\" && depth === 0) {\n parts.push(current);\n current = \"\";\n } else {\n current += char;\n }\n }\n if (current.trim()) parts.push(current);\n return parts;\n}\n\nfunction splitAtSlash(tokens: string[]): string[][] {\n if (tokens.length === 0) return [];\n const slash = tokens.indexOf(\"/\");\n return slash === -1\n ? [tokens]\n : [tokens.slice(0, slash), tokens.slice(slash + 1)];\n}\n\nfunction tokenize(value: string): string[] {\n return value.trim().replace(/\\//g, \" / \").split(/\\s+/).filter(Boolean);\n}\n\nfunction unquote(s: string): string {\n if (\n s.length >= 2 &&\n ((s.startsWith('\"') && s.endsWith('\"')) ||\n (s.startsWith(\"'\") && s.endsWith(\"'\")))\n ) {\n return s.slice(1, -1);\n }\n return s;\n}\n\nfunction parseAngleDegrees(value: string): number {\n const n = parseFloat(value);\n if (isNaN(n)) return NaN;\n if (value.endsWith(\"deg\")) return n;\n if (value.endsWith(\"grad\")) return n * 0.9;\n if (value.endsWith(\"rad\")) return (n * 180) / Math.PI;\n if (value.endsWith(\"turn\")) return n * 360;\n return n;\n}\n\nfunction fmt(n: number): string {\n return String(Math.round(n * 1000) / 1000);\n}\n\nfunction fmtPoint(p: Point): string {\n return `${fmt(p[0])} ${fmt(p[1])}`;\n}\n","import type { SKRSContext2D } from \"@effing/skia\";\n\nimport type { ComputedStyle } from \"../style/compute.ts\";\nimport { hasRadius, roundedRect } from \"./clip.ts\";\nimport { parseCSSLength, toNumber, resolveBoxValue } from \"./utils.ts\";\n\n/**\n * Draw the background, borders, and box-shadow for a rectangular element.\n */\nexport function drawRect(\n ctx: SKRSContext2D,\n x: number,\n y: number,\n width: number,\n height: number,\n style: ComputedStyle,\n): void {\n const borderRadius = getBorderRadiusFromStyle(style, width, height);\n const hasRoundedCorners = hasRadius(borderRadius);\n\n // Background\n if (style.backgroundColor) {\n ctx.fillStyle = style.backgroundColor;\n\n if (hasRoundedCorners) {\n ctx.beginPath();\n roundedRect(\n ctx,\n x,\n y,\n width,\n height,\n borderRadius.topLeft,\n borderRadius.topRight,\n borderRadius.bottomRight,\n borderRadius.bottomLeft,\n );\n ctx.fill();\n } else {\n ctx.fillRect(x, y, width, height);\n }\n }\n\n // Borders\n drawBorders(ctx, x, y, width, height, style, borderRadius);\n}\n\nfunction resolveRadius(v: unknown, width: number, height: number): number {\n if (typeof v === \"string\") return parseCSSLength(v, Math.min(width, height));\n return toNumber(v);\n}\n\nexport function getBorderRadiusFromStyle(\n style: ComputedStyle,\n width: number,\n height: number,\n) {\n return {\n topLeft: resolveRadius(style.borderTopLeftRadius, width, height),\n topRight: resolveRadius(style.borderTopRightRadius, width, height),\n bottomRight: resolveRadius(style.borderBottomRightRadius, width, height),\n bottomLeft: resolveRadius(style.borderBottomLeftRadius, width, height),\n };\n}\n\nfunction drawBorders(\n ctx: SKRSContext2D,\n x: number,\n y: number,\n width: number,\n height: number,\n style: ComputedStyle,\n borderRadius: ReturnType<typeof getBorderRadiusFromStyle>,\n): void {\n const hasRoundedCorners = hasRadius(borderRadius);\n\n // If all borders are the same, draw as a single stroke\n const tw = resolveBoxValue(style.borderTopWidth, width);\n const rw = resolveBoxValue(style.borderRightWidth, width);\n const bw = resolveBoxValue(style.borderBottomWidth, width);\n const lw = resolveBoxValue(style.borderLeftWidth, width);\n\n if (tw === 0 && rw === 0 && bw === 0 && lw === 0) return;\n\n const allSameWidth = tw === rw && rw === bw && bw === lw && tw > 0;\n const tc = style.borderTopColor ?? \"black\";\n const rc = style.borderRightColor ?? \"black\";\n const bc = style.borderBottomColor ?? \"black\";\n const lc = style.borderLeftColor ?? \"black\";\n const allSameColor = tc === rc && rc === bc && bc === lc;\n\n if (allSameWidth && allSameColor) {\n ctx.strokeStyle = tc;\n ctx.lineWidth = tw;\n\n if (hasRoundedCorners) {\n ctx.beginPath();\n const half = tw / 2;\n roundedRect(\n ctx,\n x + half,\n y + half,\n width - tw,\n height - tw,\n Math.max(0, borderRadius.topLeft - half),\n Math.max(0, borderRadius.topRight - half),\n Math.max(0, borderRadius.bottomRight - half),\n Math.max(0, borderRadius.bottomLeft - half),\n );\n ctx.stroke();\n } else {\n ctx.strokeRect(x + tw / 2, y + tw / 2, width - tw, height - tw);\n }\n return;\n }\n\n // Draw individual borders\n if (hasRoundedCorners) {\n const maxR = Math.min(width, height) / 2;\n const tl = Math.min(borderRadius.topLeft, maxR);\n const tr = Math.min(borderRadius.topRight, maxR);\n const br = Math.min(borderRadius.bottomRight, maxR);\n const bl = Math.min(borderRadius.bottomLeft, maxR);\n\n const top = y + tw / 2;\n const right = x + width - rw / 2;\n const bottom = y + height - bw / 2;\n const left = x + lw / 2;\n\n const eTL = Math.max(0, tl - Math.max(tw, lw) / 2);\n const eTR = Math.max(0, tr - Math.max(tw, rw) / 2);\n const eBR = Math.max(0, br - Math.max(bw, rw) / 2);\n const eBL = Math.max(0, bl - Math.max(bw, lw) / 2);\n\n // Each side owns its end corner (in drawing direction) and only draws the\n // start corner arc when the adjacent owner side is not visible (width 0).\n // This prevents double-stroking of corner arcs which causes AA artifacts.\n\n // Top side (L → R): borrows TL, owns TR\n if (tw > 0) {\n ctx.strokeStyle = tc;\n ctx.lineWidth = tw;\n ctx.beginPath();\n if (eTL > 0 && lw === 0) {\n ctx.moveTo(left, top + eTL);\n ctx.arcTo(left, top, left + eTL, top, eTL);\n } else if (eTL > 0) {\n ctx.moveTo(left + eTL, top);\n } else {\n ctx.moveTo(x, top);\n }\n if (eTR > 0) {\n ctx.lineTo(right - eTR, top);\n ctx.arcTo(right, top, right, top + eTR, eTR);\n } else {\n ctx.lineTo(x + width, top);\n }\n ctx.stroke();\n }\n\n // Right side (T → B): borrows TR, owns BR\n if (rw > 0) {\n ctx.strokeStyle = rc;\n ctx.lineWidth = rw;\n ctx.beginPath();\n if (eTR > 0 && tw === 0) {\n ctx.moveTo(right - eTR, top);\n ctx.arcTo(right, top, right, top + eTR, eTR);\n } else if (eTR > 0) {\n ctx.moveTo(right, top + eTR);\n } else {\n ctx.moveTo(right, y);\n }\n if (eBR > 0) {\n ctx.lineTo(right, bottom - eBR);\n ctx.arcTo(right, bottom, right - eBR, bottom, eBR);\n } else {\n ctx.lineTo(right, y + height);\n }\n ctx.stroke();\n }\n\n // Bottom side (R → L): borrows BR, owns BL\n if (bw > 0) {\n ctx.strokeStyle = bc;\n ctx.lineWidth = bw;\n ctx.beginPath();\n if (eBR > 0 && rw === 0) {\n ctx.moveTo(right, bottom - eBR);\n ctx.arcTo(right, bottom, right - eBR, bottom, eBR);\n } else if (eBR > 0) {\n ctx.moveTo(right - eBR, bottom);\n } else {\n ctx.moveTo(x + width, bottom);\n }\n if (eBL > 0) {\n ctx.lineTo(left + eBL, bottom);\n ctx.arcTo(left, bottom, left, bottom - eBL, eBL);\n } else {\n ctx.lineTo(x, bottom);\n }\n ctx.stroke();\n }\n\n // Left side (B → T): borrows BL, owns TL\n if (lw > 0) {\n ctx.strokeStyle = lc;\n ctx.lineWidth = lw;\n ctx.beginPath();\n if (eBL > 0 && bw === 0) {\n ctx.moveTo(left + eBL, bottom);\n ctx.arcTo(left, bottom, left, bottom - eBL, eBL);\n } else if (eBL > 0) {\n ctx.moveTo(left, bottom - eBL);\n } else {\n ctx.moveTo(left, y + height);\n }\n if (eTL > 0) {\n ctx.lineTo(left, top + eTL);\n ctx.arcTo(left, top, left + eTL, top, eTL);\n } else {\n ctx.lineTo(left, y);\n }\n ctx.stroke();\n }\n } else {\n if (tw > 0) {\n ctx.strokeStyle = tc;\n ctx.lineWidth = tw;\n ctx.beginPath();\n ctx.moveTo(x, y + tw / 2);\n ctx.lineTo(x + width, y + tw / 2);\n ctx.stroke();\n }\n if (rw > 0) {\n ctx.strokeStyle = rc;\n ctx.lineWidth = rw;\n ctx.beginPath();\n ctx.moveTo(x + width - rw / 2, y);\n ctx.lineTo(x + width - rw / 2, y + height);\n ctx.stroke();\n }\n if (bw > 0) {\n ctx.strokeStyle = bc;\n ctx.lineWidth = bw;\n ctx.beginPath();\n ctx.moveTo(x, y + height - bw / 2);\n ctx.lineTo(x + width, y + height - bw / 2);\n ctx.stroke();\n }\n if (lw > 0) {\n ctx.strokeStyle = lc;\n ctx.lineWidth = lw;\n ctx.beginPath();\n ctx.moveTo(x + lw / 2, y);\n ctx.lineTo(x + lw / 2, y + height);\n ctx.stroke();\n }\n }\n}\n\n// Parse simple box-shadow: offsetX offsetY blur spread? color\nconst BOX_SHADOW_RE =\n /(-?\\d+(?:\\.\\d+)?)\\s*(?:px)?\\s+(-?\\d+(?:\\.\\d+)?)\\s*(?:px)?\\s+(-?\\d+(?:\\.\\d+)?)\\s*(?:px)?(?:\\s+(-?\\d+(?:\\.\\d+)?)\\s*(?:px)?)?\\s+(.*)/;\n\nexport function drawBoxShadow(\n ctx: SKRSContext2D,\n x: number,\n y: number,\n width: number,\n height: number,\n boxShadow: string,\n borderRadius: ReturnType<typeof getBorderRadiusFromStyle>,\n): void {\n const parts = boxShadow.match(BOX_SHADOW_RE);\n if (!parts) return;\n\n const offsetX = parseFloat(parts[1]!);\n const offsetY = parseFloat(parts[2]!);\n const blur = parseFloat(parts[3]!);\n const color = parts[5]!.trim();\n\n const radii = [\n borderRadius.topLeft,\n borderRadius.topRight,\n borderRadius.bottomRight,\n borderRadius.bottomLeft,\n ];\n\n // Clip to area OUTSIDE the element so shadow renders but inner fill is hidden\n const margin = blur * 2 + Math.abs(offsetX) + Math.abs(offsetY);\n ctx.save();\n ctx.beginPath();\n ctx.rect(x - margin, y - margin, width + margin * 2, height + margin * 2);\n ctx.roundRect(x, y, width, height, radii);\n ctx.clip(\"evenodd\");\n\n // Use CSS filter blur (sigma = blur/2) instead of the canvas shadow API\n // because it matches SVG feGaussianBlur (used by satori) much more closely.\n ctx.filter = `blur(${blur / 2}px)`;\n ctx.translate(offsetX, offsetY);\n ctx.fillStyle = color;\n ctx.beginPath();\n ctx.roundRect(x, y, width, height, radii);\n ctx.fill();\n ctx.restore();\n}\n","import type { SKRSContext2D } from \"@effing/skia\";\n\n/**\n * Parse and create a canvas gradient from a CSS gradient string.\n * Supports linear-gradient and radial-gradient.\n *\n * @returns A CanvasGradient or null if parsing fails\n */\nexport function createGradientFromCSS(\n ctx: SKRSContext2D,\n cssGradient: string,\n x: number,\n y: number,\n width: number,\n height: number,\n): CanvasGradient | null {\n const trimmed = cssGradient.trim();\n\n if (trimmed.startsWith(\"linear-gradient\")) {\n return parseLinearGradient(ctx, trimmed, x, y, width, height);\n }\n\n if (trimmed.startsWith(\"radial-gradient\")) {\n return parseRadialGradient(ctx, trimmed, x, y, width, height);\n }\n\n return null;\n}\n\nfunction parseLinearGradient(\n ctx: SKRSContext2D,\n css: string,\n x: number,\n y: number,\n width: number,\n height: number,\n): CanvasGradient | null {\n // Extract content between parentheses\n const match = css.match(/linear-gradient\\((.*)\\)/s);\n if (!match) return null;\n\n const content = match[1]!.trim();\n const parts = splitGradientArgs(content);\n\n let angle = 180; // default: to bottom\n let colorStartIdx = 0;\n\n // Parse direction\n const first = parts[0]?.trim();\n if (first) {\n if (first.startsWith(\"to \")) {\n angle = directionToAngle(first);\n colorStartIdx = 1;\n } else if (first.endsWith(\"deg\")) {\n angle = parseFloat(first);\n colorStartIdx = 1;\n } else if (first.endsWith(\"turn\")) {\n angle = parseFloat(first) * 360;\n colorStartIdx = 1;\n }\n }\n\n // Calculate gradient line endpoints\n const rad = ((angle - 90) * Math.PI) / 180;\n const cx = x + width / 2;\n const cy = y + height / 2;\n const halfDiag =\n Math.abs(width * Math.cos(rad)) / 2 + Math.abs(height * Math.sin(rad)) / 2;\n\n const x0 = cx - halfDiag * Math.cos(rad);\n const y0 = cy - halfDiag * Math.sin(rad);\n const x1 = cx + halfDiag * Math.cos(rad);\n const y1 = cy + halfDiag * Math.sin(rad);\n\n const gradient = ctx.createLinearGradient(x0, y0, x1, y1);\n\n // Parse color stops\n const stops = parts.slice(colorStartIdx);\n addColorStops(gradient, stops);\n\n return gradient;\n}\n\nfunction parseRadialGradient(\n ctx: SKRSContext2D,\n css: string,\n x: number,\n y: number,\n width: number,\n height: number,\n): CanvasGradient | null {\n const match = css.match(/radial-gradient\\((.*)\\)/s);\n if (!match) return null;\n\n const content = match[1]!.trim();\n const parts = splitGradientArgs(content);\n\n const cx = x + width / 2;\n const cy = y + height / 2;\n const radius = Math.max(width, height) / 2;\n\n const gradient = ctx.createRadialGradient(cx, cy, 0, cx, cy, radius);\n\n // Simple parsing: skip shape/size/position, just get color stops\n let colorStartIdx = 0;\n const first = parts[0]?.trim() ?? \"\";\n if (\n first.startsWith(\"circle\") ||\n first.startsWith(\"ellipse\") ||\n first.startsWith(\"closest\") ||\n first.startsWith(\"farthest\")\n ) {\n colorStartIdx = 1;\n }\n\n addColorStops(gradient, parts.slice(colorStartIdx));\n\n return gradient;\n}\n\nfunction addColorStops(gradient: CanvasGradient, stops: string[]): void {\n if (stops.length === 0) return;\n\n for (let i = 0; i < stops.length; i++) {\n const stop = stops[i]!.trim();\n const percentMatch = stop.match(/^(.+?)\\s+(\\d+(?:\\.\\d+)?%?)$/);\n\n if (percentMatch) {\n const color = percentMatch[1]!;\n const pos = percentMatch[2]!;\n const offset = pos.endsWith(\"%\")\n ? parseFloat(pos) / 100\n : parseFloat(pos);\n gradient.addColorStop(Math.max(0, Math.min(1, offset)), color);\n } else {\n // Auto-distribute\n const offset = stops.length === 1 ? 0.5 : i / (stops.length - 1);\n gradient.addColorStop(offset, stop);\n }\n }\n}\n\nfunction directionToAngle(dir: string): number {\n const map: Record<string, number> = {\n \"to top\": 0,\n \"to right\": 90,\n \"to bottom\": 180,\n \"to left\": 270,\n \"to top right\": 45,\n \"to top left\": 315,\n \"to bottom right\": 135,\n \"to bottom left\": 225,\n };\n return map[dir] ?? 180;\n}\n\nexport function splitGradientArgs(content: string): string[] {\n const parts: string[] = [];\n let current = \"\";\n let parenDepth = 0;\n\n for (const char of content) {\n if (char === \"(\") parenDepth++;\n if (char === \")\") parenDepth--;\n if (char === \",\" && parenDepth === 0) {\n parts.push(current);\n current = \"\";\n } else {\n current += char;\n }\n }\n if (current.trim()) parts.push(current);\n\n return parts;\n}\n","// Compositing groups through @effing/skia's `beginGroup` / `endGroup`:\n// everything drawn inside a group is composited as one when it ends, which is\n// what CSS `opacity`, `filter` and `backdrop-filter` mean on an element.\n// Per-draw `globalAlpha` and `ctx.filter` can't give that once draws overlap:\n// overlapping children would show through each other, and each would cast its\n// own shadow.\n//\n// A group is composited through an offscreen buffer, which @effing/skia sizes\n// to what the group draws, so a translucent element costs about as much as\n// its own area.\n\nimport type { SKRSContext2D } from \"@effing/skia\";\nimport { beginGroup, endGroup } from \"@effing/skia/extensions\";\n\nimport { applyClip } from \"./clip.ts\";\nimport type { getBorderRadiusFromStyle } from \"./rect.ts\";\n\ntype BorderRadius = ReturnType<typeof getBorderRadiusFromStyle>;\n\n/** A CSS filter value that filters nothing. */\nfunction isNoFilter(filter: string | undefined): boolean {\n if (!filter) return true;\n const normalized = filter.trim();\n return normalized === \"\" || normalized === \"none\";\n}\n\n/**\n * Start the group an element and its descendants paint into, when its\n * `opacity` or `filter` call for one. Returns whether a group was started,\n * to end with `endElementGroup`.\n */\nexport function beginElementGroup(\n ctx: SKRSContext2D,\n opacity: number,\n filter: string | undefined,\n): boolean {\n const hasFilter = !isNoFilter(filter);\n if (opacity >= 1 && !hasFilter) return false;\n beginGroup(ctx, { opacity, filter: hasFilter ? filter!.trim() : undefined });\n return true;\n}\n\nexport function endElementGroup(ctx: SKRSContext2D): void {\n endGroup(ctx);\n}\n\n/**\n * CSS `backdrop-filter`: filter whatever is already painted behind the\n * element's border box (with its radius) and composite the result back at the\n * element's opacity. Must run before the element's own painting — box-shadow\n * and background included — so nothing of the element ends up in its own\n * backdrop and its background composites on top of the filtered result.\n *\n * The filter runs in the element's own coordinate space, and the backdrop is\n * clamped at the canvas edge, as a browser does at the viewport edge, so a\n * blur near the edge doesn't fade into transparency. Skia reads the backdrop\n * from the enclosing group, so as in a browser, an ancestor with `opacity` or\n * a `filter` bounds what the element sees through: only what that ancestor\n * has painted so far.\n */\nexport function drawBackdropFilter(\n ctx: SKRSContext2D,\n filter: string,\n x: number,\n y: number,\n width: number,\n height: number,\n borderRadius: BorderRadius,\n opacity: number,\n): void {\n if (width <= 0 || height <= 0) return;\n if (isNoFilter(filter)) return;\n ctx.save();\n applyClip(ctx, x, y, width, height, borderRadius);\n beginGroup(ctx, { backdropFilter: filter.trim(), opacity });\n endGroup(ctx);\n ctx.restore();\n}\n","/**\n * Shared cover/contain sizing logic used by both `<img>` objectFit\n * and `backgroundImage` + `backgroundSize`.\n */\n\nexport interface FitRect {\n sx: number;\n sy: number;\n sw: number;\n sh: number;\n dx: number;\n dy: number;\n dw: number;\n dh: number;\n}\n\n/**\n * Compute source and destination rectangles for \"cover\" sizing.\n * The image fills the box completely, cropping the excess.\n */\nexport function computeCover(\n imgW: number,\n imgH: number,\n boxX: number,\n boxY: number,\n boxW: number,\n boxH: number,\n): FitRect {\n const imgRatio = imgW / imgH;\n const boxRatio = boxW / boxH;\n\n let sx: number, sy: number, sw: number, sh: number;\n\n if (imgRatio > boxRatio) {\n sh = imgH;\n sw = imgH * boxRatio;\n sx = (imgW - sw) / 2;\n sy = 0;\n } else {\n sw = imgW;\n sh = imgW / boxRatio;\n sx = 0;\n sy = (imgH - sh) / 2;\n }\n\n return { sx, sy, sw, sh, dx: boxX, dy: boxY, dw: boxW, dh: boxH };\n}\n\n/**\n * Compute destination rectangle for \"contain\" sizing.\n * The image fits entirely within the box, centered, with no cropping.\n */\nexport function computeContain(\n imgW: number,\n imgH: number,\n boxX: number,\n boxY: number,\n boxW: number,\n boxH: number,\n): FitRect {\n const imgRatio = imgW / imgH;\n const boxRatio = boxW / boxH;\n\n let dw: number, dh: number;\n\n if (imgRatio > boxRatio) {\n dw = boxW;\n dh = boxW / imgRatio;\n } else {\n dh = boxH;\n dw = boxH * imgRatio;\n }\n\n const dx = boxX + (boxW - dw) / 2;\n const dy = boxY + (boxH - dh) / 2;\n\n return { sx: 0, sy: 0, sw: imgW, sh: imgH, dx, dy, dw, dh };\n}\n","import type { SKRSContext2D } from \"@effing/skia\";\n\nimport { cachedLoadImage } from \"../../image.ts\";\nimport type { ComputedStyle } from \"../style/compute.ts\";\nimport type { RenderContext } from \"../context.ts\";\nimport { computeContain, computeCover } from \"./object-fit.ts\";\n\n/**\n * Draw an image element onto the canvas.\n *\n * @param ctx - Canvas rendering context\n * @param src - Image source (URL, file path, or Buffer)\n * @param x - X position\n * @param y - Y position\n * @param width - Target width\n * @param height - Target height\n * @param context - Per-render context (image cache + fetch config)\n * @param style - Computed style (for objectFit)\n */\nexport async function drawImage(\n ctx: SKRSContext2D,\n src: string | Buffer,\n x: number,\n y: number,\n width: number,\n height: number,\n context: RenderContext,\n style?: ComputedStyle,\n): Promise<void> {\n const image = await cachedLoadImage(\n context.imageCache,\n src,\n context.userAgent,\n );\n const objectFit = style?.objectFit ?? \"fill\";\n\n if (objectFit === \"fill\") {\n ctx.drawImage(image, x, y, width, height);\n return;\n }\n\n const imgW = image.width;\n const imgH = image.height;\n\n if (objectFit === \"contain\") {\n const r = computeContain(imgW, imgH, x, y, width, height);\n ctx.drawImage(image, r.dx, r.dy, r.dw, r.dh);\n } else if (objectFit === \"cover\") {\n const r = computeCover(imgW, imgH, x, y, width, height);\n ctx.drawImage(image, r.sx, r.sy, r.sw, r.sh, r.dx, r.dy, r.dw, r.dh);\n } else if (objectFit === \"none\") {\n const dx = x + (width - imgW) / 2;\n const dy = y + (height - imgH) / 2;\n ctx.drawImage(image, dx, dy);\n } else if (objectFit === \"scale-down\") {\n if (imgW <= width && imgH <= height) {\n const dx = x + (width - imgW) / 2;\n const dy = y + (height - imgH) / 2;\n ctx.drawImage(image, dx, dy);\n } else {\n const r = computeContain(imgW, imgH, x, y, width, height);\n ctx.drawImage(image, r.dx, r.dy, r.dw, r.dh);\n }\n }\n}\n","import type { InheritedSvgStyle } from \"./types.ts\";\n\n/** Replace `\"currentColor\"` with the inherited CSS `color` value. */\nexport function resolveCurrentColor(\n value: string | undefined,\n color: string,\n): string | undefined {\n if (value?.toLowerCase() === \"currentcolor\") return color;\n return value;\n}\n\n/**\n * Merge SVG presentation properties from `props.style` into the props object.\n * Style values win over direct props, matching browser CSS specificity rules.\n */\nexport function mergeStyleIntoProps(\n props: Record<string, unknown>,\n): Record<string, unknown> {\n const style = props.style as Record<string, unknown> | undefined;\n if (!style) return props;\n return { ...props, ...style };\n}\n\n/**\n * Parse an SVG length value, resolving percentages against a reference dimension.\n * Unlike gradient-specific `parseFrac`, this returns absolute coordinates (not 0–1 fractions).\n */\nexport function svgLength(\n value: unknown,\n reference: number,\n fallback = 0,\n): number {\n if (value == null) return fallback;\n const s = String(value);\n if (s.endsWith(\"%\")) return (parseFloat(s) / 100) * reference;\n const n = Number(s);\n return isNaN(n) ? fallback : n;\n}\n\n/** Parse `url(#id)` references and return the id, or undefined. */\nexport function parseUrlRef(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined;\n const m = value.match(/^url\\(#(.+)\\)$/);\n return m?.[1];\n}\n\n/**\n * Build an `InheritedSvgStyle` from merged SVG props, falling back to `parent`\n * values when present (for nested groups) or sensible defaults (fill = \"black\").\n */\nexport function resolveInheritedStyle(\n merged: Record<string, unknown>,\n color: string,\n parent?: InheritedSvgStyle,\n): InheritedSvgStyle {\n return {\n fill:\n resolveCurrentColor(merged.fill as string | undefined, color) ??\n parent?.fill ??\n \"black\",\n stroke:\n resolveCurrentColor(merged.stroke as string | undefined, color) ??\n parent?.stroke,\n strokeWidth:\n ((merged.strokeWidth ?? merged[\"stroke-width\"]) as\n | string\n | number\n | undefined) ?? parent?.strokeWidth,\n strokeLinecap:\n ((merged.strokeLinecap ?? merged[\"stroke-linecap\"]) as\n | string\n | undefined) ?? parent?.strokeLinecap,\n strokeLinejoin:\n ((merged.strokeLinejoin ?? merged[\"stroke-linejoin\"]) as\n | string\n | undefined) ?? parent?.strokeLinejoin,\n strokeOpacity:\n ((merged.strokeOpacity ?? merged[\"stroke-opacity\"]) as\n | string\n | number\n | undefined) ?? parent?.strokeOpacity,\n };\n}\n","import type { SvgChild } from \"./types.ts\";\n\n/** Normalize children from either `.children` or `.props.children` into an array. */\nexport function normalizeChildren(node: SvgChild): SvgChild[] {\n const raw =\n node.children ?? (node.props.children as SvgChild | SvgChild[] | undefined);\n if (raw == null) return [];\n return (Array.isArray(raw) ? raw.flat(Infinity) : [raw]) as SvgChild[];\n}\n","import type { SvgChild, SvgDefs } from \"./types.ts\";\nimport { normalizeChildren } from \"./tree.ts\";\n\n/**\n * Collect `<clipPath>`, `<mask>`, `<filter>`, and gradient definitions from\n * `<defs>` elements as well as direct children of `<svg>` (both are valid per\n * the SVG spec).\n */\nexport function collectDefs(children: SvgChild[], vbW = 0, vbH = 0): SvgDefs {\n const clips = new Map<string, SvgChild[]>();\n const gradients = new Map<string, SvgChild>();\n const masks = new Map<string, SvgChild[]>();\n const filters = new Map<string, SvgChild>();\n\n function insertDef(def: SvgChild): void {\n if (!def || typeof def !== \"object\" || !(\"props\" in def) || !def.props)\n return;\n const id = def.props.id as string | undefined;\n if (!id) return;\n if (def.type === \"clipPath\") clips.set(id, normalizeChildren(def));\n else if (def.type === \"mask\") masks.set(id, normalizeChildren(def));\n else if (def.type === \"filter\") filters.set(id, def);\n else if (def.type === \"radialGradient\" || def.type === \"linearGradient\")\n gradients.set(id, def);\n }\n\n for (const child of children) {\n if (child.type === \"defs\") {\n for (const def of normalizeChildren(child)) insertDef(def);\n } else {\n // Definition elements can appear as direct children of <svg>.\n insertDef(child);\n }\n }\n return {\n clips,\n gradients,\n masks,\n filters,\n viewport: { width: vbW, height: vbH },\n };\n}\n\nexport const EMPTY_DEFS: SvgDefs = {\n clips: new Map(),\n gradients: new Map(),\n masks: new Map(),\n filters: new Map(),\n viewport: { width: 0, height: 0 },\n};\n","import type { SKRSContext2D } from \"@effing/skia\";\n\n/**\n * Save context state and apply transform + opacity if present.\n * Returns true if ctx.save() was called (caller must ctx.restore()).\n */\nexport function applyTransformAndOpacity(\n ctx: SKRSContext2D,\n transform: string | undefined,\n opacity: number,\n): boolean {\n if (!transform && opacity >= 1) return false;\n ctx.save();\n if (transform) applySvgTransform(ctx, transform);\n if (opacity < 1) ctx.globalAlpha *= opacity;\n return true;\n}\n\n/**\n * Parse an SVG `transform` attribute and apply it to the canvas context.\n *\n * Supports: translate, scale, rotate, skewX, skewY, matrix.\n * Multiple transforms are applied left-to-right (same order as SVG spec).\n */\nexport function applySvgTransform(ctx: SKRSContext2D, transform: string): void {\n const re = /\\b(translate|scale|rotate|skewX|skewY|matrix)\\s*\\(([^)]*)\\)/g;\n let match: RegExpExecArray | null;\n while ((match = re.exec(transform)) !== null) {\n const fn = match[1]!;\n const args = match[2]!\n .split(/[\\s,]+/)\n .filter(Boolean)\n .map(Number);\n\n switch (fn) {\n case \"translate\":\n ctx.translate(args[0] ?? 0, args[1] ?? 0);\n break;\n case \"scale\": {\n const sx = args[0] ?? 1;\n ctx.scale(sx, args[1] ?? sx);\n break;\n }\n case \"rotate\": {\n const angle = ((args[0] ?? 0) * Math.PI) / 180;\n if (args.length >= 3) {\n const cx = args[1]!;\n const cy = args[2]!;\n ctx.translate(cx, cy);\n ctx.rotate(angle);\n ctx.translate(-cx, -cy);\n } else {\n ctx.rotate(angle);\n }\n break;\n }\n case \"skewX\":\n ctx.transform(\n 1,\n 0,\n Math.tan(((args[0] ?? 0) * Math.PI) / 180),\n 1,\n 0,\n 0,\n );\n break;\n case \"skewY\":\n ctx.transform(\n 1,\n Math.tan(((args[0] ?? 0) * Math.PI) / 180),\n 0,\n 1,\n 0,\n 0,\n );\n break;\n case \"matrix\":\n ctx.transform(\n args[0] ?? 1,\n args[1] ?? 0,\n args[2] ?? 0,\n args[3] ?? 1,\n args[4] ?? 0,\n args[5] ?? 0,\n );\n break;\n }\n }\n}\n","import { Path2D } from \"@effing/skia\";\n\nimport type { BBox, SvgChild } from \"./types.ts\";\nimport { mergeStyleIntoProps } from \"./style.ts\";\nimport { svgLength } from \"./style.ts\";\n\n/** Compute a conservative bounding box from SVG path data. */\nexport function pathBBox(d: string): BBox {\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n let cx = 0;\n let cy = 0;\n\n const update = (x: number, y: number) => {\n if (x < minX) minX = x;\n if (x > maxX) maxX = x;\n if (y < minY) minY = y;\n if (y > maxY) maxY = y;\n };\n\n // Tokenize: commands and numbers (including negative)\n const tokens = d.match(/[a-zA-Z]|[-+]?(?:\\d+\\.?\\d*|\\.\\d+)(?:[eE][-+]?\\d+)?/g);\n if (!tokens) return { x: 0, y: 0, width: 0, height: 0 };\n\n let cmd = \"\";\n let i = 0;\n const num = () => Number(tokens[i++]);\n\n while (i < tokens.length) {\n const t = tokens[i]!;\n if (/[a-zA-Z]/.test(t)) {\n cmd = t;\n i++;\n }\n\n switch (cmd) {\n case \"M\":\n cx = num();\n cy = num();\n update(cx, cy);\n cmd = \"L\"; // implicit lineTo after moveTo\n break;\n case \"m\":\n cx += num();\n cy += num();\n update(cx, cy);\n cmd = \"l\";\n break;\n case \"L\":\n cx = num();\n cy = num();\n update(cx, cy);\n break;\n case \"l\":\n cx += num();\n cy += num();\n update(cx, cy);\n break;\n case \"H\":\n cx = num();\n update(cx, cy);\n break;\n case \"h\":\n cx += num();\n update(cx, cy);\n break;\n case \"V\":\n cy = num();\n update(cx, cy);\n break;\n case \"v\":\n cy += num();\n update(cx, cy);\n break;\n case \"C\": {\n // Cubic bezier: use control points as conservative bounds\n for (let j = 0; j < 3; j++) {\n const px = num();\n const py = num();\n update(px, py);\n }\n cx = Number(tokens[i - 2]);\n cy = Number(tokens[i - 1]);\n break;\n }\n case \"c\": {\n for (let j = 0; j < 3; j++) {\n const dx = num();\n const dy = num();\n update(cx + dx, cy + dy);\n if (j === 2) {\n cx += dx;\n cy += dy;\n }\n }\n break;\n }\n case \"Q\": {\n for (let j = 0; j < 2; j++) {\n const px = num();\n const py = num();\n update(px, py);\n }\n cx = Number(tokens[i - 2]);\n cy = Number(tokens[i - 1]);\n break;\n }\n case \"q\": {\n for (let j = 0; j < 2; j++) {\n const dx = num();\n const dy = num();\n update(cx + dx, cy + dy);\n if (j === 1) {\n cx += dx;\n cy += dy;\n }\n }\n break;\n }\n case \"A\": {\n // Arc: skip rx, ry, rotation, flags; endpoint is the bound\n num();\n num();\n num();\n num();\n num(); // rx ry rot largeArc sweep\n cx = num();\n cy = num();\n update(cx, cy);\n break;\n }\n case \"a\": {\n num();\n num();\n num();\n num();\n num();\n cx += num();\n cy += num();\n update(cx, cy);\n break;\n }\n case \"Z\":\n case \"z\":\n break;\n default:\n // Unknown command — skip token to avoid infinite loop\n i++;\n break;\n }\n }\n\n if (!isFinite(minX)) return { x: 0, y: 0, width: 0, height: 0 };\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n}\n\n/** Compute bounding box from a points attribute (polygon/polyline). */\nexport function pointsBBox(points: [number, number][]): BBox {\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const [x, y] of points) {\n if (x < minX) minX = x;\n if (x > maxX) maxX = x;\n if (y < minY) minY = y;\n if (y > maxY) maxY = y;\n }\n if (!isFinite(minX)) return { x: 0, y: 0, width: 0, height: 0 };\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n}\n\n/**\n * Build a `Path2D` from an SVG shape element (without drawing it).\n * Returns `undefined` for unsupported element types.\n */\nexport function buildPath(\n child: SvgChild,\n vbW: number,\n vbH: number,\n): Path2D | undefined {\n const props = mergeStyleIntoProps(child.props);\n switch (child.type) {\n case \"path\": {\n const d = props.d as string | undefined;\n if (!d) return undefined;\n return new Path2D(d);\n }\n case \"circle\": {\n const cx = svgLength(props.cx, vbW);\n const cy = svgLength(props.cy, vbH);\n const r = svgLength(props.r, Math.min(vbW, vbH));\n if (r <= 0) return undefined;\n const p = new Path2D();\n p.arc(cx, cy, r, 0, Math.PI * 2);\n return p;\n }\n case \"rect\": {\n const x = svgLength(props.x, vbW);\n const y = svgLength(props.y, vbH);\n const w = svgLength(props.width, vbW);\n const h = svgLength(props.height, vbH);\n if (w <= 0 || h <= 0) return undefined;\n const rxRaw = svgLength(props.rx, vbW, -1);\n const ryRaw = svgLength(props.ry, vbH, -1);\n let rx = rxRaw >= 0 ? rxRaw : ryRaw >= 0 ? ryRaw : 0;\n let ry = ryRaw >= 0 ? ryRaw : rx;\n rx = Math.min(rx, w / 2);\n ry = Math.min(ry, h / 2);\n const p = new Path2D();\n if (rx > 0 || ry > 0) {\n p.roundRect(x, y, w, h, [rx]);\n } else {\n p.rect(x, y, w, h);\n }\n return p;\n }\n case \"ellipse\": {\n const cx = svgLength(props.cx, vbW);\n const cy = svgLength(props.cy, vbH);\n const rx = svgLength(props.rx, vbW);\n const ry = svgLength(props.ry, vbH);\n if (rx <= 0 || ry <= 0) return undefined;\n const p = new Path2D();\n p.ellipse(cx, cy, rx, ry, 0, 0, Math.PI * 2);\n return p;\n }\n case \"polygon\": {\n const points = parsePoints(props.points as string | undefined);\n if (points.length < 2) return undefined;\n const p = new Path2D();\n p.moveTo(points[0]![0], points[0]![1]);\n for (let i = 1; i < points.length; i++) {\n p.lineTo(points[i]![0], points[i]![1]);\n }\n p.closePath();\n return p;\n }\n default:\n return undefined;\n }\n}\n\n/**\n * Build a combined `Path2D` from all children of a `<clipPath>` definition.\n */\nexport function buildClipPath(\n shapes: SvgChild[],\n vbW: number,\n vbH: number,\n): Path2D | undefined {\n let combined: Path2D | undefined;\n for (const shape of shapes) {\n const p = buildPath(shape, vbW, vbH);\n if (!p) continue;\n if (!combined) {\n combined = p;\n } else {\n combined.addPath(p);\n }\n }\n return combined;\n}\n\nexport function parsePoints(value: string | undefined): [number, number][] {\n if (!value) return [];\n const nums = value\n .trim()\n .split(/[\\s,]+/)\n .map(Number);\n const result: [number, number][] = [];\n for (let i = 0; i + 1 < nums.length; i += 2) {\n result.push([nums[i]!, nums[i + 1]!]);\n }\n return result;\n}\n","import type { Canvas, SKRSContext2D } from \"@effing/skia\";\nimport { createCanvas } from \"@effing/skia\";\n\nconst canvasPool = new Map<string, WeakRef<Canvas>[]>();\n\nexport function acquireOffscreen(\n w: number,\n h: number,\n): [Canvas, SKRSContext2D] {\n const key = `${w}x${h}`;\n const stack = canvasPool.get(key);\n if (stack) {\n while (stack.length > 0) {\n const ref = stack.pop()!;\n const canvas = ref.deref();\n if (canvas) {\n const ctx = canvas.getContext(\"2d\");\n ctx.reset();\n return [canvas, ctx];\n }\n }\n }\n const canvas = createCanvas(w, h);\n return [canvas, canvas.getContext(\"2d\")];\n}\n\nexport function releaseOffscreen(canvas: Canvas): void {\n const key = `${canvas.width}x${canvas.height}`;\n let stack = canvasPool.get(key);\n if (!stack) {\n stack = [];\n canvasPool.set(key, stack);\n }\n stack.push(new WeakRef(canvas));\n}\n","import type { Canvas } from \"@effing/skia\";\n\nimport type { SvgChild } from \"./types.ts\";\nimport { normalizeChildren } from \"./tree.ts\";\nimport { acquireOffscreen } from \"../offscreen.ts\";\n\nfunction applyFeOffset(\n input: Canvas,\n dx: number,\n dy: number,\n w: number,\n h: number,\n): Canvas {\n const [canvas, ctx] = acquireOffscreen(w, h);\n ctx.drawImage(input, dx, dy);\n return canvas;\n}\n\nfunction applyFeGaussianBlur(\n input: Canvas,\n stdDeviation: number,\n w: number,\n h: number,\n): Canvas {\n const [canvas, ctx] = acquireOffscreen(w, h);\n ctx.filter = `blur(${stdDeviation}px)`;\n ctx.drawImage(input, 0, 0);\n ctx.filter = \"none\";\n return canvas;\n}\n\nfunction applyFeColorMatrix(\n input: Canvas,\n type: string,\n values: string | undefined,\n w: number,\n h: number,\n): Canvas {\n const [canvas, ctx] = acquireOffscreen(w, h);\n ctx.drawImage(input, 0, 0);\n\n if (type === \"matrix\" && values) {\n const m = values\n .trim()\n .split(/[\\s,]+/)\n .map(Number);\n if (m.length >= 20) {\n const imageData = ctx.getImageData(0, 0, w, h);\n const d = imageData.data;\n for (let i = 0; i < d.length; i += 4) {\n const r = d[i]!;\n const g = d[i + 1]!;\n const b = d[i + 2]!;\n const a = d[i + 3]!;\n d[i] = Math.min(\n 255,\n Math.max(\n 0,\n m[0]! * r + m[1]! * g + m[2]! * b + m[3]! * a + m[4]! * 255,\n ),\n );\n d[i + 1] = Math.min(\n 255,\n Math.max(\n 0,\n m[5]! * r + m[6]! * g + m[7]! * b + m[8]! * a + m[9]! * 255,\n ),\n );\n d[i + 2] = Math.min(\n 255,\n Math.max(\n 0,\n m[10]! * r + m[11]! * g + m[12]! * b + m[13]! * a + m[14]! * 255,\n ),\n );\n d[i + 3] = Math.min(\n 255,\n Math.max(\n 0,\n m[15]! * r + m[16]! * g + m[17]! * b + m[18]! * a + m[19]! * 255,\n ),\n );\n }\n ctx.putImageData(imageData, 0, 0);\n }\n }\n\n return canvas;\n}\n\nconst BLEND_MODE_MAP: Record<string, GlobalCompositeOperation> = {\n normal: \"source-over\",\n multiply: \"multiply\",\n screen: \"screen\",\n darken: \"darken\",\n lighten: \"lighten\",\n overlay: \"overlay\",\n};\n\nfunction applyFeBlend(\n in1: Canvas,\n in2: Canvas,\n mode: string,\n w: number,\n h: number,\n): Canvas {\n const [canvas, ctx] = acquireOffscreen(w, h);\n ctx.drawImage(in2, 0, 0);\n ctx.globalCompositeOperation = BLEND_MODE_MAP[mode] ?? \"source-over\";\n ctx.drawImage(in1, 0, 0);\n ctx.globalCompositeOperation = \"source-over\";\n return canvas;\n}\n\n/**\n * Extract the alpha channel of a canvas as a new greyscale canvas.\n * The result is a canvas where each pixel's RGBA channels equal the\n * source alpha (i.e. white where opaque, black where transparent).\n */\nfunction extractSourceAlpha(input: Canvas, w: number, h: number): Canvas {\n const [canvas, ctx] = acquireOffscreen(w, h);\n ctx.fillStyle = \"black\";\n ctx.fillRect(0, 0, w, h);\n ctx.globalCompositeOperation = \"destination-in\";\n ctx.drawImage(input, 0, 0);\n ctx.globalCompositeOperation = \"source-over\";\n return canvas;\n}\n\n/**\n * Execute an SVG `<filter>` pipeline on the element canvas.\n * Returns a new canvas with the filtered result; the caller is responsible\n * for releasing all canvases.\n */\nexport function applyFilter(\n filterDef: SvgChild,\n sourceGraphic: Canvas,\n w: number,\n h: number,\n): Canvas {\n const buffers = new Map<string, Canvas>();\n buffers.set(\"SourceGraphic\", sourceGraphic);\n\n let sourceAlpha: Canvas | undefined;\n const getSourceAlpha = () => {\n if (!sourceAlpha) {\n sourceAlpha = extractSourceAlpha(sourceGraphic, w, h);\n buffers.set(\"SourceAlpha\", sourceAlpha);\n }\n return sourceAlpha;\n };\n\n const children = normalizeChildren(filterDef);\n let lastResult: Canvas = sourceGraphic;\n\n for (const prim of children) {\n const p = prim.props;\n const inName = (p.in as string | undefined) ?? \"\";\n const resolve = (name: string): Canvas => {\n if (name === \"SourceAlpha\") return getSourceAlpha();\n return buffers.get(name) ?? lastResult;\n };\n const input = inName ? resolve(inName) : lastResult;\n let output: Canvas;\n\n switch (prim.type) {\n case \"feOffset\":\n output = applyFeOffset(\n input,\n Number(p.dx ?? 0),\n Number(p.dy ?? 0),\n w,\n h,\n );\n break;\n case \"feGaussianBlur\": {\n const std = Number(p.stdDeviation ?? 0);\n output = std > 0 ? applyFeGaussianBlur(input, std, w, h) : input;\n break;\n }\n case \"feColorMatrix\":\n output = applyFeColorMatrix(\n input,\n (p.type as string) ?? \"matrix\",\n p.values as string | undefined,\n w,\n h,\n );\n break;\n case \"feBlend\": {\n const in2Name = (p.in2 as string | undefined) ?? \"\";\n const in2 = in2Name ? resolve(in2Name) : lastResult;\n output = applyFeBlend(input, in2, (p.mode as string) ?? \"normal\", w, h);\n break;\n }\n default:\n output = input;\n break;\n }\n\n const resultName = p.result as string | undefined;\n if (resultName) buffers.set(resultName, output);\n lastResult = output;\n }\n\n return lastResult;\n}\n","import { Path2D } from \"@effing/skia\";\nimport type { SKRSContext2D } from \"@effing/skia\";\n\nimport type { BBox, InheritedSvgStyle, SvgDefs } from \"./types.ts\";\nimport { applyFillAndStroke, applyStroke } from \"./paint.ts\";\nimport { pathBBox, pointsBBox, parsePoints } from \"./path.ts\";\nimport { svgLength } from \"./style.ts\";\n\nexport function drawPath(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n inherited: InheritedSvgStyle,\n color: string,\n defs: SvgDefs,\n): void {\n const d = props.d as string | undefined;\n if (!d) return;\n\n const path = new Path2D(d);\n const bbox = pathBBox(d);\n applyFillAndStroke(ctx, props, path, inherited, color, defs, bbox);\n}\n\nexport function drawCircle(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n inherited: InheritedSvgStyle,\n color: string,\n defs: SvgDefs,\n vbW = 0,\n vbH = 0,\n): void {\n const cx = svgLength(props.cx, vbW);\n const cy = svgLength(props.cy, vbH);\n const r = svgLength(props.r, Math.min(vbW, vbH));\n if (r <= 0) return;\n\n const path = new Path2D();\n path.arc(cx, cy, r, 0, Math.PI * 2);\n const bbox: BBox = { x: cx - r, y: cy - r, width: 2 * r, height: 2 * r };\n applyFillAndStroke(ctx, props, path, inherited, color, defs, bbox);\n}\n\nexport function drawSvgRect(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n inherited: InheritedSvgStyle,\n color: string,\n defs: SvgDefs,\n vbW = 0,\n vbH = 0,\n): void {\n const x = svgLength(props.x, vbW);\n const y = svgLength(props.y, vbH);\n const w = svgLength(props.width, vbW);\n const h = svgLength(props.height, vbH);\n if (w <= 0 || h <= 0) return;\n\n const rxRaw = svgLength(props.rx, vbW, -1);\n const ryRaw = svgLength(props.ry, vbH, -1);\n let rx = rxRaw >= 0 ? rxRaw : ryRaw >= 0 ? ryRaw : 0;\n let ry = ryRaw >= 0 ? ryRaw : rx;\n rx = Math.min(rx, w / 2);\n ry = Math.min(ry, h / 2);\n\n const path = new Path2D();\n if (rx > 0 || ry > 0) {\n path.roundRect(x, y, w, h, [rx]);\n } else {\n path.rect(x, y, w, h);\n }\n const bbox: BBox = { x, y, width: w, height: h };\n applyFillAndStroke(ctx, props, path, inherited, color, defs, bbox);\n}\n\nexport function drawLine(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n inherited: InheritedSvgStyle,\n color: string,\n defs: SvgDefs,\n vbW = 0,\n vbH = 0,\n): void {\n const x1 = svgLength(props.x1, vbW);\n const y1 = svgLength(props.y1, vbH);\n const x2 = svgLength(props.x2, vbW);\n const y2 = svgLength(props.y2, vbH);\n\n const path = new Path2D();\n path.moveTo(x1, y1);\n path.lineTo(x2, y2);\n // Lines are stroke-only\n const bbox: BBox = {\n x: Math.min(x1, x2),\n y: Math.min(y1, y2),\n width: Math.abs(x2 - x1),\n height: Math.abs(y2 - y1),\n };\n applyStroke(ctx, props, path, inherited, color, defs, bbox);\n}\n\nexport function drawEllipse(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n inherited: InheritedSvgStyle,\n color: string,\n defs: SvgDefs,\n vbW = 0,\n vbH = 0,\n): void {\n const cx = svgLength(props.cx, vbW);\n const cy = svgLength(props.cy, vbH);\n const rx = svgLength(props.rx, vbW);\n const ry = svgLength(props.ry, vbH);\n if (rx <= 0 || ry <= 0) return;\n\n const path = new Path2D();\n path.ellipse(cx, cy, rx, ry, 0, 0, Math.PI * 2);\n const bbox: BBox = {\n x: cx - rx,\n y: cy - ry,\n width: 2 * rx,\n height: 2 * ry,\n };\n applyFillAndStroke(ctx, props, path, inherited, color, defs, bbox);\n}\n\nexport function drawPolygon(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n inherited: InheritedSvgStyle,\n color: string,\n defs: SvgDefs,\n): void {\n const points = parsePoints(props.points as string | undefined);\n if (points.length < 2) return;\n\n const path = new Path2D();\n path.moveTo(points[0]![0], points[0]![1]);\n for (let i = 1; i < points.length; i++) {\n path.lineTo(points[i]![0], points[i]![1]);\n }\n path.closePath();\n const bbox = pointsBBox(points);\n applyFillAndStroke(ctx, props, path, inherited, color, defs, bbox);\n}\n\nexport function drawPolyline(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n inherited: InheritedSvgStyle,\n color: string,\n defs: SvgDefs,\n): void {\n const points = parsePoints(props.points as string | undefined);\n if (points.length < 2) return;\n\n const path = new Path2D();\n path.moveTo(points[0]![0], points[0]![1]);\n for (let i = 1; i < points.length; i++) {\n path.lineTo(points[i]![0], points[i]![1]);\n }\n const bbox = pointsBBox(points);\n applyFillAndStroke(ctx, props, path, inherited, color, defs, bbox);\n}\n","import { Path2D } from \"@effing/skia\";\nimport type {\n CanvasGradient,\n DOMMatrix2DInit,\n SKRSContext2D,\n} from \"@effing/skia\";\n\nimport parseCssColor from \"parse-css-color\";\n\nimport type { BBox, SvgChild, SvgDefs } from \"./types.ts\";\nimport { normalizeChildren } from \"./tree.ts\";\n\ntype Viewport = SvgDefs[\"viewport\"];\n\n/** Parse a gradient coordinate percentage/fraction to a 0–1 value. */\nfunction parseFrac(value: unknown, fallback: number): number {\n if (value == null) return fallback;\n const s = String(value);\n if (s.endsWith(\"%\")) return parseFloat(s) / 100;\n return Number(s);\n}\n\n/** True when the gradient declares `gradientUnits=\"userSpaceOnUse\"`. */\nfunction isUserSpaceOnUse(props: Record<string, unknown>): boolean {\n return props.gradientUnits === \"userSpaceOnUse\";\n}\n\n/**\n * Parse a user-space gradient coordinate. Percentages resolve against\n * `reference` (the relevant viewport dimension, per the SVG spec).\n */\nfunction parseUserLength(\n value: unknown,\n fallback: number,\n reference: number,\n): number {\n if (value == null) return fallback;\n const s = String(value);\n if (s.endsWith(\"%\")) return (parseFloat(s) / 100) * reference;\n return Number(s);\n}\n\n/** Apply opacity to a CSS color string. */\nexport function applyOpacity(color: string, opacity: number): string {\n if (opacity >= 1) return color;\n const parsed = parseCssColor(color);\n if (!parsed) return color;\n const [r, g, b] = parsed.values;\n return `rgba(${r}, ${g}, ${b}, ${parsed.alpha * opacity})`;\n}\n\n/** Add color stops from SVG `<stop>` children to a canvas gradient. */\nfunction addGradientStops(gradient: CanvasGradient, def: SvgChild): void {\n for (const stop of normalizeChildren(def)) {\n if (stop.type !== \"stop\") continue;\n const sp = stop.props;\n const offsetRaw = (sp.offset as string | number) ?? 0;\n const offset =\n typeof offsetRaw === \"string\" && offsetRaw.endsWith(\"%\")\n ? parseFloat(offsetRaw) / 100\n : Number(offsetRaw);\n const stopColor =\n ((sp.stopColor ?? sp[\"stop-color\"]) as string | undefined) ?? \"black\";\n const stopOpacity = Number(sp.stopOpacity ?? sp[\"stop-opacity\"] ?? 1);\n gradient.addColorStop(offset, applyOpacity(stopColor, stopOpacity));\n }\n}\n\n/** Create a linear gradient from bbox-relative coordinates with stops applied. */\nfunction createLinearGradientFromBBox(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n bbox: BBox,\n def: SvgChild,\n): CanvasGradient {\n const x1 = bbox.x + parseFrac(props.x1, 0) * bbox.width;\n const y1 = bbox.y + parseFrac(props.y1, 0) * bbox.height;\n const x2 = bbox.x + parseFrac(props.x2, 1) * bbox.width;\n const y2 = bbox.y + parseFrac(props.y2, 0) * bbox.height;\n const gradient = ctx.createLinearGradient(x1, y1, x2, y2);\n addGradientStops(gradient, def);\n return gradient;\n}\n\n/**\n * Create a linear gradient from `userSpaceOnUse` coordinates with stops\n * applied. The coordinates are in the SVG user coordinate system, which is\n * the context's current coordinate system (the viewBox transform is active),\n * so they map to canvas gradient coordinates directly.\n */\nfunction createLinearGradientUserSpace(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n viewport: Viewport,\n def: SvgChild,\n): CanvasGradient {\n const x1 = parseUserLength(props.x1, 0, viewport.width);\n const y1 = parseUserLength(props.y1, 0, viewport.height);\n const x2 = parseUserLength(props.x2, viewport.width, viewport.width);\n const y2 = parseUserLength(props.y2, 0, viewport.height);\n const gradient = ctx.createLinearGradient(x1, y1, x2, y2);\n addGradientStops(gradient, def);\n return gradient;\n}\n\n/**\n * Create a radial gradient from `userSpaceOnUse` coordinates with stops\n * applied. In user space the gradient is a true circle, so no elliptical\n * bbox transform is needed. Percentage radii resolve against the\n * viewport's normalized diagonal, per the SVG spec.\n */\nfunction createRadialGradientUserSpace(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n viewport: Viewport,\n def: SvgChild,\n): CanvasGradient {\n const diagonal = Math.hypot(viewport.width, viewport.height) / Math.SQRT2;\n const cx = parseUserLength(props.cx, viewport.width / 2, viewport.width);\n const cy = parseUserLength(props.cy, viewport.height / 2, viewport.height);\n const r = parseUserLength(props.r, diagonal / 2, diagonal);\n const fx = parseUserLength(props.fx, cx, viewport.width);\n const fy = parseUserLength(props.fy, cy, viewport.height);\n const gradient = ctx.createRadialGradient(fx, fy, 0, cx, cy, r);\n addGradientStops(gradient, def);\n return gradient;\n}\n\n/**\n * Fill `path` with a gradient defined by `def` in the coordinate space of `bbox`.\n *\n * With `gradientUnits=\"userSpaceOnUse\"` the gradient coordinates are already\n * in the SVG user coordinate system and are used as-is.\n *\n * With the default `objectBoundingBox` units, coordinates are fractions of\n * `bbox`. For `<linearGradient>` the bbox-to-canvas mapping is\n * straightforward. For `<radialGradient>` a non-square bbox produces an\n * *elliptical* gradient. Canvas only supports circular radial gradients, so\n * we apply a non-uniform scale transform to the context and fill an\n * inverse-transformed copy of the path.\n */\nexport function fillWithSvgGradient(\n ctx: SKRSContext2D,\n def: SvgChild,\n bbox: BBox,\n path: Path2D,\n fillRule: CanvasFillRule,\n viewport: Viewport,\n): boolean {\n const props = def.props;\n\n if (def.type === \"linearGradient\") {\n ctx.fillStyle = isUserSpaceOnUse(props)\n ? createLinearGradientUserSpace(ctx, props, viewport, def)\n : createLinearGradientFromBBox(ctx, props, bbox, def);\n ctx.fill(path, fillRule);\n return true;\n }\n\n if (def.type === \"radialGradient\" && isUserSpaceOnUse(props)) {\n ctx.fillStyle = createRadialGradientUserSpace(ctx, props, viewport, def);\n ctx.fill(path, fillRule);\n return true;\n }\n\n if (def.type === \"radialGradient\") {\n const cxF = parseFrac(props.cx, 0.5);\n const cyF = parseFrac(props.cy, 0.5);\n const rF = parseFrac(props.r, 0.5);\n const fxF = parseFrac(props.fx, cxF);\n const fyF = parseFrac(props.fy, cyF);\n\n // Render in a transformed space where the bbox maps to a unit square.\n // This turns canvas's circular radial gradient into the correct ellipse.\n ctx.save();\n ctx.translate(bbox.x, bbox.y);\n ctx.scale(bbox.width, bbox.height);\n\n const gradient = ctx.createRadialGradient(fxF, fyF, 0, cxF, cyF, rF);\n addGradientStops(gradient, def);\n ctx.fillStyle = gradient;\n\n // The path is in original (absolute) coordinates. Inverse-transform it\n // into the unit-square space so the fill aligns with the shape.\n // inverse of translate(bx,by) · scale(bw,bh) = scale(1/bw,1/bh) · translate(-bx,-by)\n const unitPath = new Path2D();\n const invTransform: DOMMatrix2DInit = {\n a: 1 / bbox.width,\n b: 0,\n c: 0,\n d: 1 / bbox.height,\n e: -bbox.x / bbox.width,\n f: -bbox.y / bbox.height,\n };\n unitPath.addPath(path, invTransform);\n\n ctx.fill(unitPath, fillRule);\n ctx.restore();\n return true;\n }\n\n return false;\n}\n\n/**\n * Stroke `path` with a gradient defined by `def` in the coordinate space of `bbox`.\n */\nexport function strokeWithSvgGradient(\n ctx: SKRSContext2D,\n def: SvgChild,\n bbox: BBox,\n path: Path2D,\n viewport: Viewport,\n): boolean {\n const props = def.props;\n\n if (def.type === \"linearGradient\") {\n ctx.strokeStyle = isUserSpaceOnUse(props)\n ? createLinearGradientUserSpace(ctx, props, viewport, def)\n : createLinearGradientFromBBox(ctx, props, bbox, def);\n ctx.stroke(path);\n return true;\n }\n\n if (def.type === \"radialGradient\" && isUserSpaceOnUse(props)) {\n ctx.strokeStyle = createRadialGradientUserSpace(ctx, props, viewport, def);\n ctx.stroke(path);\n return true;\n }\n\n if (def.type === \"radialGradient\") {\n // For stroke, use a simple circular approximation (geometric mean radius)\n const cxAbs = bbox.x + parseFrac(props.cx, 0.5) * bbox.width;\n const cyAbs = bbox.y + parseFrac(props.cy, 0.5) * bbox.height;\n const rAbs = parseFrac(props.r, 0.5) * Math.sqrt(bbox.width * bbox.height);\n const fxAbs = bbox.x + parseFrac(props.fx, 0.5) * bbox.width;\n const fyAbs = bbox.y + parseFrac(props.fy, 0.5) * bbox.height;\n const gradient = ctx.createRadialGradient(\n fxAbs,\n fyAbs,\n 0,\n cxAbs,\n cyAbs,\n rAbs,\n );\n addGradientStops(gradient, def);\n ctx.strokeStyle = gradient;\n ctx.stroke(path);\n return true;\n }\n\n return false;\n}\n","import type { Path2D, SKRSContext2D } from \"@effing/skia\";\n\nimport type { BBox, InheritedSvgStyle, SvgDefs } from \"./types.ts\";\nimport { resolveCurrentColor } from \"./style.ts\";\nimport { parseUrlRef } from \"./style.ts\";\nimport {\n applyOpacity,\n fillWithSvgGradient,\n strokeWithSvgGradient,\n} from \"./gradients.ts\";\n\nexport function applyFillAndStroke(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n path: Path2D,\n inherited: InheritedSvgStyle,\n color: string,\n defs: SvgDefs,\n bbox: BBox,\n): void {\n // Use element's own fill if set, otherwise inherit from parent\n const fill =\n resolveCurrentColor(props.fill as string | undefined, color) ??\n inherited.fill;\n const fillRule = (props.fillRule ?? props[\"fill-rule\"]) as\n CanvasFillRule | undefined;\n const fillOpacity = Number(props.fillOpacity ?? props[\"fill-opacity\"] ?? 1);\n\n // Resolve url(#id) gradient reference\n const fillRef = parseUrlRef(fill);\n if (fillRef) {\n const gradientDef = defs.gradients.get(fillRef);\n if (gradientDef) {\n if (fillOpacity < 1) {\n ctx.save();\n ctx.globalAlpha *= fillOpacity;\n fillWithSvgGradient(\n ctx,\n gradientDef,\n bbox,\n path,\n fillRule ?? \"nonzero\",\n defs.viewport,\n );\n ctx.restore();\n } else {\n fillWithSvgGradient(\n ctx,\n gradientDef,\n bbox,\n path,\n fillRule ?? \"nonzero\",\n defs.viewport,\n );\n }\n }\n } else if (fill !== \"none\") {\n ctx.fillStyle = applyOpacity(fill, fillOpacity);\n ctx.fill(path, fillRule ?? \"nonzero\");\n }\n\n applyStroke(ctx, props, path, inherited, color, defs, bbox);\n}\n\nexport function applyStroke(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n path: Path2D,\n inherited: InheritedSvgStyle,\n color: string,\n defs: SvgDefs,\n bbox: BBox,\n): void {\n const stroke =\n resolveCurrentColor(props.stroke as string | undefined, color) ??\n inherited.stroke;\n if (!stroke || stroke === \"none\") return;\n\n const strokeOpacity = Number(\n props.strokeOpacity ??\n props[\"stroke-opacity\"] ??\n inherited.strokeOpacity ??\n 1,\n );\n\n ctx.lineWidth = Number(\n props.strokeWidth ?? props[\"stroke-width\"] ?? inherited.strokeWidth ?? 1,\n );\n ctx.lineCap = (((props.strokeLinecap ??\n props[\"stroke-linecap\"]) as CanvasLineCap) ??\n inherited.strokeLinecap ??\n \"butt\") as CanvasLineCap;\n ctx.lineJoin = (((props.strokeLinejoin ??\n props[\"stroke-linejoin\"]) as CanvasLineJoin) ??\n inherited.strokeLinejoin ??\n \"miter\") as CanvasLineJoin;\n\n // Resolve url(#id) gradient reference for stroke\n const strokeRef = parseUrlRef(stroke);\n if (strokeRef) {\n const gradientDef = defs.gradients.get(strokeRef);\n if (gradientDef) {\n if (strokeOpacity < 1) {\n ctx.save();\n ctx.globalAlpha *= strokeOpacity;\n strokeWithSvgGradient(ctx, gradientDef, bbox, path, defs.viewport);\n ctx.restore();\n } else {\n strokeWithSvgGradient(ctx, gradientDef, bbox, path, defs.viewport);\n }\n return;\n }\n }\n\n ctx.strokeStyle = applyOpacity(stroke, strokeOpacity);\n ctx.stroke(path);\n}\n","import type { Canvas, SKRSContext2D } from \"@effing/skia\";\n\nimport type { InheritedSvgStyle, SvgChild, SvgDefs } from \"./types.ts\";\nimport { EMPTY_DEFS } from \"./defs.ts\";\nimport { normalizeChildren } from \"./tree.ts\";\nimport {\n mergeStyleIntoProps,\n parseUrlRef,\n resolveInheritedStyle,\n} from \"./style.ts\";\nimport { applyTransformAndOpacity } from \"./transform.ts\";\nimport { buildClipPath } from \"./path.ts\";\nimport { applyFilter } from \"./filters.ts\";\nimport { acquireOffscreen, releaseOffscreen } from \"../offscreen.ts\";\nimport {\n drawPath,\n drawCircle,\n drawSvgRect,\n drawLine,\n drawEllipse,\n drawPolygon,\n drawPolyline,\n} from \"./shapes.ts\";\n\nexport function drawSvgChild(\n ctx: SKRSContext2D,\n child: SvgChild,\n inherited: InheritedSvgStyle,\n color: string,\n defs: SvgDefs = EMPTY_DEFS,\n vbW = 0,\n vbH = 0,\n): void {\n const { type } = child;\n const props = mergeStyleIntoProps(child.props);\n\n // Skip non-drawable definition elements\n if (\n type === \"defs\" ||\n type === \"clipPath\" ||\n type === \"mask\" ||\n type === \"filter\"\n )\n return;\n\n // Apply transform and opacity on shape elements (drawGroup handles its own)\n const transform =\n type !== \"g\" ? (props.transform as string | undefined) : undefined;\n const opacity = type !== \"g\" ? Number(props.opacity ?? 1) : 1;\n const savedTransform = applyTransformAndOpacity(ctx, transform, opacity);\n\n // Check for clip-path=\"url(#id)\" reference\n const clipRef = parseUrlRef(props.clipPath ?? props[\"clip-path\"]);\n const clipShapes = clipRef ? defs.clips.get(clipRef) : undefined;\n const clipPath = clipShapes ? buildClipPath(clipShapes, vbW, vbH) : undefined;\n\n // Check for mask=\"url(#id)\" reference\n const maskRef = parseUrlRef(props.mask as string | undefined);\n const maskShapes = maskRef ? defs.masks.get(maskRef) : undefined;\n\n // Check for filter=\"url(#id)\" reference\n const filterRef = parseUrlRef(props.filter as string | undefined);\n const filterDef = filterRef ? defs.filters.get(filterRef) : undefined;\n\n if (clipPath) {\n ctx.save();\n ctx.clip(clipPath);\n }\n\n // When a mask or filter is present, render the element to an offscreen\n // canvas so we can post-process it before drawing to the main context.\n const needsOffscreen = maskShapes || filterDef;\n let elemCanvas: Canvas | undefined;\n let targetCtx: SKRSContext2D;\n if (needsOffscreen) {\n const [c, cCtx] = acquireOffscreen(Math.ceil(vbW), Math.ceil(vbH));\n elemCanvas = c;\n targetCtx = cCtx;\n } else {\n targetCtx = ctx;\n }\n\n switch (type) {\n case \"path\":\n drawPath(targetCtx, props, inherited, color, defs);\n break;\n case \"circle\":\n drawCircle(targetCtx, props, inherited, color, defs, vbW, vbH);\n break;\n case \"rect\":\n drawSvgRect(targetCtx, props, inherited, color, defs, vbW, vbH);\n break;\n case \"line\":\n drawLine(targetCtx, props, inherited, color, defs, vbW, vbH);\n break;\n case \"ellipse\":\n drawEllipse(targetCtx, props, inherited, color, defs, vbW, vbH);\n break;\n case \"polygon\":\n drawPolygon(targetCtx, props, inherited, color, defs);\n break;\n case \"polyline\":\n drawPolyline(targetCtx, props, inherited, color, defs);\n break;\n case \"g\":\n drawGroup(targetCtx, child, props, inherited, color, defs, vbW, vbH);\n break;\n }\n\n if (needsOffscreen && elemCanvas) {\n applyOffscreenEffects(\n ctx,\n elemCanvas,\n targetCtx,\n maskShapes,\n filterDef,\n color,\n defs,\n vbW,\n vbH,\n );\n }\n\n if (clipPath) ctx.restore();\n if (savedTransform) ctx.restore();\n}\n\nfunction drawGroup(\n ctx: SKRSContext2D,\n node: SvgChild,\n mergedProps: Record<string, unknown>,\n inherited: InheritedSvgStyle,\n color: string,\n defs: SvgDefs = EMPTY_DEFS,\n vbW = 0,\n vbH = 0,\n): void {\n const children = normalizeChildren(node);\n if (children.length === 0) return;\n const groupInherited = resolveInheritedStyle(mergedProps, color, inherited);\n\n const opacity = Number(mergedProps.opacity ?? 1);\n const transform = mergedProps.transform as string | undefined;\n const saved = applyTransformAndOpacity(ctx, transform, opacity);\n\n for (const child of children) {\n if (child != null && typeof child === \"object\") {\n drawSvgChild(ctx, child, groupInherited, color, defs, vbW, vbH);\n }\n }\n\n if (saved) ctx.restore();\n}\n\n/** Composite mask and/or filter effects from offscreen canvas onto main context. */\nfunction applyOffscreenEffects(\n ctx: SKRSContext2D,\n elemCanvas: Canvas,\n targetCtx: SKRSContext2D,\n maskShapes: SvgChild[] | undefined,\n filterDef: SvgChild | undefined,\n color: string,\n defs: SvgDefs,\n vbW: number,\n vbH: number,\n): void {\n // Apply mask if present\n if (maskShapes) {\n const [maskCanvas, maskCtx] = acquireOffscreen(\n Math.ceil(vbW),\n Math.ceil(vbH),\n );\n for (const shape of maskShapes) {\n drawSvgChild(maskCtx, shape, { fill: \"white\" }, \"white\", defs, vbW, vbH);\n }\n targetCtx.globalCompositeOperation = \"destination-in\";\n targetCtx.drawImage(maskCanvas, 0, 0);\n targetCtx.globalCompositeOperation = \"source-over\";\n releaseOffscreen(maskCanvas);\n }\n\n // Apply filter if present\n if (filterDef) {\n const filteredCanvas = applyFilter(\n filterDef,\n elemCanvas,\n Math.ceil(vbW),\n Math.ceil(vbH),\n );\n ctx.drawImage(filteredCanvas, 0, 0);\n // Release intermediates (filteredCanvas may be elemCanvas if no-op)\n if (filteredCanvas !== elemCanvas) releaseOffscreen(filteredCanvas);\n } else {\n ctx.drawImage(elemCanvas, 0, 0);\n }\n releaseOffscreen(elemCanvas);\n}\n","import type { SKRSContext2D } from \"@effing/skia\";\n\nimport type { LayoutNode } from \"../../layout.ts\";\nimport type { SvgChild } from \"./types.ts\";\nimport { mergeStyleIntoProps, resolveInheritedStyle } from \"./style.ts\";\nimport { collectDefs } from \"./defs.ts\";\nimport { drawSvgChild } from \"./traverse.ts\";\n\n/**\n * Draw an `<svg>` container and its SVG children (path, circle, rect, etc.).\n *\n * Parses the `viewBox` prop to compute scale factors, then recurses into\n * the React children stored in `node.props.children`.\n */\nexport function drawSvgContainer(\n ctx: SKRSContext2D,\n node: LayoutNode,\n x: number,\n y: number,\n width: number,\n height: number,\n): void {\n ctx.save();\n ctx.translate(x, y);\n\n // Parse viewBox for coordinate mapping; default to rendered size when absent\n const viewBox = node.props.viewBox as string | undefined;\n let vbW = width;\n let vbH = height;\n if (viewBox) {\n const parts = viewBox.split(/[\\s,]+/).map(Number);\n if (parts.length === 4) {\n const [vbX, vbY, parsedW, parsedH] = parts as [\n number,\n number,\n number,\n number,\n ];\n vbW = parsedW;\n vbH = parsedH;\n const scaleX = width / vbW;\n const scaleY = height / vbH;\n ctx.scale(scaleX, scaleY);\n ctx.translate(-vbX, -vbY);\n }\n }\n\n // Resolve the CSS `color` property for `currentColor` references\n const color = (node.style.color as string | undefined) ?? \"black\";\n\n // Build inherited SVG style from the <svg> element\n const merged = mergeStyleIntoProps(node.props);\n const inherited = resolveInheritedStyle(merged, color);\n\n // Traverse React children\n const children = node.props.children;\n if (children != null) {\n // Deep-flatten so helpers returning arrays don't slip nested arrays through\n // to the defs collector or shape switch (both expect element-shaped nodes).\n const childArray = (\n Array.isArray(children) ? children.flat(Infinity) : [children]\n ) as unknown[];\n const svgChildren = childArray.filter(\n (c): c is SvgChild =>\n c != null && typeof c === \"object\" && !Array.isArray(c),\n );\n\n // First pass: collect definitions from <defs>\n const defs = collectDefs(svgChildren, vbW, vbH);\n\n // Second pass: draw children\n for (const child of svgChildren) {\n drawSvgChild(ctx, child, inherited, color, defs, vbW, vbH);\n }\n }\n\n ctx.restore();\n}\n","import { loadImage } from \"@effing/skia\";\nimport type { SKRSContext2D, Image } from \"@effing/skia\";\nimport { fillParagraph, strokeParagraph } from \"@effing/skia/extensions\";\n\nimport parseCssColor from \"parse-css-color\";\n\nimport type { EmojiStyle } from \"../emoji.ts\";\nimport { emojiUrl, loadEmoji } from \"../emoji.ts\";\nimport type {\n PlacedEmoji,\n TextLayoutResult,\n TextSegment,\n} from \"../text/index.ts\";\nimport { setFont } from \"../text/measure.ts\";\n\nconst emojiImageCache = new Map<string, Promise<Image | null>>();\n\nfunction loadEmojiImage(\n style: EmojiStyle,\n emoji: string,\n): Promise<Image | null> {\n const key = emojiUrl(style, emoji);\n let cached = emojiImageCache.get(key);\n if (!cached) {\n cached = loadEmoji(style, emoji)\n .then((svgText) => {\n if (!svgText || !svgText.includes(\"<svg\")) return null;\n const dataUri =\n \"data:image/svg+xml;base64,\" +\n Buffer.from(svgText).toString(\"base64\");\n return loadImage(dataUri);\n })\n .catch(() => null);\n emojiImageCache.set(key, cached);\n }\n return cached;\n}\n\n/**\n * Draw laid-out text onto the canvas context: the paragraph, unhinted and\n * unsnapped, with its shadow, stroke and decorations, and the emoji drawn as\n * images in the inline boxes it left them.\n *\n * @param ctx - Canvas 2D rendering context\n * @param layout - The text as laid out by `layoutText`\n * @param offsetX - X offset for the text block\n * @param offsetY - Y offset for the text block\n * @param textShadow - Optional text-shadow CSS value\n * @param emojiStyle - The emoji style the text was laid out for, if any\n */\nexport async function drawText(\n ctx: SKRSContext2D,\n layout: TextLayoutResult,\n offsetX: number,\n offsetY: number,\n textShadow?: string,\n emojiStyle?: EmojiStyle,\n): Promise<void> {\n const { paragraph, segments, emoji } = layout;\n const first = segments[0];\n if (!first) return;\n const x = offsetX;\n const y = offsetY + layout.paragraphOffsetY;\n const shadow = textShadow ? parseShadow(textShadow) : null;\n ctx.fillStyle = first.color;\n\n // Each pass is a single native call for the whole paragraph.\n if (shadow) {\n drawShadowPass(ctx, shadow, getColorAlpha(first.color), () =>\n fillParagraph(ctx, paragraph, x, y),\n );\n }\n if (first.textStrokeWidth !== undefined && first.textStrokeWidth > 0) {\n ctx.save();\n ctx.lineWidth = first.textStrokeWidth;\n ctx.strokeStyle = first.textStrokeColor ?? first.color;\n ctx.lineJoin = \"round\";\n strokeParagraph(ctx, paragraph, x, y);\n ctx.restore();\n }\n fillParagraph(ctx, paragraph, x, y);\n\n if (emojiStyle && emoji.length > 0) {\n await drawEmoji(ctx, emoji, first, offsetX, offsetY, emojiStyle);\n }\n\n for (const seg of segments) {\n if (seg.textDecoration) {\n drawTextDecoration(ctx, seg, offsetX, offsetY);\n }\n }\n}\n\nasync function drawEmoji(\n ctx: SKRSContext2D,\n emoji: PlacedEmoji[],\n font: TextSegment,\n offsetX: number,\n offsetY: number,\n emojiStyle: EmojiStyle,\n): Promise<void> {\n const images = await Promise.all(\n emoji.map((e) => loadEmojiImage(emojiStyle, e.grapheme)),\n );\n emoji.forEach((e, i) => {\n const img = images[i];\n if (img) {\n ctx.drawImage(img, offsetX + e.x, offsetY + e.y, e.size, e.size);\n return;\n }\n // Emoji image unavailable: draw it as text, in its box on the baseline.\n setFont(\n ctx,\n font.fontSize,\n font.fontFamily,\n font.fontWeight,\n font.fontStyle,\n );\n const textRendering = ctx.textRendering;\n ctx.textRendering = \"geometricPrecision\";\n ctx.fillText(e.grapheme, offsetX + e.x, offsetY + e.baseline);\n ctx.textRendering = textRendering;\n });\n}\n\ninterface ParsedShadow {\n offsetX: number;\n offsetY: number;\n blur: number;\n color: string;\n}\n\nfunction parseShadow(shadow: string): ParsedShadow | null {\n const parts = shadow.match(\n /(-?\\d+(?:\\.\\d+)?)\\s*(?:px)?\\s+(-?\\d+(?:\\.\\d+)?)\\s*(?:px)?\\s+(-?\\d+(?:\\.\\d+)?)\\s*(?:px)?\\s+(.*)/,\n );\n if (!parts) return null;\n return {\n offsetX: parseFloat(parts[1]!),\n offsetY: parseFloat(parts[2]!),\n blur: parseFloat(parts[3]!),\n color: parts[4]!.trim(),\n };\n}\n\n/** Extract the alpha component from a CSS color string. */\nfunction getColorAlpha(color: string): number {\n const parsed = parseCssColor(color);\n return parsed ? parsed.alpha : 1;\n}\n\n/**\n * Draw the text shadow manually instead of using the canvas shadow API.\n *\n * CSS text-shadow renders the shadow as if derived from the text's painted\n * appearance, so when the text color has alpha < 1 the shadow is also\n * attenuated. The canvas shadow API does NOT do this — it always renders\n * the shadow at the full specified opacity. We match CSS behavior by\n * drawing the shadow as a separate fillText at the offset, with\n * globalAlpha scaled by the text color's alpha.\n */\nfunction drawShadowPass(\n ctx: SKRSContext2D,\n shadow: ParsedShadow,\n textAlpha: number,\n drawFn: () => void,\n): void {\n ctx.save();\n ctx.fillStyle = shadow.color;\n if (textAlpha < 1) ctx.globalAlpha *= textAlpha;\n if (shadow.blur > 0) ctx.filter = `blur(${shadow.blur / 2}px)`;\n ctx.translate(shadow.offsetX, shadow.offsetY);\n drawFn();\n ctx.restore();\n}\n\nfunction drawTextDecoration(\n ctx: SKRSContext2D,\n seg: TextSegment,\n offsetX: number,\n offsetY: number,\n): void {\n const decoration = seg.textDecoration;\n if (!decoration || decoration === \"none\") return;\n\n ctx.strokeStyle = seg.color;\n ctx.lineWidth = Math.max(1, seg.fontSize * 0.1);\n\n const x = offsetX + seg.x;\n const baseY = offsetY + seg.y;\n\n if (decoration.includes(\"underline\")) {\n const y = baseY + seg.ascent * 0.1;\n ctx.beginPath();\n ctx.moveTo(x, y);\n ctx.lineTo(x + seg.width, y);\n ctx.stroke();\n }\n\n if (decoration.includes(\"line-through\")) {\n const y = baseY - seg.fontSize * 0.3;\n ctx.beginPath();\n ctx.moveTo(x, y);\n ctx.lineTo(x + seg.width, y);\n ctx.stroke();\n }\n\n if (decoration.includes(\"overline\")) {\n const y = baseY - seg.fontSize * 0.85;\n ctx.beginPath();\n ctx.moveTo(x, y);\n ctx.lineTo(x + seg.width, y);\n ctx.stroke();\n }\n}\n","// This file contains code adapted from Satori (https://github.com/vercel/satori)\n// Licensed under the Mozilla Public License 2.0 (MPL-2.0)\n// See NOTICE.md in the package root for details.\n\nimport { UNASSIGNED_PICTOGRAPHIC } from \"./language.ts\";\n\n/**\n * Emoji style options for rendering\n */\nexport type EmojiStyle =\n \"twemoji\" | \"openmoji\" | \"blobmoji\" | \"noto\" | \"fluent\" | \"fluentFlat\";\n\nconst FE0F = 0xfe0f;\nconst ZWJ = 0x200d;\nconst KEYCAP = 0x20e3;\n\nconst EMOJI_CHAR = /[\\p{Emoji}\\p{Extended_Pictographic}]/u;\n// Presented as an emoji without U+FE0F: by default, or (unassigned in this\n// runtime's Unicode) as every emoji added since Unicode 9 is.\nconst EMOJI_PRESENTATION = new RegExp(\n String.raw`\\p{Emoji_Presentation}|${UNASSIGNED_PICTOGRAPHIC}`,\n \"u\",\n);\nconst EMOJI_MODIFIER = /\\p{Emoji_Modifier}/u;\n\n/**\n * An emoji's code points in its fully-qualified form (UTS #51), which names\n * its image in every style: U+FE0F after each element that is text by default\n * (©️, the ♂️ in 🏃‍♂️, the 🏳️ in 🏳️‍🌈, the 1️ in 1️⃣), unless an emoji modifier\n * follows it (☝🏽).\n */\nfunction qualifiedCodePoints(emoji: string): number[] {\n const chars = [...emoji].filter((c) => c.codePointAt(0) !== FE0F);\n const codePoints: number[] = [];\n chars.forEach((char, i) => {\n codePoints.push(char.codePointAt(0)!);\n const startsElement = i === 0 || chars[i - 1] === \"\\u200D\";\n if (\n startsElement &&\n EMOJI_CHAR.test(char) &&\n !EMOJI_PRESENTATION.test(char) &&\n !EMOJI_MODIFIER.test(chars[i + 1] ?? \"\")\n ) {\n codePoints.push(FE0F);\n }\n });\n return codePoints;\n}\n\nfunction hex(codePoints: number[], pad = 0): string {\n return codePoints.map((cp) => cp.toString(16).padStart(pad, \"0\")).join(\"-\");\n}\n\n/**\n * Twemoji's file name: lowercase hex code points, with U+FE0F dropped unless\n * the emoji is a ZWJ sequence (its own `grabTheRightIcon` rule), and from\n * 👁️‍🗨️, the one ZWJ sequence it names without them.\n */\nfunction twemojiCode(codePoints: number[]): string {\n const code = hex(\n codePoints.includes(ZWJ)\n ? codePoints\n : codePoints.filter((cp) => cp !== FE0F),\n );\n return code === \"1f441-fe0f-200d-1f5e8-fe0f\" ? \"1f441-200d-1f5e8\" : code;\n}\n\n/**\n * Svgmoji's file name (OpenMoji, Blobmoji and Noto): Emojibase hexcodes,\n * uppercase and padded to four digits, with U+FE0F kept only in ZWJ and\n * keycap sequences.\n */\nfunction svgmojiCode(codePoints: number[]): string {\n const keepFE0F = codePoints.includes(ZWJ) || codePoints.includes(KEYCAP);\n return hex(\n keepFE0F ? codePoints : codePoints.filter((cp) => cp !== FE0F),\n 4,\n ).toUpperCase();\n}\n\n/**\n * Fluent's file name: the fully-qualified emoji itself. Its hex names are\n * inconsistent about U+FE0F (`1f590-fe0f`, but `2764-200d-1f525`), so they\n * miss emoji that the glyph names cover.\n */\nfunction fluentCode(codePoints: number[]): string {\n return encodeURIComponent(String.fromCodePoint(...codePoints));\n}\n\nconst emojiUrls: Record<EmojiStyle, (codePoints: number[]) => string> = {\n twemoji: (cps) =>\n `https://cdnjs.cloudflare.com/ajax/libs/twemoji/16.0.1/svg/${twemojiCode(cps)}.svg`,\n openmoji: (cps) =>\n `https://cdn.jsdelivr.net/npm/@svgmoji/openmoji@2.0.0/svg/${svgmojiCode(cps)}.svg`,\n blobmoji: (cps) =>\n `https://cdn.jsdelivr.net/npm/@svgmoji/blob@2.0.0/svg/${svgmojiCode(cps)}.svg`,\n noto: (cps) =>\n `https://cdn.jsdelivr.net/gh/svgmoji/svgmoji/packages/svgmoji__noto/svg/${svgmojiCode(cps)}.svg`,\n fluent: (cps) =>\n `https://cdn.jsdelivr.net/gh/shuding/fluentui-emoji-unicode/assets/${fluentCode(cps)}_color.svg`,\n fluentFlat: (cps) =>\n `https://cdn.jsdelivr.net/gh/shuding/fluentui-emoji-unicode/assets/${fluentCode(cps)}_flat.svg`,\n};\n\n/**\n * The URL of an emoji's SVG image in a style. The emoji may be fully,\n * minimally or not qualified (🏳️‍🌈, or the unqualified 🏳‍🌈): each style names its images\n * after the fully-qualified form, in its own way.\n *\n * @param style - The emoji style\n * @param emoji - One emoji grapheme cluster\n */\nexport function emojiUrl(style: EmojiStyle, emoji: string): string {\n return emojiUrls[style](qualifiedCodePoints(emoji));\n}\n\nconst emojiCache: Record<string, Promise<string>> = {};\n\n/**\n * Fetch an emoji's SVG image in a style, once per URL.\n *\n * @param style - The emoji style\n * @param emoji - One emoji grapheme cluster\n */\nexport async function loadEmoji(\n style: EmojiStyle,\n emoji: string,\n): Promise<string> {\n const url = emojiUrl(style, emoji);\n return (emojiCache[url] ??= fetch(url).then((r) => r.text()));\n}\n","import type { SKRSContext2D } from \"@effing/skia\";\n\nimport type { EmojiStyle } from \"../emoji.ts\";\nimport { cachedLoadImage } from \"../../image.ts\";\nimport type { LayoutNode } from \"../layout.ts\";\nimport type { RenderContext } from \"../context.ts\";\nimport { layoutText } from \"../text/index.ts\";\nimport { applyClip, hasRadius, roundedRect } from \"./clip.ts\";\nimport { applyClipPath } from \"./clip-path.ts\";\nimport { createGradientFromCSS, splitGradientArgs } from \"./gradient.ts\";\nimport {\n beginElementGroup,\n drawBackdropFilter,\n endElementGroup,\n} from \"./group.ts\";\nimport { drawImage } from \"./image.ts\";\nimport { computeContain, computeCover } from \"./object-fit.ts\";\nimport { drawBoxShadow, drawRect, getBorderRadiusFromStyle } from \"./rect.ts\";\nimport { drawSvgContainer } from \"./svg/index.ts\";\nimport { drawText } from \"./text.ts\";\nimport { parseCSSLength, resolveBoxValue } from \"./utils.ts\";\n\n/**\n * Main draw dispatcher: recursively draws the layout tree onto the canvas.\n *\n * Every node, scaled or not, is drawn straight through its transform. Text is\n * drawn unhinted and unsnapped (see `drawText`), so it lands in the same place\n * at any scale and a scaled subtree needs no supersampled offscreen buffer.\n */\nexport async function drawNode(\n ctx: SKRSContext2D,\n node: LayoutNode,\n parentX: number,\n parentY: number,\n context?: RenderContext,\n emojiStyle?: EmojiStyle,\n): Promise<void> {\n const x = parentX + node.x;\n const y = parentY + node.y;\n const { style } = node;\n\n // Resolve a context once so the whole subtree shares one image cache.\n const renderContext: RenderContext = context ?? {\n imageCache: new Map(),\n debug: false,\n };\n\n if (style.display === \"none\") return;\n\n // A numeric string counts, as it does in CSS; anything that isn't a\n // number leaves the element opaque.\n const rawOpacity = Number(style.opacity ?? 1);\n const opacity = Number.isFinite(rawOpacity) ? rawOpacity : 1;\n if (opacity <= 0) return;\n\n // Painting awaits image loads, which can fail. The group and the save are\n // closed either way, so a caller that catches the error and draws the next\n // frame on this context doesn't paint into a layer left open.\n const group = { open: false };\n ctx.save();\n try {\n await paintNode(ctx, node, x, y, opacity, renderContext, emojiStyle, group);\n } finally {\n if (group.open) endElementGroup(ctx);\n ctx.restore();\n }\n}\n\n/** Paints a node inside the save that `drawNode` opened for it. */\nasync function paintNode(\n ctx: SKRSContext2D,\n node: LayoutNode,\n x: number,\n y: number,\n opacity: number,\n renderContext: RenderContext,\n emojiStyle: EmojiStyle | undefined,\n group: { open: boolean },\n): Promise<void> {\n const { width, height, style } = node;\n\n if (style.transform) {\n applyTransform(\n ctx,\n style.transform,\n x,\n y,\n width,\n height,\n style.transformOrigin,\n );\n }\n\n // Apply clip-path — in the element's own (transformed) coordinate space, and\n // before anything is painted, since it clips the element's entire rendering\n // including its box-shadow.\n if (style.clipPath) {\n applyClipPath(ctx, style.clipPath, style, x, y, width, height);\n }\n\n const borderRadius = getBorderRadiusFromStyle(style, width, height);\n\n // Filter the backdrop behind the border box before anything of the element\n // itself is painted: its box-shadow must not end up in the backdrop, and its\n // background composites on top of the filtered result.\n if (style.backdropFilter) {\n drawBackdropFilter(\n ctx,\n style.backdropFilter,\n x,\n y,\n width,\n height,\n borderRadius,\n opacity,\n );\n }\n\n // The element's own painting and its descendants form one group, composited\n // with its opacity and filter. CSS applies clip-path after the filter, so the\n // clip above also clips the filtered result. The backdrop above stays outside\n // the group: a group's backdrop is read from the enclosing one.\n group.open = beginElementGroup(ctx, opacity, style.filter);\n\n // Draw box-shadow BEFORE overflow clip — CSS overflow:hidden clips children,\n // not the element's own box-shadow.\n if (style.boxShadow) {\n drawBoxShadow(ctx, x, y, width, height, style.boxShadow, borderRadius);\n }\n\n // Apply clipping for overflow: hidden\n const isClipped =\n style.overflow === \"hidden\" ||\n style.overflowX === \"hidden\" ||\n style.overflowY === \"hidden\";\n\n if (isClipped) {\n applyClip(ctx, x, y, width, height, borderRadius);\n }\n\n // Draw background and borders\n if (\n style.backgroundColor ||\n style.borderTopWidth ||\n style.borderRightWidth ||\n style.borderBottomWidth ||\n style.borderLeftWidth\n ) {\n drawRect(ctx, x, y, width, height, style);\n }\n\n // Draw background-image (gradient or url) — supports multiple comma-separated layers\n if (style.backgroundImage) {\n const layers = splitGradientArgs(style.backgroundImage);\n // CSS paints last layer first (bottommost)\n for (let i = layers.length - 1; i >= 0; i--) {\n const layer = layers[i]!.trim();\n const gradient = createGradientFromCSS(ctx, layer, x, y, width, height);\n if (gradient) {\n ctx.fillStyle = gradient;\n if (hasRadius(borderRadius)) {\n ctx.beginPath();\n roundedRect(\n ctx,\n x,\n y,\n width,\n height,\n borderRadius.topLeft,\n borderRadius.topRight,\n borderRadius.bottomRight,\n borderRadius.bottomLeft,\n );\n ctx.fill();\n } else {\n ctx.fillRect(x, y, width, height);\n }\n } else {\n // Try url(...) background image\n const urlMatch = layer.match(/url\\([\"']?(.*?)[\"']?\\)/);\n if (urlMatch) {\n if (hasRadius(borderRadius)) {\n applyClip(ctx, x, y, width, height, borderRadius);\n }\n\n const image = await cachedLoadImage(\n renderContext.imageCache,\n urlMatch[1]!,\n renderContext.userAgent,\n );\n const bgSize = style.backgroundSize;\n\n if (bgSize === \"cover\") {\n // Cover fills the box completely — no tiling needed\n const r = computeCover(\n image.width,\n image.height,\n x,\n y,\n width,\n height,\n );\n ctx.drawImage(\n image,\n r.sx,\n r.sy,\n r.sw,\n r.sh,\n r.dx,\n r.dy,\n r.dw,\n r.dh,\n );\n } else {\n // Compute tile dimensions based on backgroundSize\n let tileW: number, tileH: number;\n if (bgSize === \"contain\") {\n const r = computeContain(\n image.width,\n image.height,\n 0,\n 0,\n width,\n height,\n );\n tileW = r.dw;\n tileH = r.dh;\n } else if (bgSize === \"100% 100%\") {\n tileW = width;\n tileH = height;\n } else {\n // CSS default (auto): natural image size\n tileW = image.width;\n tileH = image.height;\n }\n const repeat = style.backgroundRepeat ?? \"repeat\";\n const stepX =\n repeat === \"repeat\" || repeat === \"repeat-x\" ? tileW : width;\n const stepY =\n repeat === \"repeat\" || repeat === \"repeat-y\" ? tileH : height;\n for (let ty = y; ty < y + height; ty += stepY) {\n for (let tx = x; tx < x + width; tx += stepX) {\n ctx.drawImage(image, tx, ty, tileW, tileH);\n }\n }\n }\n }\n }\n }\n }\n\n // Debug: draw bounding boxes\n if (renderContext.debug) {\n ctx.strokeStyle = \"rgba(255, 0, 0, 0.5)\";\n ctx.lineWidth = 1;\n ctx.strokeRect(x, y, width, height);\n }\n\n // Draw text content\n if (node.textContent !== undefined && node.textContent !== \"\") {\n const paddingTop = resolveBoxValue(style.paddingTop, width);\n const paddingLeft = resolveBoxValue(style.paddingLeft, width);\n const paddingRight = resolveBoxValue(style.paddingRight, width);\n\n const borderTopW = resolveBoxValue(style.borderTopWidth, width);\n const borderLeftW = resolveBoxValue(style.borderLeftWidth, width);\n const borderRightW = resolveBoxValue(style.borderRightWidth, width);\n\n const contentX = x + paddingLeft + borderLeftW;\n const contentY = y + paddingTop + borderTopW;\n const contentWidth =\n width - paddingLeft - paddingRight - borderLeftW - borderRightW;\n\n // Text nodes come laid out at their width from the layout phase.\n const textLayout =\n node.textLayout && contentWidth === node.width\n ? node.textLayout\n : layoutText(node.textContent, style, contentWidth, !!emojiStyle);\n await drawText(\n ctx,\n textLayout,\n contentX,\n contentY,\n style.textShadow,\n emojiStyle,\n );\n }\n\n // Draw <img> elements\n if (node.type === \"img\" && node.props.src) {\n const paddingTop = resolveBoxValue(style.paddingTop, width);\n const paddingLeft = resolveBoxValue(style.paddingLeft, width);\n const paddingRight = resolveBoxValue(style.paddingRight, width);\n const paddingBottom = resolveBoxValue(style.paddingBottom, width);\n\n const borderTopW = resolveBoxValue(style.borderTopWidth, width);\n const borderLeftW = resolveBoxValue(style.borderLeftWidth, width);\n const borderRightW = resolveBoxValue(style.borderRightWidth, width);\n const borderBottomW = resolveBoxValue(style.borderBottomWidth, width);\n\n const imgX = x + paddingLeft + borderLeftW;\n const imgY = y + paddingTop + borderTopW;\n const imgW =\n width - paddingLeft - paddingRight - borderLeftW - borderRightW;\n const imgH =\n height - paddingTop - paddingBottom - borderTopW - borderBottomW;\n\n // Images are replaced content — borderRadius clips them directly\n // (unlike child content which requires overflow:hidden)\n if (!isClipped) {\n if (hasRadius(borderRadius)) {\n applyClip(ctx, imgX, imgY, imgW, imgH, borderRadius);\n }\n }\n\n await drawImage(\n ctx,\n node.props.src as string | Buffer,\n imgX,\n imgY,\n imgW,\n imgH,\n renderContext,\n style,\n );\n }\n\n // Draw <svg> containers (handle their own child traversal in SVG coordinate space)\n if (node.type === \"svg\") {\n drawSvgContainer(ctx, node, x, y, width, height);\n } else {\n for (const child of node.children) {\n await drawNode(ctx, child, x, y, renderContext, emojiStyle);\n }\n }\n}\n\nfunction applyTransform(\n ctx: SKRSContext2D,\n transform: string,\n x: number,\n y: number,\n width: number,\n height: number,\n transformOrigin?: string,\n): void {\n // Resolve transform-origin (default: center)\n let ox = x + width / 2;\n let oy = y + height / 2;\n\n if (transformOrigin) {\n const parts = transformOrigin.split(/\\s+/);\n ox = resolveOrigin(parts[0], x, width);\n oy = resolveOrigin(parts[1], y, height);\n }\n\n ctx.translate(ox, oy);\n\n // Parse and apply transform functions\n const funcs = transform.matchAll(/(\\w+)\\(([^)]+)\\)/g);\n\n for (const [, name, args] of funcs) {\n const values = args!.split(\",\").map((s) => s.trim());\n\n switch (name) {\n case \"translate\":\n case \"translateX\":\n case \"translateY\": {\n const tx =\n name === \"translateY\" ? 0 : parseCSSLength(values[0]!, width);\n const ty =\n name === \"translateX\"\n ? 0\n : parseCSSLength(\n values[name === \"translate\" ? 1 : 0] ?? \"0\",\n height,\n );\n ctx.translate(tx, ty);\n break;\n }\n case \"scale\":\n case \"scaleX\":\n case \"scaleY\": {\n const sx = name === \"scaleY\" ? 1 : parseFloat(values[0]!);\n const sy =\n name === \"scaleX\"\n ? 1\n : parseFloat(values[name === \"scale\" ? 1 : 0] ?? String(sx));\n ctx.scale(sx, sy);\n break;\n }\n case \"rotate\": {\n const angle = parseAngle(values[0]!);\n ctx.rotate(angle);\n break;\n }\n case \"skewX\": {\n const angle = parseAngle(values[0]!);\n ctx.transform(1, 0, Math.tan(angle), 1, 0, 0);\n break;\n }\n case \"skewY\": {\n const angle = parseAngle(values[0]!);\n ctx.transform(1, Math.tan(angle), 0, 1, 0, 0);\n break;\n }\n }\n }\n\n ctx.translate(-ox, -oy);\n}\n\nfunction resolveOrigin(\n value: string | undefined,\n base: number,\n size: number,\n): number {\n if (!value) return base + size / 2;\n if (value === \"left\" || value === \"top\") return base;\n if (value === \"right\" || value === \"bottom\") return base + size;\n if (value === \"center\") return base + size / 2;\n return base + parseCSSLength(value, size);\n}\n\nfunction parseAngle(value: string): number {\n if (value.endsWith(\"deg\")) return (parseFloat(value) * Math.PI) / 180;\n if (value.endsWith(\"rad\")) return parseFloat(value);\n if (value.endsWith(\"turn\")) return parseFloat(value) * 2 * Math.PI;\n return parseFloat(value);\n}\n","import { GlobalFonts } from \"@effing/skia\";\n\nimport type { FontData } from \"../types.ts\";\n\nconst registeredFonts = new Set<string>();\n\n/**\n * Reset internal font state (test-only).\n */\nexport function _resetForTest(): void {\n registeredFonts.clear();\n}\n\n/**\n * Register a font from a FontData buffer.\n * Registration is idempotent — re-registering the same font name is a no-op.\n *\n * @param font - Font data to register\n */\nexport function registerFont(font: FontData): void {\n const key = `${font.name}:${font.weight}:${font.style}`;\n if (registeredFonts.has(key)) return;\n\n const buffer = Buffer.isBuffer(font.data)\n ? font.data\n : Buffer.from(font.data);\n\n GlobalFonts.register(buffer, font.name);\n\n registeredFonts.add(key);\n}\n\n/**\n * Register a font from a file path.\n *\n * @param path - Path to the font file\n * @param nameAlias - Optional font family name override\n */\nexport function registerFontFromPath(path: string, nameAlias?: string): void {\n GlobalFonts.registerFromPath(path, nameAlias ?? \"\");\n}\n\n/**\n * Get the list of registered font family names.\n *\n * @returns Array of font family names\n */\nexport function registeredFamilies(): string[] {\n return GlobalFonts.families.map((f: { family: string }) => f.family);\n}\n\n/**\n * Ensure all fonts from the given array are registered.\n * Called internally by `renderReactElement()`.\n */\nexport function ensureFontsRegistered(fonts: FontData[]): void {\n for (const font of fonts) {\n registerFont(font);\n }\n}\n","// This file contains code adapted from Satori (https://github.com/vercel/satori)\n// Licensed under the Mozilla Public License 2.0 (MPL-2.0)\n// See NOTICE.md in the package root for details.\n\nimport { splitGradientArgs } from \"../draw/gradient.ts\";\nimport type { ExpandedStyle } from \"./compute.ts\";\n\ntype RawStyle = Record<string, unknown>;\n\nconst SIDES = [\"Top\", \"Right\", \"Bottom\", \"Left\"] as const;\n\n/**\n * Parse a CSS shorthand value like \"10px 20px\" into 1-4 parts.\n */\nfunction parseSides(value: string): string[] {\n const parts = value.toString().split(/\\s+/).filter(Boolean);\n switch (parts.length) {\n case 1:\n return [parts[0]!, parts[0]!, parts[0]!, parts[0]!];\n case 2:\n return [parts[0]!, parts[1]!, parts[0]!, parts[1]!];\n case 3:\n return [parts[0]!, parts[1]!, parts[2]!, parts[1]!];\n default:\n return [parts[0]!, parts[1]!, parts[2]!, parts[3]!];\n }\n}\n\nfunction parseValue(v: unknown): number | string | undefined {\n if (v === undefined || v === null) return undefined;\n const s = String(v);\n if (s === \"auto\") return \"auto\";\n const n = Number(s);\n if (s !== \"\" && !isNaN(n)) return n;\n return s;\n}\n\n/**\n * Expand CSS shorthand properties into their longhand equivalents.\n * Mutates and returns the style object.\n */\nexport function expandStyle(\n raw: RawStyle,\n fontFamilies?: string[],\n): ExpandedStyle {\n const style = { ...raw } as Record<string, unknown>;\n\n // margin shorthand\n if (style.margin !== undefined) {\n const sides = parseSides(String(style.margin));\n for (let i = 0; i < 4; i++) {\n const key = `margin${SIDES[i]}`;\n if (style[key] === undefined) style[key] = parseValue(sides[i]);\n }\n delete style.margin;\n }\n\n // padding shorthand\n if (style.padding !== undefined) {\n const sides = parseSides(String(style.padding));\n for (let i = 0; i < 4; i++) {\n const key = `padding${SIDES[i]}`;\n if (style[key] === undefined) style[key] = parseValue(sides[i]);\n }\n delete style.padding;\n }\n\n // borderRadius shorthand\n if (style.borderRadius !== undefined) {\n const sides = parseSides(String(style.borderRadius));\n const corners = [\n \"borderTopLeftRadius\",\n \"borderTopRightRadius\",\n \"borderBottomRightRadius\",\n \"borderBottomLeftRadius\",\n ];\n for (let i = 0; i < 4; i++) {\n if (style[corners[i]!] === undefined)\n style[corners[i]!] = parseValue(sides[i]);\n }\n delete style.borderRadius;\n }\n\n // borderWidth shorthand\n if (style.borderWidth !== undefined) {\n const sides = parseSides(String(style.borderWidth));\n for (let i = 0; i < 4; i++) {\n const key = `border${SIDES[i]}Width`;\n if (style[key] === undefined) style[key] = parseValue(sides[i]);\n }\n delete style.borderWidth;\n }\n\n // borderColor shorthand\n if (style.borderColor !== undefined) {\n const val = style.borderColor;\n for (const side of SIDES) {\n const key = `border${side}Color`;\n if (style[key] === undefined) style[key] = val;\n }\n delete style.borderColor;\n }\n\n // borderStyle shorthand\n if (style.borderStyle !== undefined) {\n const val = style.borderStyle;\n for (const side of SIDES) {\n const key = `border${side}Style`;\n if (style[key] === undefined) style[key] = val;\n }\n delete style.borderStyle;\n }\n\n // border shorthand (e.g. \"1px solid black\")\n if (style.border !== undefined) {\n const parts = String(style.border).split(/\\s+/);\n const width = parseValue(parts[0]);\n const borderStyle = parts[1] ?? \"solid\";\n const color = parts[2] ?? \"black\";\n for (const side of SIDES) {\n if (style[`border${side}Width`] === undefined)\n style[`border${side}Width`] = width;\n if (style[`border${side}Style`] === undefined)\n style[`border${side}Style`] = borderStyle;\n if (style[`border${side}Color`] === undefined)\n style[`border${side}Color`] = color;\n }\n delete style.border;\n }\n\n // Per-side border shorthands (e.g. borderLeft: \"3px solid white\")\n for (const side of SIDES) {\n const key = `border${side}`;\n if (style[key] !== undefined) {\n const parts = String(style[key]).split(/\\s+/);\n const width = parseValue(parts[0]);\n const borderStyle = parts[1] ?? \"solid\";\n const color = parts[2] ?? \"black\";\n if (style[`${key}Width`] === undefined) style[`${key}Width`] = width;\n if (style[`${key}Style`] === undefined)\n style[`${key}Style`] = borderStyle;\n if (style[`${key}Color`] === undefined) style[`${key}Color`] = color;\n delete style[key];\n }\n }\n\n // flex shorthand\n if (style.flex !== undefined) {\n const val = String(style.flex);\n if (val === \"none\") {\n if (style.flexGrow === undefined) style.flexGrow = 0;\n if (style.flexShrink === undefined) style.flexShrink = 0;\n if (style.flexBasis === undefined) style.flexBasis = \"auto\";\n } else {\n const parts = val.split(/\\s+/);\n if (parts.length === 1) {\n const n = parseFloat(parts[0]!);\n if (!isNaN(n)) {\n if (style.flexGrow === undefined) style.flexGrow = n;\n if (style.flexShrink === undefined) style.flexShrink = 1;\n if (style.flexBasis === undefined) style.flexBasis = 0;\n }\n } else if (parts.length === 2) {\n if (style.flexGrow === undefined)\n style.flexGrow = parseFloat(parts[0]!);\n if (style.flexShrink === undefined)\n style.flexShrink = parseFloat(parts[1]!);\n } else if (parts.length >= 3) {\n if (style.flexGrow === undefined)\n style.flexGrow = parseFloat(parts[0]!);\n if (style.flexShrink === undefined)\n style.flexShrink = parseFloat(parts[1]!);\n if (style.flexBasis === undefined)\n style.flexBasis = parseValue(parts[2]);\n }\n }\n delete style.flex;\n }\n\n // gap shorthand\n if (style.gap !== undefined) {\n const sides = parseSides(String(style.gap));\n if (style.rowGap === undefined) style.rowGap = parseValue(sides[0]);\n if (style.columnGap === undefined) style.columnGap = parseValue(sides[1]);\n delete style.gap;\n }\n\n // background shorthand\n if (style.background !== undefined) {\n const parts = parseBackgroundShorthand(String(style.background));\n if (parts.image !== undefined && style.backgroundImage === undefined)\n style.backgroundImage = parts.image;\n if (parts.repeat !== undefined && style.backgroundRepeat === undefined)\n style.backgroundRepeat = parts.repeat;\n if (parts.size !== undefined && style.backgroundSize === undefined)\n style.backgroundSize = parts.size;\n if (parts.color !== undefined && style.backgroundColor === undefined)\n style.backgroundColor = parts.color;\n delete style.background;\n }\n\n // overflow shorthand\n if (style.overflow !== undefined) {\n if (style.overflowX === undefined) style.overflowX = style.overflow;\n if (style.overflowY === undefined) style.overflowY = style.overflow;\n }\n\n // textBox shorthand (e.g. \"trim-both cap alphabetic\")\n if (style.textBox !== undefined) {\n const val = String(style.textBox);\n if (val === \"normal\" || val === \"none\") {\n style.textBoxTrim ??= \"none\";\n } else {\n const parts = val.split(/\\s+/);\n style.textBoxTrim ??= parts[0];\n if (parts.length > 1) {\n style.textBoxEdge ??= parts.slice(1).join(\" \");\n }\n }\n delete style.textBox;\n }\n\n // WebkitTextStroke shorthand (e.g. \"2px red\")\n if (style.WebkitTextStroke !== undefined) {\n const val = String(style.WebkitTextStroke).trim();\n const match = val.match(/^(\\S+)\\s+(.+)$/);\n if (match) {\n if (style.WebkitTextStrokeWidth === undefined)\n style.WebkitTextStrokeWidth = parseValue(match[1]);\n if (style.WebkitTextStrokeColor === undefined)\n style.WebkitTextStrokeColor = match[2];\n } else {\n // Single value — treat as width\n if (style.WebkitTextStrokeWidth === undefined)\n style.WebkitTextStrokeWidth = parseValue(val);\n }\n delete style.WebkitTextStroke;\n }\n\n // Vendor-prefixed aliases\n if (style.WebkitBackdropFilter !== undefined) {\n if (style.backdropFilter === undefined)\n style.backdropFilter = style.WebkitBackdropFilter;\n delete style.WebkitBackdropFilter;\n }\n // `word-wrap` is the legacy name of `overflow-wrap`.\n if (style.wordWrap !== undefined) {\n if (style.overflowWrap === undefined) style.overflowWrap = style.wordWrap;\n delete style.wordWrap;\n }\n if (style.WebkitClipPath !== undefined) {\n if (style.clipPath === undefined) style.clipPath = style.WebkitClipPath;\n delete style.WebkitClipPath;\n }\n\n // fontFamily normalization\n if (typeof style.fontFamily === \"string\") {\n const families = style.fontFamily\n .split(\",\")\n .map((s) => s.trim().replace(/^['\"]|['\"]$/g, \"\"))\n .filter(Boolean);\n if (fontFamilies) {\n const present = new Set(families);\n for (const name of fontFamilies) {\n if (!present.has(name)) families.push(name);\n }\n }\n style.fontFamily = families.join(\", \");\n }\n\n return style as unknown as ExpandedStyle;\n}\n\nconst BG_REPEAT_KEYWORDS = new Set([\n \"repeat\",\n \"no-repeat\",\n \"repeat-x\",\n \"repeat-y\",\n \"space\",\n \"round\",\n]);\nconst BG_POSITION_KEYWORDS = new Set([\n \"left\",\n \"right\",\n \"top\",\n \"bottom\",\n \"center\",\n]);\nconst BG_ATTACHMENT_KEYWORDS = new Set([\"scroll\", \"fixed\", \"local\"]);\nconst BG_BOX_KEYWORDS = new Set([\"border-box\", \"padding-box\", \"content-box\"]);\nconst BG_IMAGE_FN =\n /^(?:url|image-set|(?:repeating-)?(?:linear|radial|conic)-gradient)\\(/;\n\n// Whitespace-tokenize a CSS value, keeping balanced-paren blocks intact and\n// emitting `/` as its own token (the position/size separator).\nfunction tokenizeBackground(value: string): string[] {\n const tokens: string[] = [];\n let buf = \"\";\n for (let i = 0; i < value.length; i++) {\n const c = value[i]!;\n if (c === \"(\") {\n let depth = 1;\n buf += c;\n i++;\n while (i < value.length && depth > 0) {\n const ch = value[i]!;\n if (ch === \"(\") depth++;\n else if (ch === \")\") depth--;\n buf += ch;\n i++;\n }\n i--;\n } else if (/\\s/.test(c)) {\n if (buf) {\n tokens.push(buf);\n buf = \"\";\n }\n } else if (c === \"/\") {\n if (buf) {\n tokens.push(buf);\n buf = \"\";\n }\n tokens.push(\"/\");\n } else {\n buf += c;\n }\n }\n if (buf) tokens.push(buf);\n return tokens;\n}\n\ninterface BackgroundParts {\n image?: string;\n repeat?: string;\n size?: string;\n color?: string;\n}\n\nfunction parseLayer(value: string): BackgroundParts {\n const out: BackgroundParts = {};\n const sizeTokens: string[] = [];\n let afterSlash = false;\n for (const tok of tokenizeBackground(value)) {\n if (tok === \"/\") {\n afterSlash = true;\n continue;\n }\n if (afterSlash) {\n sizeTokens.push(tok);\n continue;\n }\n if (BG_IMAGE_FN.test(tok)) {\n out.image = tok;\n continue;\n }\n if (tok === \"none\") continue;\n if (BG_REPEAT_KEYWORDS.has(tok)) {\n out.repeat = tok;\n continue;\n }\n // Position/attachment/box/length tokens are recognized so they don't fall\n // through and get treated as colors; the renderer doesn't honor them yet.\n if (\n BG_POSITION_KEYWORDS.has(tok) ||\n BG_ATTACHMENT_KEYWORDS.has(tok) ||\n BG_BOX_KEYWORDS.has(tok) ||\n /^-?\\d/.test(tok)\n ) {\n continue;\n }\n out.color = tok;\n }\n if (sizeTokens.length > 0) out.size = sizeTokens.join(\" \");\n return out;\n}\n\n/**\n * Parse the CSS `background` shorthand into image/repeat/size/color longhands.\n * For multi-layer values, image is comma-joined and color is taken only from\n * the final layer (the only layer permitted a color per the CSS spec).\n */\nexport function parseBackgroundShorthand(value: string): BackgroundParts {\n const layers = splitGradientArgs(value).map((l) => l.trim());\n if (layers.length <= 1) return parseLayer(layers[0] ?? \"\");\n\n const parsed = layers.map(parseLayer);\n const out: BackgroundParts = {};\n const images = parsed.map((p) => p.image ?? \"none\");\n if (images.some((i) => i !== \"none\")) out.image = images.join(\", \");\n for (const p of parsed) {\n if (p.repeat !== undefined && out.repeat === undefined)\n out.repeat = p.repeat;\n if (p.size !== undefined && out.size === undefined) out.size = p.size;\n }\n const finalColor = parsed[parsed.length - 1]?.color;\n if (finalColor !== undefined) out.color = finalColor;\n return out;\n}\n","import Yoga, {\n Align,\n Display,\n Edge,\n FlexDirection,\n Gutter,\n Justify,\n MeasureMode,\n Overflow,\n PositionType,\n Wrap,\n} from \"yoga-layout\";\nimport type { Node as YogaNode } from \"yoga-layout\";\n\nexport type { YogaNode };\n\nexport {\n Yoga,\n Align,\n Display,\n Edge,\n FlexDirection,\n Gutter,\n Justify,\n MeasureMode,\n Overflow,\n PositionType,\n Wrap,\n};\n\nexport function createYogaNode(): YogaNode {\n return Yoga.Node.create();\n}\n\nlet textConfig: ReturnType<typeof Yoga.Config.create> | undefined;\n\n/**\n * A node for text, whose layout Yoga leaves unrounded (its parents are still\n * rounded to whole pixels). Its width is then the width the text was measured\n * at, which it's drawn at too, so a line that just fits stays on one line,\n * and a line that doesn't wraps, as in a browser.\n */\nexport function createTextYogaNode(): YogaNode {\n if (!textConfig) {\n textConfig = Yoga.Config.create();\n textConfig.setPointScaleFactor(0);\n }\n return Yoga.Node.create(textConfig);\n}\n\nexport function freeYogaNode(node: YogaNode): void {\n node.freeRecursive();\n}\n","import {\n Align,\n Display,\n Edge,\n FlexDirection,\n Gutter,\n Justify,\n Overflow,\n PositionType,\n Wrap,\n} from \"../yoga.ts\";\nimport type { YogaNode } from \"../yoga.ts\";\nimport type { ComputedStyle } from \"./compute.ts\";\n\n/**\n * Apply computed CSS styles to a Yoga node.\n */\nexport function applyStylesToYoga(node: YogaNode, style: ComputedStyle): void {\n // Display\n if (style.display === \"none\") {\n node.setDisplay(Display.None);\n } else {\n node.setDisplay(Display.Flex);\n }\n\n // Flex direction (CSS default is \"row\", Yoga defaults to \"column\")\n {\n const map: Record<string, FlexDirection> = {\n row: FlexDirection.Row,\n \"row-reverse\": FlexDirection.RowReverse,\n column: FlexDirection.Column,\n \"column-reverse\": FlexDirection.ColumnReverse,\n };\n node.setFlexDirection(\n map[style.flexDirection ?? \"row\"] ?? FlexDirection.Row,\n );\n }\n\n // Justify content\n if (style.justifyContent) {\n const map: Record<string, Justify> = {\n \"flex-start\": Justify.FlexStart,\n \"flex-end\": Justify.FlexEnd,\n center: Justify.Center,\n \"space-between\": Justify.SpaceBetween,\n \"space-around\": Justify.SpaceAround,\n \"space-evenly\": Justify.SpaceEvenly,\n };\n const jc = map[style.justifyContent];\n if (jc !== undefined) node.setJustifyContent(jc);\n }\n\n // Align items.\n // NOTE: `baseline` does NOT produce typographic baseline alignment. The\n // bundled yoga-layout JS binding exposes no baseline function, so Yoga falls\n // back to a node's height as its baseline — which aligns box bottoms (the\n // same result as `flex-end`), correct only when all children share a font\n // size. The README documents this limitation; don't re-advertise it as full\n // baseline support without a real fix, since the engine can't express it.\n if (style.alignItems) {\n const map: Record<string, Align> = {\n \"flex-start\": Align.FlexStart,\n \"flex-end\": Align.FlexEnd,\n center: Align.Center,\n stretch: Align.Stretch,\n baseline: Align.Baseline,\n };\n const ai = map[style.alignItems];\n if (ai !== undefined) node.setAlignItems(ai);\n }\n\n // Align self (`baseline` carries the same box-bottom caveat as alignItems)\n if (style.alignSelf) {\n const map: Record<string, Align> = {\n auto: Align.Auto,\n \"flex-start\": Align.FlexStart,\n \"flex-end\": Align.FlexEnd,\n center: Align.Center,\n stretch: Align.Stretch,\n baseline: Align.Baseline,\n };\n const as_ = map[style.alignSelf];\n if (as_ !== undefined) node.setAlignSelf(as_);\n }\n\n // Align content\n if (style.alignContent) {\n const map: Record<string, Align> = {\n \"flex-start\": Align.FlexStart,\n \"flex-end\": Align.FlexEnd,\n center: Align.Center,\n stretch: Align.Stretch,\n \"space-between\": Align.SpaceBetween,\n \"space-around\": Align.SpaceAround,\n };\n const ac = map[style.alignContent];\n if (ac !== undefined) node.setAlignContent(ac);\n }\n\n // Flex wrap\n if (style.flexWrap) {\n const map: Record<string, Wrap> = {\n nowrap: Wrap.NoWrap,\n wrap: Wrap.Wrap,\n \"wrap-reverse\": Wrap.WrapReverse,\n };\n const fw = map[style.flexWrap];\n if (fw !== undefined) node.setFlexWrap(fw);\n }\n\n // Flex grow / shrink / basis\n if (style.flexGrow !== undefined) node.setFlexGrow(style.flexGrow);\n // Satori defaults flexShrink to 0 (React Native convention); match it for compatibility\n node.setFlexShrink(style.flexShrink ?? 0);\n if (style.flexBasis !== undefined) {\n if (typeof style.flexBasis === \"number\") {\n node.setFlexBasis(style.flexBasis);\n } else if (String(style.flexBasis).endsWith(\"%\")) {\n node.setFlexBasis(String(style.flexBasis) as `${number}%`);\n } else if (style.flexBasis === \"auto\") {\n node.setFlexBasis(\"auto\");\n } else {\n const n = parseFloat(String(style.flexBasis));\n if (!isNaN(n)) node.setFlexBasis(n);\n }\n }\n\n // Dimensions\n applyDimension(node, \"setWidth\", style.width);\n applyDimension(node, \"setHeight\", style.height);\n applyDimension(node, \"setMinWidth\", style.minWidth);\n applyDimension(node, \"setMinHeight\", style.minHeight);\n applyDimension(node, \"setMaxWidth\", style.maxWidth);\n applyDimension(node, \"setMaxHeight\", style.maxHeight);\n\n // Position\n if (style.position === \"absolute\") {\n node.setPositionType(PositionType.Absolute);\n } else {\n node.setPositionType(PositionType.Relative);\n }\n\n // Position edges\n applyEdgeValue(node, \"setPosition\", Edge.Top, style.top);\n applyEdgeValue(node, \"setPosition\", Edge.Right, style.right);\n applyEdgeValue(node, \"setPosition\", Edge.Bottom, style.bottom);\n applyEdgeValue(node, \"setPosition\", Edge.Left, style.left);\n\n // Margin\n applyEdgeValue(node, \"setMargin\", Edge.Top, style.marginTop);\n applyEdgeValue(node, \"setMargin\", Edge.Right, style.marginRight);\n applyEdgeValue(node, \"setMargin\", Edge.Bottom, style.marginBottom);\n applyEdgeValue(node, \"setMargin\", Edge.Left, style.marginLeft);\n\n // Padding\n applyEdgeValue(node, \"setPadding\", Edge.Top, style.paddingTop);\n applyEdgeValue(node, \"setPadding\", Edge.Right, style.paddingRight);\n applyEdgeValue(node, \"setPadding\", Edge.Bottom, style.paddingBottom);\n applyEdgeValue(node, \"setPadding\", Edge.Left, style.paddingLeft);\n\n // Border width (resolved to numbers by resolveUnits before this point)\n if (style.borderTopWidth !== undefined)\n node.setBorder(Edge.Top, style.borderTopWidth as number);\n if (style.borderRightWidth !== undefined)\n node.setBorder(Edge.Right, style.borderRightWidth as number);\n if (style.borderBottomWidth !== undefined)\n node.setBorder(Edge.Bottom, style.borderBottomWidth as number);\n if (style.borderLeftWidth !== undefined)\n node.setBorder(Edge.Left, style.borderLeftWidth as number);\n\n // Gap\n if (style.rowGap !== undefined) node.setGap(Gutter.Row, style.rowGap);\n if (style.columnGap !== undefined)\n node.setGap(Gutter.Column, style.columnGap);\n\n // Overflow\n if (\n style.overflow === \"hidden\" ||\n style.overflowX === \"hidden\" ||\n style.overflowY === \"hidden\"\n ) {\n node.setOverflow(Overflow.Hidden);\n } else {\n node.setOverflow(Overflow.Visible);\n }\n}\n\nfunction applyDimension(\n node: YogaNode,\n setter:\n | \"setWidth\"\n | \"setHeight\"\n | \"setMinWidth\"\n | \"setMinHeight\"\n | \"setMaxWidth\"\n | \"setMaxHeight\",\n value: number | string | undefined,\n): void {\n if (value === undefined) return;\n if (value === \"auto\") {\n if (setter === \"setWidth\" || setter === \"setHeight\") {\n node[setter](\"auto\");\n }\n return;\n }\n if (typeof value === \"number\") {\n node[setter](value);\n return;\n }\n const s = String(value);\n if (s.endsWith(\"%\")) {\n node[setter](s as `${number}%`);\n } else {\n const n = parseFloat(s);\n if (!isNaN(n)) node[setter](n);\n }\n}\n\nfunction applyEdgeValue(\n node: YogaNode,\n setter: \"setMargin\" | \"setPadding\" | \"setPosition\",\n edge: Edge,\n value: number | string | undefined,\n): void {\n if (value === undefined) return;\n if (value === \"auto\" && setter === \"setMargin\") {\n node.setMargin(edge, \"auto\");\n return;\n }\n if (typeof value === \"number\") {\n node[setter](edge, value);\n return;\n }\n const s = String(value);\n if (s.endsWith(\"%\")) {\n node[setter](edge, s as `${number}%`);\n } else {\n const n = parseFloat(s);\n if (!isNaN(n)) node[setter](edge, n);\n }\n}\n","// This file contains code adapted from Satori (https://github.com/vercel/satori)\n// Licensed under the Mozilla Public License 2.0 (MPL-2.0)\n// See NOTICE.md in the package root for details.\n\nimport type { ReactElement, ReactNode } from \"react\";\n\nimport type { ImageCache } from \"../image.ts\";\nimport { cachedLoadImage } from \"../image.ts\";\nimport type { RenderContext } from \"./context.ts\";\nimport { expandStyle } from \"./style/expand.ts\";\nimport {\n resolveStyle,\n resolveUnit,\n resolveUnits,\n DEFAULT_STYLE,\n} from \"./style/compute.ts\";\nimport type { ComputedStyle } from \"./style/compute.ts\";\nimport { applyStylesToYoga } from \"./style/properties.ts\";\nimport { TextMeasure } from \"./text/index.ts\";\nimport { isWhiteSpaceOnly } from \"./text/white-space.ts\";\nimport type { TextLayoutResult } from \"./text/index.ts\";\nimport {\n createTextYogaNode,\n createYogaNode,\n freeYogaNode,\n FlexDirection,\n MeasureMode,\n} from \"./yoga.ts\";\nimport type { YogaNode } from \"./yoga.ts\";\n\n/**\n * A node in the computed layout tree, ready for drawing.\n */\nexport type LayoutNode = {\n type: string;\n style: ComputedStyle;\n children: LayoutNode[];\n textContent?: string;\n /** The text laid out at the node's width, for drawing. */\n textLayout?: TextLayoutResult;\n props: Record<string, unknown>;\n x: number;\n y: number;\n width: number;\n height: number;\n};\n\n/**\n * Build a layout tree from a React element tree.\n * Creates Yoga nodes, calculates layout, and returns the positioned tree.\n *\n * @param element - React element tree to lay out\n * @param containerWidth - Width of the container (from canvas)\n * @param containerHeight - Height of the container (from canvas)\n * @returns Root layout node with computed positions and dimensions\n */\nexport async function buildLayoutTree(\n element: ReactNode,\n containerWidth: number,\n containerHeight: number,\n emojiEnabled?: boolean,\n fontFamilies?: string[],\n context?: RenderContext,\n): Promise<{ tree: LayoutNode; imageCache: ImageCache }> {\n const renderContext: RenderContext = context ?? {\n imageCache: new Map(),\n debug: false,\n };\n const rootElement = renderComponents(element);\n const elementYogaNode = isText(rootElement)\n ? createTextYogaNode()\n : createYogaNode();\n\n // Set font families as default on root style so all nodes inherit them\n const rootStyle = fontFamilies?.length\n ? { ...DEFAULT_STYLE, fontFamily: fontFamilies.join(\", \") }\n : DEFAULT_STYLE;\n\n // Build the tree\n const elementNode = await buildNode(\n rootElement,\n rootStyle,\n elementYogaNode,\n containerWidth,\n containerHeight,\n emojiEnabled,\n fontFamilies,\n renderContext,\n );\n\n // Wrap the user element in a canvas-sized container (like Satori) so that\n // absolute positioning, percentage sizes, etc. resolve against the canvas.\n const rootYogaNode = createYogaNode();\n rootYogaNode.setWidth(containerWidth);\n rootYogaNode.setHeight(containerHeight);\n rootYogaNode.setFlexDirection(FlexDirection.Row);\n rootYogaNode.insertChild(elementYogaNode, 0);\n\n rootYogaNode.calculateLayout(containerWidth, containerHeight);\n settleText(\n elementNode,\n () => rootYogaNode.calculateLayout(containerWidth, containerHeight),\n renderContext.debug,\n );\n\n const elementLayout = extractLayout(elementNode, elementYogaNode);\n freeYogaNode(rootYogaNode);\n\n const tree: LayoutNode = {\n type: \"div\",\n style: rootStyle,\n children: [elementLayout],\n props: {},\n x: 0,\n y: 0,\n width: containerWidth,\n height: containerHeight,\n };\n return { tree, imageCache: renderContext.imageCache };\n}\n\n/**\n * Build the node for `element` on `yogaNode`. Function components must be\n * rendered first (`renderComponents`), so the caller can make text a text\n * node (`createTextYogaNode`).\n */\nasync function buildNode(\n element: ReactNode,\n parentStyle: ComputedStyle,\n yogaNode: YogaNode,\n viewportWidth: number,\n viewportHeight: number,\n emojiEnabled?: boolean,\n fontFamilies?: string[],\n context?: RenderContext,\n): Promise<IntermediateNode> {\n // Handle null/undefined/boolean\n if (\n element === null ||\n element === undefined ||\n typeof element === \"boolean\"\n ) {\n return {\n type: \"empty\",\n style: parentStyle,\n children: [],\n props: {},\n yogaNode,\n };\n }\n\n // Handle text/number primitives\n if (typeof element === \"string\" || typeof element === \"number\") {\n const text = String(element);\n const style = resolveStyle(undefined, parentStyle);\n\n // Set up text measurement\n const textMeasure = new TextMeasure(text, style, emojiEnabled);\n setTextMeasure(yogaNode, textMeasure);\n\n return {\n type: \"text\",\n style,\n children: [],\n textContent: text,\n textMeasure,\n props: {},\n yogaNode,\n };\n }\n\n // Handle React elements (host elements: components are rendered already)\n const el = element as ReactElement<Record<string, unknown>>;\n const type = el.type;\n\n const props = (el.props ?? {}) as Record<string, unknown>;\n const rawStyle = (props.style ?? {}) as Record<string, unknown>;\n const expanded = expandStyle(rawStyle, fontFamilies);\n const style = resolveStyle(expanded, parentStyle);\n resolveUnits(style, viewportWidth, viewportHeight);\n\n const tagName = String(type);\n\n // For <svg> elements, merge width/height props into style when not set via CSS\n if (tagName === \"svg\") {\n if (props.width != null && style.width === undefined) {\n const v = props.width;\n if (typeof v === \"string\") {\n const resolved = resolveUnit(v, viewportWidth, viewportHeight, 16, 16);\n style.width =\n typeof resolved === \"string\" && resolved.endsWith(\"%\")\n ? resolved\n : Number(resolved);\n } else {\n style.width = Number(v);\n }\n }\n if (props.height != null && style.height === undefined) {\n const v = props.height;\n if (typeof v === \"string\") {\n const resolved = resolveUnit(v, viewportWidth, viewportHeight, 16, 16);\n style.height =\n typeof resolved === \"string\" && resolved.endsWith(\"%\")\n ? resolved\n : Number(resolved);\n } else {\n style.height = Number(v);\n }\n }\n\n // Derive missing dimension from viewBox aspect ratio\n const viewBox = props.viewBox as string | undefined;\n if (viewBox) {\n const parts = viewBox.split(/[\\s,]+/).map(Number);\n if (parts.length === 4) {\n const [, , vbW, vbH] = parts as [number, number, number, number];\n if (vbW > 0 && vbH > 0) {\n const wSet = style.width !== undefined;\n const hSet = style.height !== undefined;\n if (!wSet && !hSet) {\n style.width = vbW;\n style.height = vbH;\n } else if (!hSet && typeof style.width === \"number\") {\n style.height = style.width * (vbH / vbW);\n } else if (!wSet && typeof style.height === \"number\") {\n style.width = style.height * (vbW / vbH);\n }\n // When either/both are %, leave as-is for Yoga\n }\n }\n }\n }\n\n // For <img> elements, derive missing dimensions from intrinsic aspect ratio\n if (tagName === \"img\") {\n // Map HTML width/height attributes to style (like <svg>)\n if (props.width != null && style.width === undefined) {\n const v = props.width;\n style.width = typeof v === \"string\" && v.endsWith(\"%\") ? v : Number(v);\n }\n if (props.height != null && style.height === undefined) {\n const v = props.height;\n style.height = typeof v === \"string\" && v.endsWith(\"%\") ? v : Number(v);\n }\n\n const src = props.src as string | Buffer | undefined;\n if (src) {\n try {\n const image = await cachedLoadImage(\n context?.imageCache ?? new Map(),\n src,\n context?.userAgent,\n );\n const naturalW = image.width;\n const naturalH = image.height;\n\n const wSet = style.width !== undefined;\n const hSet = style.height !== undefined;\n\n if (naturalW > 0 && naturalH > 0 && !(wSet && hSet)) {\n if (!wSet && !hSet) {\n // No dimensions given — fill parent, let aspect ratio derive height.\n style.width = \"100%\";\n }\n yogaNode.setAspectRatio(naturalW / naturalH);\n }\n } catch (err) {\n // Don't fail layout when the image is unreachable — render at whatever\n // size Yoga computes. Surface the error (only in debug) so misconfigured\n // URLs and UA-gated CDNs are diagnosable instead of silently dropping\n // pixels, without spamming logs on every frame of a normal render.\n if (context?.debug) {\n const id = Buffer.isBuffer(src) ? \"<Buffer>\" : src;\n console.warn(\n `[@effing/canvas] failed to load image for layout (${id}): ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n }\n }\n }\n\n // Apply styles to Yoga node\n applyStylesToYoga(yogaNode, style);\n\n // SVG containers: children use SVG coordinate space, not flex layout.\n // Skip Yoga child nodes and keep React children in props for the SVG drawer.\n if (tagName === \"svg\") {\n const resolvedChildren = resolveSvgTree(props.children as ReactNode);\n return {\n type: tagName,\n style,\n children: [],\n props: { ...props, children: resolvedChildren },\n yogaNode,\n };\n }\n\n // The children as the DOM has them: components rendered, fragments and\n // arrays unwrapped, and adjacent text one run.\n const items = flattenChildren(props.children as ReactNode);\n\n // If this node has only text content, create a child text node.\n // Using a child node (instead of setMeasureFunc on this node directly)\n // ensures Yoga's baseline calculation accounts for this node's padding/border\n // when a parent uses alignItems: \"baseline\". Text of nothing but white space\n // is no flex item at all (see below), so the node has no line box.\n const onlyText = items.length === 1 && isText(items[0]) ? items[0] : null;\n if (onlyText !== null && !isWhiteSpaceOnly(String(onlyText))) {\n const textContent = String(onlyText);\n const childStyle = resolveStyle(undefined, style);\n const childYogaNode = createTextYogaNode();\n const textMeasure = new TextMeasure(textContent, childStyle, emojiEnabled);\n setTextMeasure(childYogaNode, textMeasure);\n const jc = style.justifyContent;\n if (!jc || jc === \"flex-start\") {\n childYogaNode.setFlexGrow(1);\n }\n childYogaNode.setFlexShrink(1);\n yogaNode.insertChild(childYogaNode, 0);\n\n // Match satori: text-only nodes default to flexShrink=1 so they shrink to\n // fit the available flex space. Without this, text containers overflow their\n // flex parent when siblings consume part of the main axis.\n if (style.flexShrink === undefined) {\n yogaNode.setFlexShrink(1);\n }\n\n return {\n type: tagName,\n style,\n children: [\n {\n type: \"text\",\n style: childStyle,\n children: [],\n textContent,\n textMeasure,\n props: {},\n yogaNode: childYogaNode,\n },\n ],\n props,\n yogaNode,\n };\n }\n\n // Process children. Each run of text between elements is a flex item of\n // its own (CSS Flexbox §4), its white space collapsed as its box's text\n // (see `layoutText`): the spaces at its start and end, after a <br> say,\n // are removed. A run of nothing but white space isn't rendered at all,\n // whatever its `white-space`.\n const children: IntermediateNode[] = [];\n for (const rendered of items) {\n if (typeof rendered === \"string\" && isWhiteSpaceOnly(rendered)) continue;\n const childYogaNode = isText(rendered)\n ? createTextYogaNode()\n : createYogaNode();\n yogaNode.insertChild(childYogaNode, children.length);\n children.push(\n await buildNode(\n rendered,\n style,\n childYogaNode,\n viewportWidth,\n viewportHeight,\n emojiEnabled,\n fontFamilies,\n context,\n ),\n );\n }\n\n return {\n type: tagName,\n style,\n children,\n props,\n yogaNode,\n };\n}\n\ntype IntermediateNode = {\n type: string;\n style: ComputedStyle;\n children: IntermediateNode[];\n textContent?: string;\n /** Set on text nodes, which Yoga measures. */\n textMeasure?: TextMeasure;\n props: Record<string, unknown>;\n yogaNode: YogaNode;\n};\n\n/**\n * How many times the layout is computed again for text that Yoga sized at\n * another width than it's drawn at (see `TextMeasure`). One normally settles\n * it; the bound is for layouts where a node's width depends on its height\n * (wrapping columns, aspect ratios), which could otherwise keep changing.\n */\nconst MAX_TEXT_RELAYOUTS = 2;\n\n/**\n * Lay every text node out at its final width, and compute the layout again\n * while Yoga sized one from a different height.\n */\nfunction settleText(\n root: IntermediateNode,\n relayout: () => void,\n debug: boolean,\n): void {\n const textNodes: IntermediateNode[] = [];\n const collect = (node: IntermediateNode) => {\n // Nothing under `display: none` is laid out or drawn.\n if (node.style.display === \"none\") return;\n if (node.textMeasure) textNodes.push(node);\n node.children.forEach(collect);\n };\n collect(root);\n // Text nodes have no padding or border: their width is the content's.\n const settle = (node: IntermediateNode, pin: boolean) =>\n node.textMeasure!.settle(node.yogaNode.getComputedWidth(), pin);\n\n for (let pass = 0; pass < MAX_TEXT_RELAYOUTS; pass++) {\n let unsettled = false;\n for (const node of textNodes) {\n if (settle(node, true)) {\n node.yogaNode.markDirty();\n unsettled = true;\n }\n }\n if (!unsettled) return;\n relayout();\n }\n if (!textNodes.some((node) => settle(node, false))) return;\n\n // Each pin moved the layout on to widths the drawn heights don't fit. Go\n // back to Yoga's own layout, as without the pins, and draw the text at the\n // widths it gives.\n for (const node of textNodes) {\n if (node.textMeasure!.unpin()) node.yogaNode.markDirty();\n }\n relayout();\n const unsettled = textNodes.filter((node) => settle(node, false)).length;\n if (debug && unsettled > 0) {\n console.warn(\n `[@effing/canvas] ${unsettled} text node(s) sized for other lines ` +\n `than drawn: the layout didn't settle in ${MAX_TEXT_RELAYOUTS} relayouts`,\n );\n }\n}\n\n/** Measure `yogaNode` with `textMeasure`. */\nfunction setTextMeasure(yogaNode: YogaNode, textMeasure: TextMeasure): void {\n yogaNode.setMeasureFunc((width, widthMode) =>\n textMeasure.measure(\n widthMode === MeasureMode.Undefined || Number.isNaN(width)\n ? Infinity\n : width,\n ),\n );\n}\n\nconst isText = (node: ReactNode): node is string | number =>\n typeof node === \"string\" || typeof node === \"number\";\n\n/** Render function components until something else is left. */\nfunction renderComponents(node: ReactNode): ReactNode {\n while (\n node !== null &&\n typeof node === \"object\" &&\n \"type\" in node &&\n typeof node.type === \"function\"\n ) {\n const el = node as ReactElement<Record<string, unknown>>;\n node = (el.type as (props: Record<string, unknown>) => ReactNode)(\n el.props ?? {},\n );\n }\n return node;\n}\n\n/**\n * The children as the DOM has them: function components rendered, fragments\n * and arrays unwrapped, null, undefined and booleans left out, and adjacent\n * text, as `Hello {name}` or a fragment of text gives, merged into one run.\n */\nfunction flattenChildren(\n node: ReactNode,\n items: ReactNode[] = [],\n): ReactNode[] {\n const rendered = renderComponents(node);\n if (\n rendered === null ||\n rendered === undefined ||\n typeof rendered === \"boolean\"\n ) {\n return items;\n }\n if (Array.isArray(rendered)) {\n for (const child of rendered as ReactNode[]) flattenChildren(child, items);\n return items;\n }\n const el = rendered as ReactElement<{ children?: ReactNode }>;\n if (typeof rendered === \"object\" && (el.type as unknown) === REACT_FRAGMENT) {\n return flattenChildren(el.props?.children, items);\n }\n const last = items[items.length - 1];\n if (isText(rendered) && items.length > 0 && isText(last)) {\n items[items.length - 1] = `${last}${rendered}`;\n } else {\n items.push(rendered);\n }\n return items;\n}\n\n/** Floor to a whole pixel, as Yoga does text (snapping values within 1e-4). */\nfunction floorToPixel(value: number): number {\n const rounded = Math.round(value);\n return Math.abs(value - rounded) < 1e-4 ? rounded : Math.floor(value);\n}\n\nfunction extractLayout(node: IntermediateNode, yogaNode: YogaNode): LayoutNode {\n const layout = yogaNode.getComputedLayout();\n // Yoga leaves text nodes unrounded (see `createTextYogaNode`) for their\n // width; they're placed on whole pixels, floored as Yoga rounds text.\n const place = node.textMeasure ? floorToPixel : (v: number) => v;\n\n return {\n type: node.type,\n style: node.style,\n children: node.children.map((child, i) => {\n const childYoga = yogaNode.getChild(i);\n return extractLayout(child, childYoga);\n }),\n textContent: node.textContent,\n textLayout: node.textMeasure?.layout,\n props: node.props,\n x: place(layout.left),\n y: place(layout.top),\n width: layout.width,\n height: layout.height,\n };\n}\n\n/**\n * React's `Fragment` type. A registered symbol shared by all React copies,\n * so we can detect fragments without a runtime dependency on `react`.\n */\nconst REACT_FRAGMENT = Symbol.for(\"react.fragment\");\n\n/**\n * Resolve function components, unwrap fragments, and flatten nested arrays\n * inside an `<svg>` subtree. The SVG drawer switches on primitive element\n * strings (path, rect, etc.) and does not flatten its own children, so\n * without this preprocessing (a) function components and fragments silently\n * disappear and (b) helpers returning arrays crash the defs collector.\n */\nfunction resolveSvgTree(node: ReactNode): ReactNode {\n if (node === null || node === undefined || typeof node === \"boolean\")\n return null;\n if (typeof node === \"string\" || typeof node === \"number\") return node;\n\n if (Array.isArray(node)) {\n const out: ReactNode[] = [];\n let changed = false;\n for (const child of node as ReactNode[]) {\n const resolved = resolveSvgTree(child);\n if (resolved === null || resolved === undefined) {\n changed = true;\n continue;\n }\n if (Array.isArray(resolved)) {\n changed = true;\n for (const r of resolved) out.push(r);\n } else {\n if (resolved !== child) changed = true;\n out.push(resolved);\n }\n }\n return changed ? out : node;\n }\n\n const el = node as ReactElement<Record<string, unknown>>;\n if (typeof el.type === \"function\") {\n const rendered = (el.type as (props: Record<string, unknown>) => ReactNode)(\n el.props ?? {},\n );\n return resolveSvgTree(rendered);\n }\n\n // Unwrap fragments: their children take the fragment's place in the parent\n // (callers flatten arrays), since the drawer only knows SVG element strings.\n if ((el.type as unknown) === REACT_FRAGMENT) {\n return resolveSvgTree((el.props ?? {}).children as ReactNode);\n }\n\n const elProps = (el.props ?? {}) as Record<string, unknown>;\n if (elProps.children !== undefined) {\n const resolvedChildren = resolveSvgTree(elProps.children as ReactNode);\n if (resolvedChildren !== elProps.children) {\n return { ...el, props: { ...elProps, children: resolvedChildren } };\n }\n }\n return el;\n}\n","import type { SKRSContext2D } from \"@effing/skia\";\nimport type { ReactNode } from \"react\";\n\nimport type { RenderReactElementOptions } from \"../types.ts\";\nimport { drawNode } from \"./draw/index.ts\";\nimport { ensureFontsRegistered } from \"./font.ts\";\nimport { buildLayoutTree } from \"./layout.ts\";\nimport { releaseParagraphs } from \"./text/native.ts\";\nimport type { RenderContext } from \"./context.ts\";\n\n/**\n * Render a React element tree to a canvas context.\n *\n * Width and height default to `ctx.canvas.width` / `ctx.canvas.height` but\n * can be overridden via `options.width` and `options.height`. This is useful\n * for HiDPI rendering where the canvas is larger than the logical layout size.\n *\n * @param ctx - Canvas 2D rendering context to draw into\n * @param element - React element tree to render\n * @param options - Rendering options (fonts, dimensions, debug mode)\n *\n * @example\n * ```tsx\n * import { createCanvas, renderReactElement } from \"@effing/canvas\";\n *\n * const canvas = createCanvas(1080, 1080);\n * const ctx = canvas.getContext(\"2d\");\n *\n * await renderReactElement(ctx, <MyComponent />, { fonts: [myFont] });\n *\n * const png = await canvas.encode(\"png\");\n * ```\n *\n * @example HiDPI rendering (2x)\n * ```tsx\n * const dpr = 2;\n * const canvas = createCanvas(1080 * dpr, 1080 * dpr);\n * const ctx = canvas.getContext(\"2d\");\n * ctx.scale(dpr, dpr);\n *\n * await renderReactElement(ctx, <MyComponent />, {\n * fonts: [myFont],\n * width: 1080,\n * height: 1080,\n * });\n * ```\n *\n * @example Custom User-Agent for remote image fetches\n * ```tsx\n * await renderReactElement(ctx, <MyComponent />, {\n * userAgent: \"my-renderer/1.0\",\n * });\n * ```\n *\n * @example Persistent image cache for repeated calls (e.g. per frame)\n * ```tsx\n * const imageCache: ImageCache = new Map();\n * for (let frame = 0; frame < frameCount; frame++) {\n * await renderReactElement(ctx, <Frame n={frame} />, { fonts, imageCache });\n * }\n * ```\n */\nexport async function renderReactElement(\n ctx: SKRSContext2D,\n element: ReactNode,\n options: RenderReactElementOptions = {},\n): Promise<void> {\n const fonts = options.fonts ?? [];\n\n // Register fonts\n ensureFontsRegistered(fonts);\n\n // Get dimensions (option overrides take precedence over canvas size)\n const width = options.width ?? ctx.canvas.width;\n const height = options.height ?? ctx.canvas.height;\n\n // Per-render context: shared image cache + cross-cutting fetch/diagnostic\n // config, threaded through both the layout and draw phases. The caller may\n // supply the cache to persist image loads across calls.\n const renderContext: RenderContext = {\n imageCache: options.imageCache ?? new Map(),\n userAgent: options.userAgent,\n debug: options.debug ?? false,\n };\n\n // Build layout tree (Yoga)\n const emojiStyle =\n options.emoji === \"none\" ? undefined : (options.emoji ?? \"twemoji\");\n const fontFamilies = [...new Set(fonts.map((f) => f.name))];\n const { tree: layoutTree } = await buildLayoutTree(\n element,\n width,\n height,\n !!emojiStyle,\n fontFamilies,\n renderContext,\n );\n\n // Draw to canvas\n await drawNode(ctx, layoutTree, 0, 0, renderContext, emojiStyle);\n\n // Text is laid out as native paragraphs, whose memory Node releases only on\n // a turn of the event loop: take one when a caller's loop hasn't.\n await releaseParagraphs();\n}\n","import type { FontData } from \"./types.ts\";\nimport type { ComputedStyle } from \"./jsx/style/compute.ts\";\nimport { registerFont } from \"./jsx/font.ts\";\nimport { layoutText } from \"./jsx/text/index.ts\";\n\n/**\n * Options for {@link findLargestUsableFontSize}.\n */\nexport type FindLargestUsableFontSizeOptions = {\n /** The text to fit */\n text: string;\n /** Font data to use for measurement */\n font: FontData;\n /** Maximum width in pixels */\n maxWidth: number;\n /** Maximum height in pixels */\n maxHeight: number;\n /** Line height — `\"normal\"` uses font metrics, numeric values are CSS multipliers */\n lineHeight?: number | \"normal\";\n /**\n * Whitespace handling, as in CSS (default: `\"normal\"`). Use `\"nowrap\"` to\n * fit the text on one line instead of wrapping to `maxWidth`, its newlines\n * collapsing to spaces, or `\"pre\"` to fit each newline-separated paragraph\n * on a line of its own.\n */\n whiteSpace?: ComputedStyle[\"whiteSpace\"];\n /** Minimum font size to consider (default: 1) */\n minFontSize?: number;\n /** Maximum font size to consider (default: 1000) */\n maxFontSize?: number;\n};\n\n/**\n * Find the largest integer font size that keeps text within the given bounds.\n *\n * Uses binary search over integer font sizes, measuring with {@link layoutText}\n * at each step. Returns `minFontSize` if even the smallest size overflows.\n *\n * By default text wraps to `maxWidth` and is fit into the `maxWidth` × `maxHeight`\n * box. Set `whiteSpace: \"nowrap\"` to fit the text on one line instead (or\n * `\"pre\"` for one line per newline-separated paragraph), in which case\n * `maxWidth` constrains the full line width.\n */\nexport function findLargestUsableFontSize(\n options: FindLargestUsableFontSizeOptions,\n): number {\n const {\n text,\n font,\n maxWidth,\n maxHeight,\n lineHeight = \"normal\",\n whiteSpace,\n minFontSize = 1,\n maxFontSize = 1000,\n } = options;\n\n registerFont(font);\n\n let lo = minFontSize;\n let hi = maxFontSize;\n let best = minFontSize;\n\n while (lo <= hi) {\n const mid = Math.floor((lo + hi) / 2);\n const style: ComputedStyle = {\n fontSize: mid,\n fontFamily: font.name,\n fontWeight: font.weight,\n fontStyle: font.style,\n lineHeight: lineHeight === \"normal\" ? undefined : lineHeight,\n whiteSpace,\n };\n\n const result = layoutText(text, style, maxWidth);\n\n if (result.width <= maxWidth && result.height <= maxHeight) {\n best = mid;\n lo = mid + 1;\n } else {\n hi = mid - 1;\n }\n }\n\n return best;\n}\n"],"mappings":";AAMA,SAAS,gBAAgB,qBAAqB;AAC9C;AAAA,EACE;AAAA,EAEA,eAAAA;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;;;ACpBP,SAAS,aAAa,uBAAuB;AAgCtC,SAAS,UACd,QACA,SACgB;AAChB,QAAM,YACJ,OAAO,WAAW,YAAY,YAAY,MAAM,IAC5C,SACA,kBAAkB,OAAO,YAAY,OAAO,IAAI,IAC9C,OAAO,OACP;AACR,MAAI,cAAc,QAAW;AAC3B,WAAO,gBAAgB,WAAW,SAAS,SAAS;AAAA,EACtD;AACA,SAAO,gBAAgB,MAAM;AAC/B;AAoBO,SAAS,gBACd,OACA,KACA,WACgB;AAChB,MAAI,OAAO,SAAS,GAAG,EAAG,QAAO,UAAU,GAAG;AAC9C,MAAI,QAAQ,MAAM,IAAI,GAAG;AACzB,MAAI,CAAC,OAAO;AACV,UAAM,UAAU;AAAA,MACd;AAAA,MACA,cAAc,SAAY,SAAY,EAAE,UAAU;AAAA,IACpD;AACA,YAAQ,MAAM,MAAM;AAClB,UAAI,MAAM,IAAI,GAAG,MAAM,QAAS,OAAM,OAAO,GAAG;AAAA,IAClD,CAAC;AACD,UAAM,IAAI,KAAK,OAAO;AACtB,YAAQ;AAAA,EACV;AACA,SAAO;AACT;AAMO,SAAS,YAAY,KAAsB;AAChD,SAAO,gBAAgB,KAAK,GAAG;AACjC;AAOA,eAAsB,gBACpB,KACA,WACgB;AAChB,QAAM,OACJ,cAAc,SACV,EAAE,SAAS,EAAE,cAAc,UAAU,EAAE,IACvC;AACN,QAAM,WAAW,MAAM,MAAM,KAAK,IAAI;AACtC,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI;AAAA,MACR,yBAAyB,GAAG,KAAK,SAAS,MAAM,IAAI,SAAS,UAAU;AAAA,IACzE;AAAA,EACF;AACA,QAAM,SAAS,OAAO,KAAK,MAAM,SAAS,YAAY,CAAC;AACvD,SAAO,gBAAgB,MAAM;AAC/B;;;ACrHA,SAAS,uBAAuB;AAiBzB,SAAS,WACd,MACA,SACiB;AACjB,QAAM,aAAa,OAAO,SAAS,WAAW,OAAO,KAAK,SAAS,OAAO;AAC1E,SAAO,gBAAgB,aAAa,YAAY;AAAA,IAC9C,cAAc,SAAS;AAAA,EACzB,CAAC;AACH;AAwBO,SAAS,kBACd,KACA,WACA,OACM;AACN,YAAU,UAAU,KAAK;AACzB,YAAU,OAAO,GAAG;AACtB;;;ACpDO,SAAS,eAAe,OAAe,eAA+B;AAC3E,MAAI,MAAM,SAAS,GAAG,EAAG,QAAQ,WAAW,KAAK,IAAI,MAAO;AAC5D,SAAO,WAAW,KAAK;AACzB;AAEO,SAAS,SAAS,GAAoB;AAC3C,MAAI,OAAO,MAAM,SAAU,QAAO;AAClC,MAAI,MAAM,UAAa,MAAM,KAAM,QAAO;AAC1C,QAAM,IAAI,WAAW,OAAO,CAAC,CAAC;AAC9B,SAAO,MAAM,CAAC,IAAI,IAAI;AACxB;AAOO,SAAS,gBAAgB,GAAY,gBAAgC;AAC1E,MAAI,OAAO,MAAM,SAAU,QAAO;AAClC,MAAI,MAAM,UAAa,MAAM,KAAM,QAAO;AAC1C,QAAM,IAAI,OAAO,CAAC;AAClB,MAAI,EAAE,SAAS,GAAG,EAAG,QAAQ,WAAW,CAAC,IAAI,MAAO;AACpD,QAAM,IAAI,WAAW,CAAC;AACtB,SAAO,MAAM,CAAC,IAAI,IAAI;AACxB;AAOO,SAAS,gBAAgB,GAAmB;AACjD,QAAM,QAAQ,EAAE,QAAQ,CAAC,EAAE,QAAQ,UAAU,EAAE;AAC/C,SAAO,UAAU,QAAQ,UAAU,KAAK,MAAM;AAChD;;;ACgHA,IAAM,iBAAiB;AAMhB,IAAM,sBAAsB;AAK5B,IAAM,gBAA+B;AAAA,EAC1C,SAAS;AAAA,EACT,eAAe;AAAA,EACf,UAAU;AAAA,EACV,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,cAAc;AAAA,EACd,SAAS;AAAA,EACT,UAAU;AACZ;AAKA,IAAM,oBAA6C;AAAA,EACjD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAKO,SAAS,aACd,UACA,aACe;AACf,QAAM,QAAQ,EAAE,GAAG,SAAS;AAG5B,aAAW,QAAQ,mBAAmB;AACpC,QAAI,MAAM,IAAI,MAAM,UAAa,YAAY,IAAI,MAAM,QAAW;AAChE,MAAC,MAAkC,IAAI,IAAI,YAAY,IAAI;AAAA,IAC7D;AAAA,EACF;AAGA,MAAI,OAAO,MAAM,aAAa,UAAU;AACtC,UAAM,iBACJ,OAAO,YAAY,aAAa,WAC5B,YAAY,WACZ;AACN,UAAM,WAAW;AAAA,MACf,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,UAAM,WAAW,OAAO,aAAa,WAAW,WAAW;AAAA,EAC7D;AAKA,MAAI,OAAO,MAAM,eAAe,UAAU;AACxC,UAAM,MAAM,MAAM;AAClB,QAAI,IAAI,SAAS,GAAG,GAAG;AACrB,YAAM,aAAa,WAAW,GAAG,IAAI;AAAA,IACvC,OAAO;AACL,YAAM,SAAS,WAAW,GAAG;AAC7B,UAAI,CAAC,MAAM,MAAM,GAAG;AAClB,cAAM,aAAa;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AAGA,MAAI,OAAO,MAAM,kBAAkB,UAAU;AAC3C,UAAM,kBACJ,OAAO,MAAM,aAAa,WACtB,MAAM,WACN,OAAO,YAAY,aAAa,WAC9B,YAAY,WACZ;AACR,UAAM,WAAW;AAAA,MACf,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,QAAI,OAAO,aAAa,UAAU;AAChC,YAAM,gBAAgB;AAAA,IACxB;AAAA,EACF;AAEA,SAAO;AACT;AAKA,IAAM,kBAA2C;AAAA,EAC/C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAOO,SAAS,YACd,OACA,eACA,gBACA,UACA,cACiB;AAEjB,MAAI,MAAM,SAAS,GAAG,KAAK,UAAU,OAAQ,QAAO;AAGpD,MAAI,MAAM,SAAS,MAAM,GAAG;AAC1B,UAAM,IAAI,WAAW,KAAK;AAC1B,WAAO,MAAM,CAAC,IACV,QACC,IAAI,MAAO,KAAK,IAAI,eAAe,cAAc;AAAA,EACxD;AACA,MAAI,MAAM,SAAS,MAAM,GAAG;AAC1B,UAAM,IAAI,WAAW,KAAK;AAC1B,WAAO,MAAM,CAAC,IACV,QACC,IAAI,MAAO,KAAK,IAAI,eAAe,cAAc;AAAA,EACxD;AACA,MAAI,MAAM,SAAS,IAAI,GAAG;AACxB,UAAM,IAAI,WAAW,KAAK;AAC1B,WAAO,MAAM,CAAC,IAAI,QAAS,IAAI,MAAO;AAAA,EACxC;AACA,MAAI,MAAM,SAAS,IAAI,GAAG;AACxB,UAAM,IAAI,WAAW,KAAK;AAC1B,WAAO,MAAM,CAAC,IAAI,QAAS,IAAI,MAAO;AAAA,EACxC;AAGA,MAAI,MAAM,SAAS,KAAK,GAAG;AACzB,UAAM,IAAI,WAAW,KAAK;AAC1B,WAAO,MAAM,CAAC,IAAI,QAAQ,IAAI;AAAA,EAChC;AACA,MAAI,MAAM,SAAS,IAAI,GAAG;AACxB,UAAM,IAAI,WAAW,KAAK;AAC1B,WAAO,MAAM,CAAC,IAAI,QAAQ,IAAI;AAAA,EAChC;AAGA,MAAI,MAAM,SAAS,IAAI,GAAG;AACxB,UAAM,IAAI,WAAW,KAAK;AAC1B,WAAO,MAAM,CAAC,IAAI,QAAQ;AAAA,EAC5B;AACA,MAAI,MAAM,SAAS,IAAI,GAAG;AACxB,UAAM,IAAI,WAAW,KAAK;AAC1B,WAAO,MAAM,CAAC,IAAI,QAAQ,KAAK,KAAK;AAAA,EACtC;AACA,MAAI,MAAM,SAAS,IAAI,GAAG;AACxB,UAAM,IAAI,WAAW,KAAK;AAC1B,WAAO,MAAM,CAAC,IAAI,QAAQ,IAAI;AAAA,EAChC;AACA,MAAI,MAAM,SAAS,IAAI,GAAG;AACxB,UAAM,IAAI,WAAW,KAAK;AAC1B,WAAO,MAAM,CAAC,IAAI,QAAQ,IAAI;AAAA,EAChC;AACA,MAAI,MAAM,SAAS,IAAI,GAAG;AACxB,UAAM,IAAI,WAAW,KAAK;AAC1B,WAAO,MAAM,CAAC,IAAI,QAAQ,KAAK,KAAK;AAAA,EACtC;AACA,MAAI,MAAM,SAAS,IAAI,GAAG;AACxB,UAAM,IAAI,WAAW,KAAK;AAC1B,WAAO,MAAM,CAAC,IAAI,QAAQ,KAAK,KAAK;AAAA,EACtC;AAEA,SAAO;AACT;AAOO,SAAS,aACd,OACA,eACA,gBACA,eAAuB,gBACR;AACf,QAAM,WACJ,OAAO,MAAM,aAAa,WAAW,MAAM,WAAW;AAExD,aAAW,QAAQ,iBAAiB;AAClC,UAAM,QAAQ,MAAM,IAAI;AACxB,QAAI,OAAO,UAAU,SAAU;AAC/B,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,QAAI,aAAa,OAAO;AACtB,MAAC,MAAkC,IAAI,IAAI;AAAA,IAC7C;AAAA,EACF;AAKA,aAAW,CAAC,MAAM,MAAM,KAAK,qBAAqB;AAChD,UAAM,QAAQ,MAAM,IAAI;AACxB,QAAI,OAAO,UAAU,SAAU;AAC/B,IAAC,MAAkC,IAAI,IAAI;AAAA,MACzC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AASA,IAAM,sBAAuD;AAAA,EAC3D,CAAC,aAAa,EAAE;AAAA,EAChB,CAAC,mBAAmB,EAAE;AAAA,EACtB,CAAC,YAAY,IAAI;AAAA,EACjB,CAAC,UAAU,IAAI;AAAA,EACf,CAAC,kBAAkB,IAAI;AACzB;AAQA,SAAS,mBACP,WACA,eACA,gBACA,UACA,cACA,SAAS,IACD;AACR,SAAO,UAAU;AAAA;AAAA,IAEf;AAAA,IACA,CAAC,UAAU;AACT,YAAM,WAAW;AAAA,QACf;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,aAAO,OAAO,aAAa,WACvB,GAAG,gBAAgB,QAAQ,CAAC,GAAG,MAAM,KACrC;AAAA,IACN;AAAA,EACF;AACF;;;AC9dA,SAAS,iBAAiB;;;ACoDnB,IAAM,0BAA0B,OAAO;AAG9C,IAAM,aAAa,OAAO;AAM1B,IAAM,cAAc;AAOpB,IAAM,kBAAkB,OAAO;AAG/B,IAAM,OAAO,OAAO;AAGpB,IAAM,kBAAkB;AAAA;AAAA,EAEtB,OAAO,MAAM,WAAW;AAAA;AAAA,EAExB,OAAO;AAAA;AAAA;AAAA,EAGP,OAAO,SAAS,WAAW,IAAI,UAAU,gCAAgC,IAAI;AAAA;AAAA;AAAA,EAG7E,OAAO,SAAS,eAAe;AAAA,EAC/B;AACF,EAAE,KAAK,GAAG;AAOV,IAAM,cAAc,MAAM,eAAe,OAAO,WAAW,IAAI,UAAU;AAEzE,IAAM,WAAW,IAAI;AAAA,EACnB,OAAO,eAAe,IAAI,WAAW,aAAa,WAAW;AAAA,EAC7D;AACF;AAYO,SAAS,QAAQ,UAA2B;AACjD,SAAO,SAAS,KAAK,QAAQ;AAC/B;;;ACvHA,SAAS,oBAAoB;AAI7B,IAAI,aAAmC;AAEvC,SAAS,gBAA+B;AACtC,MAAI,CAAC,YAAY;AACf,iBAAa,aAAa,GAAG,CAAC,EAAE,WAAW,IAAI;AAAA,EACjD;AACA,SAAO;AACT;AAEA,IAAM,mBAAmB,oBAAI,IAAI;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,SAAS,gBAAgB,QAAwB;AAC/C,MAAI,CAAC,UAAU,iBAAiB,IAAI,MAAM,EAAG,QAAO;AACpD,SAAO,IAAI,MAAM;AACnB;AAGO,SAAS,kBAAkB,YAA4B;AAC5D,SAAO,WACJ,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,gBAAgB,EAAE,KAAK,CAAC,CAAC,EACpC,KAAK,IAAI;AACd;AAKO,SAAS,QACd,KACA,UACA,YACA,aAA8B,KAC9B,YAAoB,UACd;AACN,MAAI,OAAO,GAAG,SAAS,IAAI,UAAU,IAAI,QAAQ,MAAM,kBAAkB,UAAU,CAAC;AACtF;AAYO,SAAS,mBACd,UACA,YACA,YACA,WACA,YACA,MACA,YACA,aACyC;AACzC,QAAM,IAAI,cAAc;AAExB,QAAM,UAAU,CAAC,SAAiB;AAChC,YAAQ,GAAG,UAAU,YAAY,YAAY,SAAS;AACtD,UAAM,WAAW,EAAE;AACnB,MAAE,gBAAgB;AAClB,QAAI;AACF,aAAO,EAAE,YAAY,IAAI;AAAA,IAC3B,UAAE;AACA,QAAE,gBAAgB;AAAA,IACpB;AAAA,EACF;AAGA,QAAM,QAAQ,KAAK,KAAK,EAAE,MAAM,KAAK;AACrC,QAAM,WAAW,MAAM,CAAC,KAAK;AAC7B,QAAM,YAAY,MAAM,SAAS,IAAI,MAAM,CAAC,IAAK;AAGjD,MAAI;AACJ,UAAQ,UAAU;AAAA,IAChB,KAAK,OAAO;AACV,YAAM,aAAa,QAAQ,GAAG;AAC9B,qBAAe,WAAW,2BAA2B,WAAW;AAChE;AAAA,IACF;AAAA,IACA,KAAK,MAAM;AACT,YAAM,YAAY,QAAQ,GAAG;AAC7B,qBAAe,UAAU,2BAA2B,WAAW;AAC/D;AAAA,IACF;AAAA,IACA,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL;AACE,qBAAe;AACf;AAAA,EACJ;AAGA,MAAI;AACJ,UAAQ,WAAW;AAAA,IACjB,KAAK;AACH,sBAAgB;AAChB;AAAA,IACF,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL;AACE,sBAAgB;AAChB;AAAA,EACJ;AAEA,QAAM,eAAe,cAAc,aAAa,gBAAgB;AAChE,QAAM,WAAW,eAAe,aAAa;AAC7C,QAAM,YAAY,eAAe,cAAc;AAE/C,SAAO;AAAA,IACL,UAAU,KAAK,IAAI,GAAG,QAAQ;AAAA,IAC9B,WAAW,KAAK,IAAI,GAAG,SAAS;AAAA,EAClC;AACF;;;AFlHA,SAAS,SAAS,QAA6C;AAC7D,MAAI,OAAO,WAAW,SAAU,QAAO;AACvC,MAAI,WAAW,OAAQ,QAAO;AAC9B,QAAM,SAAS,SAAS,OAAO,UAAU,KAAK,GAAG,EAAE;AACnD,SAAO,MAAM,MAAM,IAAI,MAAM;AAC/B;AAEA,SAAS,YACP,WAC6B;AAC7B,MAAI,WAAW,WAAW,QAAQ,EAAG,QAAO;AAC5C,MAAI,WAAW,WAAW,SAAS,EAAG,QAAO;AAC7C,SAAO;AACT;AAEA,IAAM,cAAc,oBAAI,IAAI;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,SAAS,YACP,WAC6B;AAC7B,SAAO,cAAc,UAAa,YAAY,IAAI,SAAS,IACtD,YACD;AACN;AAGA,SAAS,YAAY,OAAmD;AACtE,QAAM,EAAE,UAAU,IAAI;AACtB,SAAO,cAAc,eAAe,cAAc,aAC9C,YACA;AACN;AAQA,SAAS,eAAe,OAAsD;AAC5E,QAAM,EAAE,cAAc,UAAU,IAAI;AACpC,SAAO,iBAAiB,gBACtB,iBAAiB,cACjB,cAAc,eACZ,eACA;AACN;AAIA,IAAM,YAAY;AAIlB,IAAM,gBAAgB;AAStB,IAAM,aAAa;AAOnB,IAAM,yBAAyB;AAC/B,IAAI,oBAAoB;AACxB,IAAI,cAAc;AAElB,SAAS,iBAAuB;AAC9B;AACA,MAAI,YAAa;AACjB,gBAAc;AAEd,eAAa,MAAM;AACjB,wBAAoB;AACpB,kBAAc;AAAA,EAChB,CAAC;AACH;AAMA,eAAsB,oBAAmC;AACvD,MAAI,oBAAoB,uBAAwB;AAChD,QAAM,IAAI,QAAc,CAAC,YAAY,aAAa,OAAO,CAAC;AAC5D;AAEA,IAAM,oBAAoB,IAAI,KAAK,UAAU,QAAW;AAAA,EACtD,aAAa;AACf,CAAC;AAiBD,SAAS,WACP,MACA,UACA,eACS;AACT,QAAM,QAA2C,CAAC;AAClD,QAAM,QAAkB,CAAC;AAEzB,QAAM,QAA4B,CAAC;AACnC,MAAI,MAAM;AACV,MAAI,iBAAiB;AACrB,MAAI,YAAY;AAChB,aAAW,EAAE,QAAQ,KAAK,kBAAkB,QAAQ,IAAI,GAAG;AACzD,QAAI,CAAC,QAAQ,OAAO,GAAG;AACrB,aAAO;AACP,wBAAkB,QAAQ;AAC1B,mBAAa,QAAQ;AACrB;AAAA,IACF;AACA,QAAI,IAAK,OAAM,KAAK,GAAG;AACvB,UAAM;AACN,UAAM,KAAK;AAAA;AAAA;AAAA,MAGT,OAAO,KAAK,IAAI,GAAG,WAAW,aAAa;AAAA,MAC3C,QAAQ;AAAA,MACR,eAAe;AAAA,MACf,gBAAgB,YAAY,IAAI;AAAA;AAAA;AAAA;AAAA,MAIhC,WAAW;AAAA,IACb,CAAC;AACD,UAAM,KAAK,OAAO;AAClB,UAAM,KAAK,CAAC,gBAAgB,SAAS,CAAC;AACtC,sBAAkB;AAClB,iBAAa,QAAQ;AACrB,UAAM,KAAK,CAAC,gBAAgB,SAAS,CAAC;AAAA,EACxC;AACA,MAAI,IAAK,OAAM,KAAK,GAAG;AACvB,MAAI,MAAM,WAAW,EAAG,QAAO,EAAE,OAAO,CAAC,IAAI,GAAG,MAAM;AACtD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,aAAa,CAAC,UAAU;AAEtB,UAAI,OAAyB,CAAC,GAAG,CAAC;AAClC,iBAAW,KAAK,OAAO;AACrB,YAAI,EAAE,CAAC,IAAI,MAAO;AAClB,eAAO;AAAA,MACT;AACA,aAAO,KAAK,CAAC,KAAK,QAAQ,KAAK,CAAC;AAAA,IAClC;AAAA,EACF;AACF;AAWO,SAAS,iBACd,MACA,OACA,UACA,YACA,cACkB;AAClB,QAAM,iBAAiB,MAAM,YAAY;AACzC,QAAM,WAAW,OAAO,SAAS,cAAc,IAC3C,KAAK,IAAI,gBAAgB,aAAa,IACtC;AACJ,QAAM,aAAa,MAAM,cAAc;AACvC,QAAM,aAAa,MAAM,cAAc;AACvC,QAAM,YAAY,MAAM,aAAa;AACrC,QAAM,gBACJ,OAAO,MAAM,kBAAkB,YAC/B,OAAO,SAAS,MAAM,aAAa,IAC/B,MAAM,gBACN;AACN,QAAM,aAAa,MAAM,cAAc;AACvC,QAAM,SAAS,eAAe,YAAY,eAAe;AACzD,QAAM,YACJ,MAAM,aAAa,MAAM,aAAa,IAClC,KAAK,MAAM,MAAM,SAAS,IAC1B;AACN,QAAM,WACJ,cAAc,UAAc,UAAU,MAAM,iBAAiB,aACzD,WACA;AACN,QAAM,QAAQ,WAAW,IAAI,WAAW;AAExC,QAAM,UAAU,eACZ,WAAW,MAAM,UAAU,aAAa,IACxC,EAAE,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,EAAE;AAK/B,QAAM,YAAY,IAAI,UAAU,QAAQ,OAAO;AAAA,IAC7C,YAAY,kBAAkB,UAAU;AAAA,IACxC;AAAA,IACA,YAAY,SAAS,UAAU;AAAA,IAC/B,WAAW,YAAY,SAAS;AAAA,IAChC;AAAA,IACA;AAAA,IACA,WAAW,YAAY,MAAM,SAAS;AAAA,IACtC;AAAA,IACA,UAAU;AAAA,IACV;AAAA;AAAA,IAEA,wBAAwB,eAAe,SAAS,eAAe;AAAA,IAC/D,WAAW,YAAY,KAAK;AAAA,IAC5B,cAAc,eAAe,KAAK;AAAA,EACpC,CAAC;AACD,iBAAe;AACf,QAAM,SAAS,UAAU,OAAO,KAAK;AAGrC,QAAM,QACJ,OAAO,MAAM,SAAS,IAClB,OAAO,QACP;AAAA,IACE;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA;AAAA,MAEP,WAAW,OAAO,aAAa,OAAO,SAAS,OAAO,WAAW;AAAA,MACjE,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,WAAW;AAAA,IACb;AAAA,EACF;AACN,QAAM,cAAc,QAAQ,gBAAgB,CAAC,UAAkB;AAC/D,QAAM,WAA0B,MAAM,IAAI,CAAC,MAAM,OAAO;AAAA;AAAA,IAEtD,MAAM,KACH,MAAM,YAAY,KAAK,UAAU,GAAG,YAAY,KAAK,QAAQ,CAAC,EAC9D,QAAQ,OAAO,EAAE;AAAA,IACpB,GAAG,KAAK;AAAA,IACR,GAAG,KAAK;AAAA,IACR,OAAO,KAAK;AAAA,IACZ,QAAQ,OAAO;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO,MAAM,SAAS;AAAA,IACtB,QAAQ,OAAO;AAAA,IACf,gBAAgB,MAAM;AAAA,IACtB;AAAA,IACA,WAAW;AAAA,EACb,EAAE;AAEF,QAAM,QAAuB,CAAC;AAC9B,SAAO,aAAa,QAAQ,CAAC,KAAK,MAAM;AAEtC,QAAI,CAAC,IAAK;AACV,UAAM,KAAK;AAAA,MACT,UAAU,QAAQ,MAAM,CAAC;AAAA,MACzB,GAAG,IAAI;AAAA,MACP,GAAG,IAAI;AAAA,MACP,MAAM;AAAA,MACN,UAAU,MAAM,IAAI,IAAI,EAAG;AAAA,IAC7B,CAAC;AAAA,EACH,CAAC;AAED,MAAI,SAAS,MAAM,SAAS,OAAO;AACnC,MAAI,eAAe,QAAW;AAI5B,UAAM,aAAa,OAAO,SAAS,cAAc,KAAK,kBAAkB;AACxE,aAAS,aAAa,IAAI,KAAK,KAAK,MAAM;AAAA,EAC5C;AAEA,MAAI,mBAAmB;AACvB,QAAM,cAAc,MAAM;AAC1B,MAAI,eAAe,gBAAgB,QAAQ;AACzC,UAAM,OAAO;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO;AAAA,MACP,MAAM,eAAe;AAAA,MACrB,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AACA,QAAI,gBAAgB,gBAAgB,gBAAgB,aAAa;AAC/D,iBAAW,OAAO,SAAU,KAAI,KAAK,KAAK;AAC1C,iBAAW,KAAK,OAAO;AACrB,UAAE,KAAK,KAAK;AACZ,UAAE,YAAY,KAAK;AAAA,MACrB;AACA,gBAAU,KAAK;AACf,yBAAmB,CAAC,KAAK;AAAA,IAC3B;AACA,QAAI,gBAAgB,cAAc,gBAAgB,aAAa;AAC7D,gBAAU,KAAK;AAAA,IACjB;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA,OAAO,SAAS,OAAO,CAAC,GAAG,MAAM,KAAK,IAAI,GAAG,EAAE,KAAK,GAAG,CAAC;AAAA,IACxD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AGrVO,SAAS,iBAAiB,MAAuB;AACtD,SAAO,mBAAmB,KAAK,IAAI;AACrC;AAwCO,SAAS,mBACd,MACA,YACQ;AACR,MAAI,SAAS,KAAK,QAAQ,WAAW,EAAE,EAAE,QAAQ,SAAS,IAAI;AAC9D,MAAI,eAAe,SAAS,eAAe,YAAY;AACrD,aAAS,OAAO,QAAQ,OAAO,EAAE;AAAA,EACnC,WAAW,sBAAsB,KAAK,MAAM,GAAG;AAG7C,aAAS,OAAO,QAAQ,WAAW,GAAG,EAAE,QAAQ,WAAW,IAAI;AAC/D,QAAI,eAAe,WAAY,UAAS,OAAO,QAAQ,QAAQ,GAAG;AAClE,aAAS,OAAO,QAAQ,UAAU,GAAG,EAAE,QAAQ,UAAU,EAAE;AAAA,EAC7D;AACA,SAAO,OAAO,QAAQ,aAAa,EAAE,EAAE,QAAQ,YAAY,eAAe;AAC5E;AAEA,IAAM,cAAc;AAEpB,IAAM,aAAa;AAMnB,IAAM,kBAAkB;;;ACdjB,SAAS,WACd,MACA,OACA,UACA,cACkB;AAClB,QAAM,WAAW,MAAM,YAAY;AACnC,QAAM,SAAS;AAAA,IACb,mBAAmB,mBAAmB,MAAM,MAAM,UAAU,GAAG,KAAK;AAAA,IACpE;AAAA,IACA;AAAA,IACA,kBAAkB,MAAM,YAAY,QAAQ;AAAA,IAC5C;AAAA,EACF;AACA,QAAM,kBAAkB,uBAAuB,OAAO,QAAQ;AAC9D,aAAW,OAAO,OAAO,UAAU;AACjC,QAAI,kBAAkB;AACtB,QAAI,kBAAkB,MAAM;AAAA,EAC9B;AACA,SAAO;AACT;AAEA,SAAS,uBACP,OACA,UACoB;AACpB,QAAM,MAAM,MAAM;AAClB,MAAI,QAAQ,OAAW,QAAO;AAC9B,MAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,QAAM,WAAW,YAAY,OAAO,GAAG,GAAG,GAAG,GAAG,UAAU,EAAE;AAC5D,SAAO,OAAO,aAAa,WAAW,WAAW;AACnD;AAEA,SAAS,mBAAmB,MAAc,OAA8B;AACtE,MAAI,MAAM,kBAAkB,YAAa,QAAO,KAAK,YAAY;AACjE,MAAI,MAAM,kBAAkB,YAAa,QAAO,KAAK,YAAY;AACjE,MAAI,MAAM,kBAAkB,cAAc;AACxC,WAAO,KAAK,QAAQ,SAAS,CAAC,MAAM,EAAE,YAAY,CAAC;AAAA,EACrD;AACA,SAAO;AACT;AAMA,SAAS,kBACP,YACA,UACoB;AACpB,MAAI,eAAe,UAAa,eAAe,SAAU,QAAO;AAChE,MAAI;AACJ,MAAI,OAAO,eAAe,UAAU;AAElC,SAAK,aAAa,IAAI,aAAa,aAAa;AAAA,EAClD,OAAO;AACL,SAAK,WAAW,UAAU;AAAA,EAC5B;AAGA,SAAO,OAAO,SAAS,EAAE,KAAK,MAAM,IAAI,KAAK;AAC/C;AAgBO,IAAM,cAAN,MAAkB;AAAA,EASvB,YACmB,MACA,OACA,cACjB;AAHiB;AACA;AACA;AAKjB,SAAK,eAAe,EAAE,GAAG,OAAO,cAAc,OAAO;AAAA,EACvD;AAAA,EARmB;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAVF,QAAQ,oBAAI,IAA+C;AAAA;AAAA,EAE3D,WAAW,oBAAI,IAAY;AAAA,EACpC;AAAA,EACA;AAAA,EACS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBjB,QAAQ,UAAqD;AAC3D,QAAI,OAAO,KAAK,MAAM,IAAI,QAAQ;AAClC,QAAI,CAAC,MAAM;AACT,YAAM,SAAS;AAAA,QACb,KAAK;AAAA,QACL,KAAK;AAAA,QACL;AAAA,QACA,KAAK;AAAA,MACP;AAIA,YAAM,UAAU,OAAO,SAAS,SAAS,KAAK,WAAW;AACzD,aAAO;AAAA,QACL,OAAO,UAAU,WAAW,KAAK,IAAI,OAAO,OAAO,QAAQ;AAAA,QAC3D,QAAQ,OAAO;AAAA,MACjB;AACA,WAAK,MAAM,IAAI,UAAU,IAAI;AAAA,IAC/B;AACA,UAAM,SAAS,KAAK,gBAAgB,KAAK;AACzC,SAAK,SAAS,IAAI,MAAM;AACxB,WAAO,EAAE,OAAO,KAAK,OAAO,OAAO;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,OAAO,OAAe,KAAuB;AAC3C,QAAI,KAAK,SAAS,UAAU,OAAO;AACjC,WAAK,UAAU;AAAA,QACb;AAAA,QACA,QAAQ,WAAW,KAAK,MAAM,KAAK,OAAO,OAAO,KAAK,YAAY;AAAA,MACpE;AAAA,IACF;AACA,UAAM,EAAE,OAAO,IAAI,KAAK,QAAQ;AAChC,UAAM,SACJ,KAAK,SAAS,SAAS,KACtB,KAAK,SAAS,SAAS,KAAK,KAAK,SAAS,IAAI,MAAM;AACvD,SAAK,SAAS,MAAM;AACpB,QAAI,OAAQ,QAAO;AACnB,QAAI,IAAK,MAAK,eAAe;AAC7B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,QAAiB;AACf,UAAM,SAAS,KAAK,iBAAiB;AACrC,SAAK,eAAe;AACpB,SAAK,SAAS,MAAM;AACpB,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,IAAI,SAAuC;AACzC,WAAO,KAAK,SAAS;AAAA,EACvB;AACF;;;ACxOO,SAAS,UACd,KACA,GACA,GACA,OACA,QACA,cAMM;AACN,MAAI,UAAU;AAEd,MAAI,gBAAgB,UAAU,YAAY,GAAG;AAC3C,UAAM,EAAE,SAAS,UAAU,aAAa,WAAW,IAAI;AACvD;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF,OAAO;AACL,QAAI,KAAK,GAAG,GAAG,OAAO,MAAM;AAAA,EAC9B;AAEA,MAAI,KAAK;AACX;AAKO,SAAS,YACd,KACA,GACA,GACA,GACA,GACA,IACA,IACA,IACA,IACM;AACN,QAAM,OAAO,gBAAgB,GAAG,CAAC;AACjC,OAAK,KAAK,IAAI,IAAI,IAAI;AACtB,OAAK,KAAK,IAAI,IAAI,IAAI;AACtB,OAAK,KAAK,IAAI,IAAI,IAAI;AACtB,OAAK,KAAK,IAAI,IAAI,IAAI;AAEtB,MAAI,OAAO,IAAI,IAAI,CAAC;AACpB,MAAI,OAAO,IAAI,IAAI,IAAI,CAAC;AACxB,MAAI,KAAK,EAAG,KAAI,MAAM,IAAI,GAAG,GAAG,IAAI,GAAG,IAAI,IAAI,EAAE;AACjD,MAAI,OAAO,IAAI,GAAG,IAAI,IAAI,EAAE;AAC5B,MAAI,KAAK,EAAG,KAAI,MAAM,IAAI,GAAG,IAAI,GAAG,IAAI,IAAI,IAAI,IAAI,GAAG,EAAE;AACzD,MAAI,OAAO,IAAI,IAAI,IAAI,CAAC;AACxB,MAAI,KAAK,EAAG,KAAI,MAAM,GAAG,IAAI,GAAG,GAAG,IAAI,IAAI,IAAI,EAAE;AACjD,MAAI,OAAO,GAAG,IAAI,EAAE;AACpB,MAAI,KAAK,EAAG,KAAI,MAAM,GAAG,GAAG,IAAI,IAAI,GAAG,EAAE;AACzC,MAAI,UAAU;AAChB;AAQO,SAAS,gBAAgB,GAAW,GAAmB;AAC5D,SAAO,KAAK,IAAI,GAAG,CAAC,IAAI;AAC1B;AAEO,SAAS,UAAU,GAKd;AACV,SACE,EAAE,UAAU,KAAK,EAAE,WAAW,KAAK,EAAE,cAAc,KAAK,EAAE,aAAa;AAE3E;;;AC5FA,SAAS,cAAc;;;ACShB,SAAS,SACd,KACA,GACA,GACA,OACA,QACA,OACM;AACN,QAAM,eAAe,yBAAyB,OAAO,OAAO,MAAM;AAClE,QAAM,oBAAoB,UAAU,YAAY;AAGhD,MAAI,MAAM,iBAAiB;AACzB,QAAI,YAAY,MAAM;AAEtB,QAAI,mBAAmB;AACrB,UAAI,UAAU;AACd;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,aAAa;AAAA,QACb,aAAa;AAAA,QACb,aAAa;AAAA,QACb,aAAa;AAAA,MACf;AACA,UAAI,KAAK;AAAA,IACX,OAAO;AACL,UAAI,SAAS,GAAG,GAAG,OAAO,MAAM;AAAA,IAClC;AAAA,EACF;AAGA,cAAY,KAAK,GAAG,GAAG,OAAO,QAAQ,OAAO,YAAY;AAC3D;AAEA,SAAS,cAAc,GAAY,OAAe,QAAwB;AACxE,MAAI,OAAO,MAAM,SAAU,QAAO,eAAe,GAAG,KAAK,IAAI,OAAO,MAAM,CAAC;AAC3E,SAAO,SAAS,CAAC;AACnB;AAEO,SAAS,yBACd,OACA,OACA,QACA;AACA,SAAO;AAAA,IACL,SAAS,cAAc,MAAM,qBAAqB,OAAO,MAAM;AAAA,IAC/D,UAAU,cAAc,MAAM,sBAAsB,OAAO,MAAM;AAAA,IACjE,aAAa,cAAc,MAAM,yBAAyB,OAAO,MAAM;AAAA,IACvE,YAAY,cAAc,MAAM,wBAAwB,OAAO,MAAM;AAAA,EACvE;AACF;AAEA,SAAS,YACP,KACA,GACA,GACA,OACA,QACA,OACA,cACM;AACN,QAAM,oBAAoB,UAAU,YAAY;AAGhD,QAAM,KAAK,gBAAgB,MAAM,gBAAgB,KAAK;AACtD,QAAM,KAAK,gBAAgB,MAAM,kBAAkB,KAAK;AACxD,QAAM,KAAK,gBAAgB,MAAM,mBAAmB,KAAK;AACzD,QAAM,KAAK,gBAAgB,MAAM,iBAAiB,KAAK;AAEvD,MAAI,OAAO,KAAK,OAAO,KAAK,OAAO,KAAK,OAAO,EAAG;AAElD,QAAM,eAAe,OAAO,MAAM,OAAO,MAAM,OAAO,MAAM,KAAK;AACjE,QAAM,KAAK,MAAM,kBAAkB;AACnC,QAAM,KAAK,MAAM,oBAAoB;AACrC,QAAM,KAAK,MAAM,qBAAqB;AACtC,QAAM,KAAK,MAAM,mBAAmB;AACpC,QAAM,eAAe,OAAO,MAAM,OAAO,MAAM,OAAO;AAEtD,MAAI,gBAAgB,cAAc;AAChC,QAAI,cAAc;AAClB,QAAI,YAAY;AAEhB,QAAI,mBAAmB;AACrB,UAAI,UAAU;AACd,YAAM,OAAO,KAAK;AAClB;AAAA,QACE;AAAA,QACA,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,KAAK,IAAI,GAAG,aAAa,UAAU,IAAI;AAAA,QACvC,KAAK,IAAI,GAAG,aAAa,WAAW,IAAI;AAAA,QACxC,KAAK,IAAI,GAAG,aAAa,cAAc,IAAI;AAAA,QAC3C,KAAK,IAAI,GAAG,aAAa,aAAa,IAAI;AAAA,MAC5C;AACA,UAAI,OAAO;AAAA,IACb,OAAO;AACL,UAAI,WAAW,IAAI,KAAK,GAAG,IAAI,KAAK,GAAG,QAAQ,IAAI,SAAS,EAAE;AAAA,IAChE;AACA;AAAA,EACF;AAGA,MAAI,mBAAmB;AACrB,UAAM,OAAO,KAAK,IAAI,OAAO,MAAM,IAAI;AACvC,UAAM,KAAK,KAAK,IAAI,aAAa,SAAS,IAAI;AAC9C,UAAM,KAAK,KAAK,IAAI,aAAa,UAAU,IAAI;AAC/C,UAAM,KAAK,KAAK,IAAI,aAAa,aAAa,IAAI;AAClD,UAAM,KAAK,KAAK,IAAI,aAAa,YAAY,IAAI;AAEjD,UAAM,MAAM,IAAI,KAAK;AACrB,UAAM,QAAQ,IAAI,QAAQ,KAAK;AAC/B,UAAM,SAAS,IAAI,SAAS,KAAK;AACjC,UAAM,OAAO,IAAI,KAAK;AAEtB,UAAM,MAAM,KAAK,IAAI,GAAG,KAAK,KAAK,IAAI,IAAI,EAAE,IAAI,CAAC;AACjD,UAAM,MAAM,KAAK,IAAI,GAAG,KAAK,KAAK,IAAI,IAAI,EAAE,IAAI,CAAC;AACjD,UAAM,MAAM,KAAK,IAAI,GAAG,KAAK,KAAK,IAAI,IAAI,EAAE,IAAI,CAAC;AACjD,UAAM,MAAM,KAAK,IAAI,GAAG,KAAK,KAAK,IAAI,IAAI,EAAE,IAAI,CAAC;AAOjD,QAAI,KAAK,GAAG;AACV,UAAI,cAAc;AAClB,UAAI,YAAY;AAChB,UAAI,UAAU;AACd,UAAI,MAAM,KAAK,OAAO,GAAG;AACvB,YAAI,OAAO,MAAM,MAAM,GAAG;AAC1B,YAAI,MAAM,MAAM,KAAK,OAAO,KAAK,KAAK,GAAG;AAAA,MAC3C,WAAW,MAAM,GAAG;AAClB,YAAI,OAAO,OAAO,KAAK,GAAG;AAAA,MAC5B,OAAO;AACL,YAAI,OAAO,GAAG,GAAG;AAAA,MACnB;AACA,UAAI,MAAM,GAAG;AACX,YAAI,OAAO,QAAQ,KAAK,GAAG;AAC3B,YAAI,MAAM,OAAO,KAAK,OAAO,MAAM,KAAK,GAAG;AAAA,MAC7C,OAAO;AACL,YAAI,OAAO,IAAI,OAAO,GAAG;AAAA,MAC3B;AACA,UAAI,OAAO;AAAA,IACb;AAGA,QAAI,KAAK,GAAG;AACV,UAAI,cAAc;AAClB,UAAI,YAAY;AAChB,UAAI,UAAU;AACd,UAAI,MAAM,KAAK,OAAO,GAAG;AACvB,YAAI,OAAO,QAAQ,KAAK,GAAG;AAC3B,YAAI,MAAM,OAAO,KAAK,OAAO,MAAM,KAAK,GAAG;AAAA,MAC7C,WAAW,MAAM,GAAG;AAClB,YAAI,OAAO,OAAO,MAAM,GAAG;AAAA,MAC7B,OAAO;AACL,YAAI,OAAO,OAAO,CAAC;AAAA,MACrB;AACA,UAAI,MAAM,GAAG;AACX,YAAI,OAAO,OAAO,SAAS,GAAG;AAC9B,YAAI,MAAM,OAAO,QAAQ,QAAQ,KAAK,QAAQ,GAAG;AAAA,MACnD,OAAO;AACL,YAAI,OAAO,OAAO,IAAI,MAAM;AAAA,MAC9B;AACA,UAAI,OAAO;AAAA,IACb;AAGA,QAAI,KAAK,GAAG;AACV,UAAI,cAAc;AAClB,UAAI,YAAY;AAChB,UAAI,UAAU;AACd,UAAI,MAAM,KAAK,OAAO,GAAG;AACvB,YAAI,OAAO,OAAO,SAAS,GAAG;AAC9B,YAAI,MAAM,OAAO,QAAQ,QAAQ,KAAK,QAAQ,GAAG;AAAA,MACnD,WAAW,MAAM,GAAG;AAClB,YAAI,OAAO,QAAQ,KAAK,MAAM;AAAA,MAChC,OAAO;AACL,YAAI,OAAO,IAAI,OAAO,MAAM;AAAA,MAC9B;AACA,UAAI,MAAM,GAAG;AACX,YAAI,OAAO,OAAO,KAAK,MAAM;AAC7B,YAAI,MAAM,MAAM,QAAQ,MAAM,SAAS,KAAK,GAAG;AAAA,MACjD,OAAO;AACL,YAAI,OAAO,GAAG,MAAM;AAAA,MACtB;AACA,UAAI,OAAO;AAAA,IACb;AAGA,QAAI,KAAK,GAAG;AACV,UAAI,cAAc;AAClB,UAAI,YAAY;AAChB,UAAI,UAAU;AACd,UAAI,MAAM,KAAK,OAAO,GAAG;AACvB,YAAI,OAAO,OAAO,KAAK,MAAM;AAC7B,YAAI,MAAM,MAAM,QAAQ,MAAM,SAAS,KAAK,GAAG;AAAA,MACjD,WAAW,MAAM,GAAG;AAClB,YAAI,OAAO,MAAM,SAAS,GAAG;AAAA,MAC/B,OAAO;AACL,YAAI,OAAO,MAAM,IAAI,MAAM;AAAA,MAC7B;AACA,UAAI,MAAM,GAAG;AACX,YAAI,OAAO,MAAM,MAAM,GAAG;AAC1B,YAAI,MAAM,MAAM,KAAK,OAAO,KAAK,KAAK,GAAG;AAAA,MAC3C,OAAO;AACL,YAAI,OAAO,MAAM,CAAC;AAAA,MACpB;AACA,UAAI,OAAO;AAAA,IACb;AAAA,EACF,OAAO;AACL,QAAI,KAAK,GAAG;AACV,UAAI,cAAc;AAClB,UAAI,YAAY;AAChB,UAAI,UAAU;AACd,UAAI,OAAO,GAAG,IAAI,KAAK,CAAC;AACxB,UAAI,OAAO,IAAI,OAAO,IAAI,KAAK,CAAC;AAChC,UAAI,OAAO;AAAA,IACb;AACA,QAAI,KAAK,GAAG;AACV,UAAI,cAAc;AAClB,UAAI,YAAY;AAChB,UAAI,UAAU;AACd,UAAI,OAAO,IAAI,QAAQ,KAAK,GAAG,CAAC;AAChC,UAAI,OAAO,IAAI,QAAQ,KAAK,GAAG,IAAI,MAAM;AACzC,UAAI,OAAO;AAAA,IACb;AACA,QAAI,KAAK,GAAG;AACV,UAAI,cAAc;AAClB,UAAI,YAAY;AAChB,UAAI,UAAU;AACd,UAAI,OAAO,GAAG,IAAI,SAAS,KAAK,CAAC;AACjC,UAAI,OAAO,IAAI,OAAO,IAAI,SAAS,KAAK,CAAC;AACzC,UAAI,OAAO;AAAA,IACb;AACA,QAAI,KAAK,GAAG;AACV,UAAI,cAAc;AAClB,UAAI,YAAY;AAChB,UAAI,UAAU;AACd,UAAI,OAAO,IAAI,KAAK,GAAG,CAAC;AACxB,UAAI,OAAO,IAAI,KAAK,GAAG,IAAI,MAAM;AACjC,UAAI,OAAO;AAAA,IACb;AAAA,EACF;AACF;AAGA,IAAM,gBACJ;AAEK,SAAS,cACd,KACA,GACA,GACA,OACA,QACA,WACA,cACM;AACN,QAAM,QAAQ,UAAU,MAAM,aAAa;AAC3C,MAAI,CAAC,MAAO;AAEZ,QAAM,UAAU,WAAW,MAAM,CAAC,CAAE;AACpC,QAAM,UAAU,WAAW,MAAM,CAAC,CAAE;AACpC,QAAM,OAAO,WAAW,MAAM,CAAC,CAAE;AACjC,QAAM,QAAQ,MAAM,CAAC,EAAG,KAAK;AAE7B,QAAM,QAAQ;AAAA,IACZ,aAAa;AAAA,IACb,aAAa;AAAA,IACb,aAAa;AAAA,IACb,aAAa;AAAA,EACf;AAGA,QAAM,SAAS,OAAO,IAAI,KAAK,IAAI,OAAO,IAAI,KAAK,IAAI,OAAO;AAC9D,MAAI,KAAK;AACT,MAAI,UAAU;AACd,MAAI,KAAK,IAAI,QAAQ,IAAI,QAAQ,QAAQ,SAAS,GAAG,SAAS,SAAS,CAAC;AACxE,MAAI,UAAU,GAAG,GAAG,OAAO,QAAQ,KAAK;AACxC,MAAI,KAAK,SAAS;AAIlB,MAAI,SAAS,QAAQ,OAAO,CAAC;AAC7B,MAAI,UAAU,SAAS,OAAO;AAC9B,MAAI,YAAY;AAChB,MAAI,UAAU;AACd,MAAI,UAAU,GAAG,GAAG,OAAO,QAAQ,KAAK;AACxC,MAAI,KAAK;AACT,MAAI,QAAQ;AACd;;;AD9PA,IAAM,iBAAiB,oBAAI,IAAI;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,IAAM,aAAa,oBAAI,IAAoB;AAAA,EACzC,CAAC,QAAQ,CAAC;AAAA,EACV,CAAC,WAAW,CAAC;AAAA,EACb,CAAC,UAAU,GAAG;AAAA,EACd,CAAC,SAAS,CAAC;AAAA,EACX,CAAC,SAAS,CAAC;AACb,CAAC;AAED,IAAM,aAAa,oBAAI,IAAoB;AAAA,EACzC,CAAC,OAAO,CAAC;AAAA,EACT,CAAC,WAAW,CAAC;AAAA,EACb,CAAC,UAAU,GAAG;AAAA,EACd,CAAC,UAAU,CAAC;AAAA,EACZ,CAAC,SAAS,CAAC;AACb,CAAC;AAED,IAAM,cAAc,oBAAI,IAAI,CAAC,MAAM,MAAM,OAAO,SAAS,SAAS,QAAQ,CAAC;AAQpE,SAAS,cACd,KACA,UACA,OACA,GACA,GACA,OACA,QACM;AACN,QAAM,QAAQ,cAAc,UAAU,OAAO,EAAE,GAAG,GAAG,OAAO,OAAO,CAAC;AACpE,MAAI,CAAC,SAAS,MAAM,SAAS,OAAQ;AACrC,QAAM,OAAO,gBAAgB,KAAK;AAClC,MAAI,KAAM,KAAI,KAAK,MAAM,cAAc,KAAK,CAAC;AAC/C;AAEA,SAAS,cAAc,OAA4B;AACjD,SAAO,MAAM,SAAS,aAAa,MAAM,SAAS,SAC9C,MAAM,WACN;AACN;AAQO,SAAS,cACd,OACA,OACA,KACkB;AAClB,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,YAAY,OAAQ,QAAO,EAAE,MAAM,OAAO;AAI9C,MAAI,KAA4C;AAChD,MAAI,cAAc;AAClB,QAAM,UAAU,QAAQ,MAAM,8BAA8B;AAC5D,MAAI;AACJ,MAAI,SAAS;AACX,SAAK,EAAE,MAAM,QAAQ,CAAC,GAAI,MAAM,QAAQ,CAAC,EAAG;AAC5C,eAAW,CAAC,QAAQ,CAAC,GAAI,QAAQ,CAAC,CAAE,EACjC,KAAK,GAAG,EACR,MAAM,KAAK,EACX,OAAO,OAAO;AAAA,EACnB,OAAO;AACL,eAAW,QAAQ,MAAM,KAAK,EAAE,OAAO,OAAO;AAAA,EAChD;AACA,aAAW,MAAM,UAAU;AACzB,QAAI,CAAC,eAAe,IAAI,EAAE,EAAG,QAAO;AACpC,kBAAc;AAAA,EAChB;AACA,MAAI,CAAC,MAAM,SAAS,WAAW,EAAG,QAAO;AAEzC,QAAM,MAAM,oBAAoB,aAAa,OAAO,GAAG;AACvD,QAAM,EAAE,OAAO,GAAG,QAAQ,EAAE,IAAI;AAEhC,MAAI,CAAC,IAAI;AAGP,WAAO;AAAA,MACL,MAAM;AAAA,MACN,GAAG,IAAI;AAAA,MACP,GAAG,IAAI;AAAA,MACP,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,OAAO,kBAAkB,aAAa,OAAO,KAAK,GAAG;AAAA,IACvD;AAAA,EACF;AAEA,UAAQ,GAAG,MAAM;AAAA,IACf,KAAK;AACH,aAAO,WAAW,GAAG,MAAM,GAAG;AAAA,IAChC,KAAK;AACH,aAAO,UAAU,GAAG,MAAM,GAAG;AAAA,IAC/B,KAAK;AACH,aAAO,UAAU,GAAG,MAAM,GAAG;AAAA,IAC/B,KAAK;AACH,aAAO,YAAY,GAAG,MAAM,GAAG;AAAA,IACjC,KAAK;AACH,aAAO,aAAa,GAAG,MAAM,GAAG;AAAA,IAClC,KAAK;AACH,aAAO,aAAa,GAAG,MAAM,GAAG;AAAA,IAClC,KAAK;AACH,aAAO,UAAU,GAAG,MAAM,GAAG;AAAA,IAC/B,KAAK;AACH,aAAO,WAAW,GAAG,MAAM,GAAG;AAAA,IAChC;AACE,aAAO;AAAA,EACX;AACF;AAOO,SAAS,gBAAgB,OAAiC;AAC/D,QAAM,IAAI,IAAI,OAAO;AACrB,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH;AAAA,IACF,KAAK;AACH,UAAI,MAAM,SAAS,MAAM,QAAQ,KAAK,MAAM,SAAS,GAAG;AACtD;AAAA,UACE;AAAA,UACA,MAAM;AAAA,UACN,MAAM;AAAA,UACN,MAAM;AAAA,UACN,MAAM;AAAA,UACN,MAAM;AAAA,QACR;AAAA,MACF,OAAO;AACL,UAAE;AAAA,UACA,MAAM;AAAA,UACN,MAAM;AAAA,UACN,KAAK,IAAI,GAAG,MAAM,KAAK;AAAA,UACvB,KAAK,IAAI,GAAG,MAAM,MAAM;AAAA,QAC1B;AAAA,MACF;AACA;AAAA,IACF,KAAK;AACH,UAAI,MAAM,IAAI,EAAG,GAAE,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,GAAG,GAAG,KAAK,KAAK,CAAC;AAClE;AAAA,IACF,KAAK;AACH,UAAI,MAAM,KAAK,KAAK,MAAM,KAAK,GAAG;AAChC,UAAE,QAAQ,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,GAAG,GAAG,KAAK,KAAK,CAAC;AAAA,MACrE;AACA;AAAA,IACF,KAAK;AACH,UAAI,MAAM,OAAO,UAAU,GAAG;AAC5B,cAAM,CAAC,OAAO,GAAG,IAAI,IAAI,MAAM;AAC/B,UAAE,OAAO,MAAO,CAAC,GAAG,MAAO,CAAC,CAAC;AAC7B,mBAAW,CAAC,IAAI,EAAE,KAAK,KAAM,GAAE,OAAO,IAAI,EAAE;AAC5C,UAAE,UAAU;AAAA,MACd;AACA;AAAA,IACF,KAAK,QAAQ;AACX,UAAI;AACJ,UAAI;AACF,gBAAQ,IAAI,OAAO,MAAM,CAAC;AAAA,MAC5B,QAAQ;AACN,eAAO;AAAA,MACT;AACA,UAAI,MAAM,OAAO,KAAK,MAAM,OAAO,EAAG,QAAO;AAC7C,QAAE,QAAQ,OAAO,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC;AACrE;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAMA,SAAS,oBACP,aACA,OACA,KACc;AACd,QAAM,EAAE,GAAG,GAAG,OAAO,OAAO,IAAI;AAChC,UAAQ,aAAa;AAAA,IACnB,KAAK,eAAe;AAClB,YAAM,IAAI,gBAAgB,MAAM,gBAAgB,KAAK;AACrD,YAAM,IAAI,gBAAgB,MAAM,kBAAkB,KAAK;AACvD,YAAM,IAAI,gBAAgB,MAAM,mBAAmB,KAAK;AACxD,YAAM,IAAI,gBAAgB,MAAM,iBAAiB,KAAK;AACtD,aAAO;AAAA,QACL,GAAG,IAAI;AAAA,QACP,GAAG,IAAI;AAAA,QACP,OAAO,QAAQ,IAAI;AAAA,QACnB,QAAQ,SAAS,IAAI;AAAA,MACvB;AAAA,IACF;AAAA,IACA,KAAK,eAAe;AAClB,YAAM,IACJ,gBAAgB,MAAM,gBAAgB,KAAK,IAC3C,gBAAgB,MAAM,YAAY,KAAK;AACzC,YAAM,IACJ,gBAAgB,MAAM,kBAAkB,KAAK,IAC7C,gBAAgB,MAAM,cAAc,KAAK;AAC3C,YAAM,IACJ,gBAAgB,MAAM,mBAAmB,KAAK,IAC9C,gBAAgB,MAAM,eAAe,KAAK;AAC5C,YAAM,IACJ,gBAAgB,MAAM,iBAAiB,KAAK,IAC5C,gBAAgB,MAAM,aAAa,KAAK;AAC1C,aAAO;AAAA,QACL,GAAG,IAAI;AAAA,QACP,GAAG,IAAI;AAAA,QACP,OAAO,QAAQ,IAAI;AAAA,QACnB,QAAQ,SAAS,IAAI;AAAA,MACvB;AAAA,IACF;AAAA,IACA,KAAK,cAAc;AACjB,YAAM,IAAI,YAAY,MAAM,WAAW,KAAK;AAC5C,YAAM,IAAI,YAAY,MAAM,aAAa,KAAK;AAC9C,YAAM,IAAI,YAAY,MAAM,cAAc,KAAK;AAC/C,YAAM,IAAI,YAAY,MAAM,YAAY,KAAK;AAC7C,aAAO;AAAA,QACL,GAAG,IAAI;AAAA,QACP,GAAG,IAAI;AAAA,QACP,OAAO,QAAQ,IAAI;AAAA,QACnB,QAAQ,SAAS,IAAI;AAAA,MACvB;AAAA,IACF;AAAA,IACA;AACE,aAAO;AAAA,EACX;AACF;AAEA,SAAS,YAAY,GAAY,gBAAgC;AAC/D,MAAI,MAAM,OAAQ,QAAO;AACzB,SAAO,gBAAgB,GAAG,cAAc;AAC1C;AAWA,SAAS,kBACP,aACA,OACA,KACA,KACoB;AACpB,QAAM,KAAK,yBAAyB,OAAO,IAAI,OAAO,IAAI,MAAM;AAChE,QAAM,OAAO,gBAAgB,IAAI,OAAO,IAAI,MAAM;AAClD,QAAM,OAAO,CAAC,GAAG,SAAS,GAAG,UAAU,GAAG,aAAa,GAAG,UAAU,EAAE;AAAA,IACpE,CAAC,MAAM,KAAK,IAAI,KAAK,IAAI,GAAG,CAAC,GAAG,IAAI;AAAA,EACtC;AACA,MAAI,KAAK,MAAM,CAAC,MAAM,KAAK,CAAC,EAAG,QAAO;AAItC,QAAM,OAAO,IAAI,IAAI,IAAI;AACzB,QAAM,MAAM,IAAI,IAAI,IAAI;AACxB,QAAM,QAAQ,IAAI,IAAI,IAAI,SAAS,IAAI,IAAI,IAAI;AAC/C,QAAM,SAAS,IAAI,IAAI,IAAI,UAAU,IAAI,IAAI,IAAI;AACjD,QAAM,SAAuC;AAAA,IAC3C,CAAC,MAAM,GAAG;AAAA,IACV,CAAC,OAAO,GAAG;AAAA,IACX,CAAC,OAAO,MAAM;AAAA,IACd,CAAC,MAAM,MAAM;AAAA,EACf;AAEA,QAAM,QAAQ,KAAK,IAAI,CAAC,GAAG,MAAM;AAC/B,UAAM,CAAC,IAAI,EAAE,IAAI,OAAO,CAAC;AACzB,WAAO,CAAC,aAAa,GAAG,EAAE,GAAG,aAAa,GAAG,EAAE,CAAC;AAAA,EAClD,CAAC;AACD,MAAI,MAAM,MAAM,CAAC,CAAC,IAAI,EAAE,MAAM,MAAM,KAAK,MAAM,CAAC,EAAG,QAAO;AAC1D,SAAO,eAAe,OAAO,IAAI,OAAO,IAAI,MAAM;AACpD;AASA,SAAS,aAAa,GAAW,OAAuB;AACtD,MAAI,SAAS,EAAG,QAAO,KAAK,IAAI,GAAG,IAAI,KAAK;AAC5C,MAAI,KAAK,EAAG,QAAO;AACnB,QAAM,IAAI,CAAC;AACX,MAAI,KAAK,EAAG,QAAO,IAAI;AACvB,QAAM,QAAQ,IAAI,IAAI;AACtB,SAAO,IAAI,KAAK,IAAI,QAAQ,QAAQ;AACtC;AAMA,SAAS,WAAW,MAAc,KAAqC;AACrE,QAAM,CAAC,WAAW,SAAS,IAAI,WAAW,IAAI;AAC9C,QAAM,SAAS,SAAS,SAAS;AACjC,MAAI,OAAO,SAAS,KAAK,OAAO,SAAS,EAAG,QAAO;AACnD,QAAM,CAAC,GAAG,GAAG,GAAG,CAAC,IAAI,YAAY,MAAM;AACvC,QAAM,MAAM,eAAe,GAAG,IAAI,MAAM;AACxC,QAAM,QAAQ,eAAe,GAAG,IAAI,KAAK;AACzC,QAAM,SAAS,eAAe,GAAG,IAAI,MAAM;AAC3C,QAAM,OAAO,eAAe,GAAG,IAAI,KAAK;AACxC,MAAI,CAAC,KAAK,OAAO,QAAQ,IAAI,EAAE,KAAK,KAAK,EAAG,QAAO;AACnD,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,IAAI,IAAI;AAAA,IACR,IAAI,QAAQ,OAAO;AAAA,IACnB,IAAI,SAAS,MAAM;AAAA,IACnB;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,UAAU,MAAc,KAAqC;AACpE,QAAM,CAAC,UAAU,SAAS,IAAI,WAAW,IAAI;AAC7C,QAAM,SAAS,SAAS,QAAQ;AAChC,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,QAAM,CAAC,GAAG,GAAG,GAAG,CAAC,IAAI;AACrB,QAAM,MAAM,MAAM,SAAS,IAAI,eAAe,GAAG,IAAI,MAAM;AAC3D,QAAM,QAAQ,MAAM,SAAS,IAAI,QAAQ,eAAe,GAAG,IAAI,KAAK;AACpE,QAAM,SAAS,MAAM,SAAS,IAAI,SAAS,eAAe,GAAG,IAAI,MAAM;AACvE,QAAM,OAAO,MAAM,SAAS,IAAI,eAAe,GAAG,IAAI,KAAK;AAC3D,MAAI,CAAC,KAAK,OAAO,QAAQ,IAAI,EAAE,KAAK,KAAK,EAAG,QAAO;AAEnD,QAAM,KAAK,KAAK,IAAI,MAAM,KAAK;AAC/B,QAAM,KAAK,KAAK,IAAI,KAAK,MAAM;AAC/B,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,IAAI,IAAI;AAAA,IACR,KAAK;AAAA,IACL,KAAK;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,UAAU,MAAc,KAAqC;AACpE,QAAM,CAAC,UAAU,SAAS,IAAI,WAAW,IAAI;AAC7C,QAAM,SAAS,SAAS,QAAQ;AAChC,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,QAAM,CAAC,IAAI,IAAI,IAAI,EAAE,IAAI;AACzB,QAAM,IAAI,eAAe,IAAI,IAAI,KAAK;AACtC,QAAM,IAAI,eAAe,IAAI,IAAI,MAAM;AACvC,QAAM,IAAI,eAAe,IAAI,IAAI,KAAK;AACtC,QAAM,IAAI,eAAe,IAAI,IAAI,MAAM;AACvC,MAAI,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE,KAAK,KAAK,EAAG,QAAO;AACrC,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,IAAI,IAAI;AAAA,IACR,KAAK,IAAI,GAAG,CAAC;AAAA,IACb,KAAK,IAAI,GAAG,CAAC;AAAA,IACb;AAAA,IACA;AAAA,EACF;AACF;AAMA,SAAS,SACP,GACA,GACA,OACA,QACA,WACA,KACkB;AAClB,QAAM,IAAI,KAAK,IAAI,GAAG,KAAK;AAC3B,QAAM,IAAI,KAAK,IAAI,GAAG,MAAM;AAC5B,MAAI,QAA4B;AAChC,MAAI,cAAc,QAAW;AAC3B,UAAM,SAAS,WAAW,WAAW,IAAI,OAAO,IAAI,QAAQ,GAAG,CAAC;AAChE,QAAI,WAAW,OAAW,QAAO;AACjC,YAAQ;AAAA,EACV;AACA,SAAO,EAAE,MAAM,QAAQ,GAAG,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM;AAC1D;AAEA,SAAS,YAAY,MAAc,KAAqC;AACtE,QAAM,CAAC,YAAY,OAAO,IAAI,QAAQ,IAAI;AAC1C,QAAM,eAAe,SAAS,UAAU;AACxC,MAAI,aAAa,SAAS,EAAG,QAAO;AACpC,QAAM,MAAM,gBAAgB,SAAS,WAAW,EAAE,GAAG,IAAI,OAAO,IAAI,MAAM;AAC1E,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,CAAC,IAAI,EAAE,IAAI;AACjB,QAAM,UAAU,KAAK,IAAI,IAAI,IAAI,IAAI,QAAQ,IAAI,IAAI,SAAS,EAAE;AAChE,QAAM,WAAW,KAAK,IAAI,IAAI,IAAI,IAAI,QAAQ,IAAI,IAAI,SAAS,EAAE;AACjE,QAAM,cAAc,KAAK,MAAM,IAAI,OAAO,IAAI,MAAM,IAAI,KAAK;AAC7D,QAAM,IAAIC,eAAc,aAAa,CAAC,GAAG,SAAS,UAAU,WAAW;AACvE,MAAI,MAAM,OAAW,QAAO;AAC5B,SAAO,EAAE,MAAM,UAAU,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,GAAG,KAAK,IAAI,GAAG,CAAC,EAAE;AAC7E;AAEA,SAAS,aAAa,MAAc,KAAqC;AACvE,QAAM,CAAC,YAAY,OAAO,IAAI,QAAQ,IAAI;AAC1C,QAAM,eAAe,SAAS,UAAU;AACxC,MAAI,aAAa,WAAW,KAAK,aAAa,WAAW,EAAG,QAAO;AACnE,QAAM,MAAM,gBAAgB,SAAS,WAAW,EAAE,GAAG,IAAI,OAAO,IAAI,MAAM;AAC1E,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,CAAC,IAAI,EAAE,IAAI;AACjB,QAAM,KAAKA;AAAA,IACT,aAAa,CAAC;AAAA,IACd,KAAK,IAAI,IAAI,IAAI,QAAQ,EAAE;AAAA,IAC3B,KAAK,IAAI,IAAI,IAAI,QAAQ,EAAE;AAAA,IAC3B,IAAI;AAAA,EACN;AACA,QAAM,KAAKA;AAAA,IACT,aAAa,CAAC;AAAA,IACd,KAAK,IAAI,IAAI,IAAI,SAAS,EAAE;AAAA,IAC5B,KAAK,IAAI,IAAI,IAAI,SAAS,EAAE;AAAA,IAC5B,IAAI;AAAA,EACN;AACA,MAAI,OAAO,UAAa,OAAO,OAAW,QAAO;AACjD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,IAAI,IAAI,IAAI;AAAA,IACZ,IAAI,IAAI,IAAI;AAAA,IACZ,IAAI,KAAK,IAAI,GAAG,EAAE;AAAA,IAClB,IAAI,KAAK,IAAI,GAAG,EAAE;AAAA,EACpB;AACF;AAEA,SAAS,aAAa,MAAc,KAAqC;AACvE,QAAM,QAAQ,UAAU,IAAI;AAC5B,MAAI,WAAqB;AACzB,QAAM,QAAQ,MAAM,CAAC,GAAG,KAAK;AAC7B,MAAI,UAAU,aAAa,UAAU,WAAW;AAC9C,eAAW;AACX,UAAM,MAAM;AAAA,EACd;AACA,QAAM,SAAkB,CAAC;AACzB,aAAW,QAAQ,OAAO;AACxB,UAAM,OAAO,SAAS,IAAI;AAC1B,QAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,UAAM,KAAK,eAAe,KAAK,CAAC,GAAI,IAAI,KAAK;AAC7C,UAAM,KAAK,eAAe,KAAK,CAAC,GAAI,IAAI,MAAM;AAC9C,QAAI,MAAM,EAAE,KAAK,MAAM,EAAE,EAAG,QAAO;AACnC,WAAO,KAAK,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC;AAAA,EACtC;AACA,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,SAAO,EAAE,MAAM,WAAW,QAAQ,SAAS;AAC7C;AAEA,SAAS,UAAU,MAAc,KAAqC;AACpE,QAAM,QAAQ,UAAU,IAAI;AAC5B,MAAI,WAAqB;AACzB,QAAM,QAAQ,MAAM,CAAC,GAAG,KAAK;AAC7B,MAAI,UAAU,aAAa,UAAU,WAAW;AAC9C,eAAW;AACX,UAAM,MAAM;AAAA,EACd;AACA,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,QAAM,IAAI,QAAQ,MAAM,CAAC,EAAG,KAAK,CAAC;AAClC,MAAI,CAAC,EAAG,QAAO;AACf,SAAO,EAAE,MAAM,QAAQ,GAAG,IAAI,IAAI,GAAG,IAAI,IAAI,GAAG,SAAS;AAC3D;AAgBA,SAAS,WAAW,MAAc,KAAqC;AACrE,QAAM,EAAE,OAAO,GAAG,QAAQ,EAAE,IAAI;AAChC,QAAM,QAAQ,UAAU,IAAI;AAC5B,QAAM,QAAQ,MAAM,MAAM,GAAG,KAAK;AAClC,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,aAAa,MAAM,MAAM,yCAAyC;AACxE,MAAI,CAAC,WAAY,QAAO;AACxB,QAAM,WAAY,WAAW,CAAC,KAAK;AAEnC,MAAI,UAAU,aAAa,SAAS,WAAW,CAAC,CAAE,GAAG,GAAG,CAAC;AACzD,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI,eAAe;AACnB,MAAI,IAAI,IAAI,SAAS,OAAO,CAAC;AAE7B,aAAW,QAAQ,OAAO;AACxB,UAAM,SAAS,SAAS,IAAI;AAC5B,UAAM,UAAU,OAAO,MAAM;AAE7B,YAAQ,SAAS;AAAA,MACf,KAAK,SAAS;AACZ,YAAI,OAAO,OAAQ,QAAO;AAC1B,aAAK;AACL,kBAAU;AACV;AAAA,MACF;AAAA,MACA,KAAK;AAAA,MACL,KAAK,QAAQ;AACX,cAAM,MAAM,gBAAgB,QAAQ,SAAS,GAAG,CAAC;AACjD,YAAI,CAAC,IAAK,QAAO;AACjB,aAAK,IAAI,YAAY,SAAS,MAAM,GAAG,GAAG,SAAS,GAAG,CAAC;AACvD,kBAAU;AACV,YAAI,YAAY,OAAQ,gBAAe;AACvC;AAAA,MACF;AAAA,MACA,KAAK;AAAA,MACL,KAAK,SAAS;AACZ,cAAM,CAAC,MAAM,OAAO,GAAG,IAAI,IAAI;AAC/B,YAAK,SAAS,QAAQ,SAAS,QAAS,CAAC,SAAS,KAAK,QAAQ;AAC7D,iBAAO;AAAA,QACT;AACA,cAAM,OAAO,YAAY,UAAU,IAAI;AACvC,cAAM,OAAO,SAAS,IAAI,IAAI;AAC9B,cAAM,WAAW,SAAS,IAAI,aAAa;AAC3C,cAAM,KAAK,SAAS,IAAI,KAAK;AAC7B,cAAM,WACJ,SAAS,QAAQ,OAAO,SACpB,KAAK,OACL,eAAe,OAAO,IAAI;AAChC,YAAI,MAAM,QAAQ,EAAG,QAAO;AAC5B,cAAM,OAAc,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC;AAC3C,aAAK,IAAI,IAAI,SAAS,OAAO,QAAQ,IAAI,IAAI,WAAW;AACxD,aAAK,SAAS,IAAI,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC;AACzD,kBAAU;AACV;AAAA,MACF;AAAA,MACA,KAAK;AAAA,MACL,KAAK,UAAU;AACb,cAAM,YAAY,OAAO,QAAQ,MAAM;AACvC,cAAM,YACJ,cAAc,KAAK,SAAS,OAAO,MAAM,GAAG,SAAS;AACvD,cAAM,gBACJ,cAAc,KAAK,CAAC,IAAI,OAAO,MAAM,YAAY,CAAC;AACpD,cAAM,OAAO,UAAU,CAAC;AACxB,cAAM,MAAM,gBAAgB,WAAW,SAAS,GAAG,CAAC;AACpD,YAAI,CAAC,IAAK,QAAO;AACjB,YAAI,YAAY,WAAW,cAAc,GAAI,QAAO;AAEpD,cAAM,WAAoB,CAAC;AAC3B,mBAAW,WAAW,aAAa,aAAa,GAAG;AACjD,gBAAM,QAAQ,oBAAoB,SAAS,MAAM,SAAS,KAAK,GAAG,CAAC;AACnE,cAAI,CAAC,MAAO,QAAO;AACnB,mBAAS,KAAK,KAAK;AAAA,QACrB;AAEA,YAAI,YAAY,SAAS;AACvB,cAAI,SAAS,WAAW,GAAG;AACzB,iBAAK,KAAK,SAAS,SAAS,CAAC,CAAE,CAAC,IAAI,SAAS,GAAG,CAAC;AAAA,UACnD,WAAW,SAAS,WAAW,GAAG;AAChC,iBAAK,KAAK,SAAS,SAAS,CAAC,CAAE,CAAC,IAAI,SAAS,SAAS,CAAC,CAAE,CAAC,IAAI,SAAS,GAAG,CAAC;AAAA,UAC7E,OAAO;AACL,mBAAO;AAAA,UACT;AAAA,QACF,WAAW,SAAS,WAAW,GAAG;AAChC,eAAK,KAAK,SAAS,GAAG,CAAC;AAAA,QACzB,WAAW,SAAS,WAAW,GAAG;AAChC,eAAK,KAAK,SAAS,SAAS,CAAC,CAAE,CAAC,IAAI,SAAS,GAAG,CAAC;AAAA,QACnD,OAAO;AACL,iBAAO;AAAA,QACT;AACA,kBAAU;AACV;AAAA,MACF;AAAA,MACA,KAAK,OAAO;AACV,cAAM,cAAc,OAAO,UAAU,CAAC,MAAM,YAAY,IAAI,CAAC,CAAC;AAC9D,cAAM,YACJ,gBAAgB,KAAK,SAAS,OAAO,MAAM,GAAG,WAAW;AAC3D,cAAM,UAAU,gBAAgB,KAAK,CAAC,IAAI,OAAO,MAAM,WAAW;AAClE,cAAM,MAAM,gBAAgB,WAAW,SAAS,GAAG,CAAC;AACpD,YAAI,CAAC,IAAK,QAAO;AAEjB,YAAI,KAAK;AACT,YAAI,KAAK;AACT,YAAI,WAAW;AACf,YAAI,QAAQ;AACZ,YAAI,QAAQ;AACZ,iBAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,gBAAM,SAAS,QAAQ,CAAC;AACxB,cAAI,WAAW,MAAM;AACnB,kBAAM,KAAK,QAAQ,EAAE,CAAC;AACtB,gBAAI,CAAC,GAAI,QAAO;AAChB,kBAAM,KAAK,QAAQ,IAAI,CAAC;AACxB,kBAAM,YAAY,OAAO,UAAa,CAAC,YAAY,IAAI,EAAE;AACzD,gBAAI,WAAW;AACb;AACA,mBAAK,eAAe,IAAI,CAAC;AACzB,mBAAK,eAAe,IAAK,CAAC;AAAA,YAC5B,OAAO;AACL,mBAAK,KAAK,eAAe,IAAI,KAAK,MAAM,GAAG,CAAC,IAAI,KAAK,KAAK;AAAA,YAC5D;AACA,gBAAI,MAAM,EAAE,KAAK,MAAM,EAAE,EAAG,QAAO;AAAA,UACrC,WAAW,WAAW,QAAQ,WAAW,OAAO;AAC9C,oBAAQ,WAAW,OAAO,IAAI;AAAA,UAChC,WAAW,WAAW,WAAW,WAAW,SAAS;AACnD,oBAAQ,WAAW,UAAU,IAAI;AAAA,UACnC,WAAW,WAAW,UAAU;AAC9B,kBAAM,QAAQ,QAAQ,EAAE,CAAC;AACzB,gBAAI,CAAC,MAAO,QAAO;AACnB,uBAAW,kBAAkB,KAAK;AAClC,gBAAI,MAAM,QAAQ,EAAG,QAAO;AAAA,UAC9B,OAAO;AACL,mBAAO;AAAA,UACT;AAAA,QACF;AACA,aAAK,KAAK,IAAI,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,KAAK,IAAI,KAAK,IAAI,SAAS,GAAG,CAAC;AACpG,kBAAU;AACV;AAAA,MACF;AAAA,MACA;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAEA,SAAO,EAAE,MAAM,QAAQ,GAAG,IAAI,IAAI,GAAG,IAAI,IAAI,GAAG,SAAS;AAC3D;AAEA,SAAS,gBACP,QACA,SACA,GACA,GACc;AACd,QAAM,OAAO,OAAO,CAAC;AACrB,MAAI,SAAS,QAAQ,SAAS,KAAM,QAAO;AAC3C,QAAM,QAAQ,aAAa,OAAO,MAAM,CAAC,GAAG,GAAG,CAAC;AAChD,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,SAAS,OAAO,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,MAAM,CAAC,CAAC,IAAI;AAC1E;AAOA,SAAS,oBACP,QACA,MACA,OACA,KACA,GACA,GACc;AACd,MAAI,SAAqC,SAAS,OAAO,UAAU;AACnE,MAAI,SAAS;AACb,QAAM,YAAY,OAAO,QAAQ,MAAM;AACvC,MAAI,cAAc,IAAI;AACpB,UAAM,MAAM,OAAO,YAAY,CAAC;AAChC,QACG,QAAQ,WAAW,QAAQ,SAAS,QAAQ,YAC7C,OAAO,WAAW,YAAY,GAC9B;AACA,aAAO;AAAA,IACT;AACA,aAAS;AACT,aAAS,OAAO,MAAM,GAAG,SAAS;AAAA,EACpC;AACA,QAAM,QAAQ,aAAa,QAAQ,GAAG,CAAC;AACvC,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,OACJ,WAAW,UAAU,QAAQ,WAAW,QAAQ,MAAM,CAAC,GAAG,CAAC;AAC7D,SAAO,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,MAAM,CAAC,CAAC;AAChD;AAGA,SAAS,aAAa,QAAkB,GAAW,GAAyB;AAC1E,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,QAAM,IAAI,YAAY,OAAO,CAAC,GAAI,GAAG,UAAU;AAC/C,QAAM,IAAI,YAAY,OAAO,CAAC,GAAI,GAAG,UAAU;AAC/C,MAAI,MAAM,CAAC,KAAK,MAAM,CAAC,EAAG,QAAO;AACjC,SAAO,CAAC,GAAG,CAAC;AACd;AAUA,SAAS,gBAAgB,QAAkB,GAAW,GAAyB;AAC7E,MAAI,OAAO,WAAW,EAAG,QAAO,CAAC,IAAI,GAAG,IAAI,CAAC;AAE7C,MAAI,OAAO,WAAW,GAAG;AACvB,UAAM,IAAI,OAAO,CAAC;AAClB,QAAI,WAAW,IAAI,CAAC,KAAK,CAAC,WAAW,IAAI,CAAC,GAAG;AAC3C,aAAO,CAAC,IAAI,GAAG,WAAW,IAAI,CAAC,IAAK,CAAC;AAAA,IACvC;AACA,UAAMC,KAAI,YAAY,GAAG,GAAG,UAAU;AACtC,WAAO,MAAMA,EAAC,IAAI,OAAO,CAACA,IAAG,IAAI,CAAC;AAAA,EACpC;AAEA,MAAI,OAAO,WAAW,GAAG;AACvB,QAAI,CAAC,GAAG,CAAC,IAAI;AAIb,UAAM,gBACH,WAAW,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,OACrC,WAAW,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC;AACxC,QACE,iBACE,WAAW,IAAI,CAAC,KAAK,CAAC,WAAW,IAAI,CAAC,KACrC,WAAW,IAAI,CAAC,KAAK,CAAC,WAAW,IAAI,CAAC,IACzC;AACA,OAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC;AAAA,IAChB;AACA,UAAMA,KAAI,YAAY,GAAG,GAAG,UAAU;AACtC,UAAMC,KAAI,YAAY,GAAG,GAAG,UAAU;AACtC,WAAO,MAAMD,EAAC,KAAK,MAAMC,EAAC,IAAI,OAAO,CAACD,IAAGC,EAAC;AAAA,EAC5C;AAGA,MAAI,IAAI,IAAI;AACZ,MAAI,IAAI,IAAI;AACZ,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,UAAM,IAAI,OAAO,CAAC;AAClB,UAAM,OAAO,OAAO,IAAI,CAAC;AACzB,UAAM,YACJ,SAAS,UAAa,CAAC,WAAW,IAAI,IAAI,KAAK,CAAC,WAAW,IAAI,IAAI;AACrE,QAAI,MAAM,UAAU,MAAM,SAAS;AACjC,YAAM,MAAM,YAAY,eAAe,MAAO,CAAC,IAAI;AACnD,UAAI,MAAM,GAAG,EAAG,QAAO;AACvB,UAAI,MAAM,SAAS,MAAM,IAAI;AAAA,IAC/B,WAAW,MAAM,SAAS,MAAM,UAAU;AACxC,YAAM,MAAM,YAAY,eAAe,MAAO,CAAC,IAAI;AACnD,UAAI,MAAM,GAAG,EAAG,QAAO;AACvB,UAAI,MAAM,QAAQ,MAAM,IAAI;AAAA,IAC9B,WAAW,MAAM,UAAU;AACzB,aAAO;AAAA,IACT;AACA,QAAI,UAAW;AAAA,EACjB;AACA,SAAO,CAAC,GAAG,CAAC;AACd;AAEA,SAAS,YACP,OACA,MACA,UACQ;AACR,QAAM,KAAK,SAAS,IAAI,KAAK;AAC7B,MAAI,OAAO,OAAW,QAAO,KAAK;AAClC,SAAO,eAAe,OAAO,IAAI;AACnC;AAEA,SAASF,eACP,OACA,aACA,cACA,aACoB;AACpB,MAAI,UAAU,UAAa,UAAU,eAAgB,QAAO;AAC5D,MAAI,UAAU,gBAAiB,QAAO;AACtC,QAAM,IAAI,eAAe,OAAO,WAAW;AAC3C,SAAO,MAAM,CAAC,IAAI,SAAY;AAChC;AASA,SAAS,WACP,OACA,MACA,MACA,GACA,GACgC;AAChC,QAAM,CAAC,OAAO,KAAK,IAAI,MAAM,MAAM,GAAG;AACtC,QAAM,UAAU,SAAS,SAAS,EAAE;AACpC,QAAM,UAAU,UAAU,SAAY,UAAU,SAAS,KAAK;AAC9D,MACE,QAAQ,SAAS,KACjB,QAAQ,SAAS,KACjB,QAAQ,SAAS,KACjB,QAAQ,SAAS,GACjB;AACA,WAAO;AAAA,EACT;AACA,QAAM,KAAK,YAAY,OAAO,EAAE,IAAI,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC;AAClE,QAAM,KAAK,YAAY,OAAO,EAAE,IAAI,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC;AAClE,MAAI,CAAC,GAAG,IAAI,GAAG,EAAE,EAAE,KAAK,KAAK,EAAG,QAAO;AACvC,QAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,MAAM;AAAA,IAC9B,KAAK,IAAI,GAAG,EAAE;AAAA,IACd,KAAK,IAAI,GAAG,GAAG,CAAC,CAAE;AAAA,EACpB,CAAC;AACD,MAAI,MAAM,MAAM,CAAC,CAAC,IAAI,EAAE,MAAM,MAAM,KAAK,MAAM,CAAC,EAAG,QAAO;AAC1D,SAAO,eAAe,OAAO,GAAG,CAAC;AACnC;AAMA,SAAS,eAAe,OAAoB,GAAW,GAAwB;AAC7E,QAAM,CAAC,IAAI,IAAI,IAAI,EAAE,IAAI;AACzB,MAAI,IAAI;AACR,QAAM,WAAW,CAAC,KAAa,WAAmB;AAChD,QAAI,MAAM,KAAK,SAAS,MAAM,EAAG,KAAI,SAAS;AAAA,EAChD;AACA,WAAS,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC;AACzB,WAAS,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC;AACzB,WAAS,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC;AACzB,WAAS,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC;AACzB,MAAI,KAAK,EAAG,QAAO;AACnB,SAAO,MAAM,IAAI,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC;AACjD;AAKA,SAAS,gBACP,GACA,GACA,GACA,GACA,GACA,OACM;AACN,QAAM,CAAC,IAAI,IAAI,IAAI,EAAE,IAAI;AACzB,QAAM,QAAQ,CAAC,MAAa,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC,IAAI;AAC/C,QAAM,OAAO,KAAK,KAAK;AAEvB,IAAE,OAAO,KAAK,MAAM,EAAE,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC;AACvC,IAAE,OAAO,IAAI,KAAK,MAAM,EAAE,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC;AAC3C,MAAI,MAAM,EAAE,GAAG;AACb,MAAE,QAAQ,IAAI,IAAI,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC;AAAA,EAC/D;AACA,IAAE,OAAO,IAAI,GAAG,IAAI,KAAK,MAAM,EAAE,IAAI,GAAG,CAAC,IAAI,EAAE;AAC/C,MAAI,MAAM,EAAE,GAAG;AACb,MAAE,QAAQ,IAAI,IAAI,GAAG,CAAC,GAAG,IAAI,IAAI,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,GAAG,IAAI;AAAA,EAClE;AACA,IAAE,OAAO,KAAK,MAAM,EAAE,IAAI,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC;AAC3C,MAAI,MAAM,EAAE,GAAG;AACb,MAAE,QAAQ,IAAI,GAAG,CAAC,GAAG,IAAI,IAAI,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,MAAM,KAAK,EAAE;AAAA,EACpE;AACA,IAAE,OAAO,GAAG,KAAK,MAAM,EAAE,IAAI,GAAG,CAAC,IAAI,EAAE;AACvC,MAAI,MAAM,EAAE,GAAG;AACb,MAAE,QAAQ,IAAI,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,KAAK,IAAI,IAAI,IAAI;AAAA,EACpE;AACA,IAAE,UAAU;AACd;AAEA,SAAS,YAAY,QAAoD;AACvE,QAAM,CAAC,GAAG,GAAG,GAAG,CAAC,IAAI;AACrB,UAAQ,OAAO,QAAQ;AAAA,IACrB,KAAK;AACH,aAAO,CAAC,GAAI,GAAI,GAAI,CAAE;AAAA,IACxB,KAAK;AACH,aAAO,CAAC,GAAI,GAAI,GAAI,CAAE;AAAA,IACxB,KAAK;AACH,aAAO,CAAC,GAAI,GAAI,GAAI,CAAE;AAAA,IACxB;AACE,aAAO,CAAC,GAAI,GAAI,GAAI,CAAE;AAAA,EAC1B;AACF;AAGA,SAAS,WAAW,MAA4C;AAC9D,QAAM,IAAI,KAAK,MAAM,uBAAuB;AAC5C,MAAI,CAAC,EAAG,QAAO,CAAC,MAAM,MAAS;AAC/B,SAAO,CAAC,EAAE,CAAC,GAAI,EAAE,CAAC,CAAE;AACtB;AAGA,SAAS,QAAQ,MAA4C;AAC3D,QAAM,IAAI,KAAK,MAAM,oBAAoB;AACzC,MAAI,CAAC,EAAG,QAAO,CAAC,MAAM,MAAS;AAC/B,SAAO,CAAC,EAAE,CAAC,GAAI,EAAE,CAAC,CAAE;AACtB;AAGA,SAAS,UAAU,SAA2B;AAC5C,QAAM,QAAkB,CAAC;AACzB,MAAI,UAAU;AACd,MAAI,QAAQ;AACZ,MAAI,QAAuB;AAC3B,aAAW,QAAQ,SAAS;AAC1B,QAAI,OAAO;AACT,UAAI,SAAS,MAAO,SAAQ;AAC5B,iBAAW;AACX;AAAA,IACF;AACA,QAAI,SAAS,OAAO,SAAS,KAAK;AAChC,cAAQ;AACR,iBAAW;AACX;AAAA,IACF;AACA,QAAI,SAAS,IAAK;AAClB,QAAI,SAAS,IAAK;AAClB,QAAI,SAAS,OAAO,UAAU,GAAG;AAC/B,YAAM,KAAK,OAAO;AAClB,gBAAU;AAAA,IACZ,OAAO;AACL,iBAAW;AAAA,IACb;AAAA,EACF;AACA,MAAI,QAAQ,KAAK,EAAG,OAAM,KAAK,OAAO;AACtC,SAAO;AACT;AAEA,SAAS,aAAa,QAA8B;AAClD,MAAI,OAAO,WAAW,EAAG,QAAO,CAAC;AACjC,QAAM,QAAQ,OAAO,QAAQ,GAAG;AAChC,SAAO,UAAU,KACb,CAAC,MAAM,IACP,CAAC,OAAO,MAAM,GAAG,KAAK,GAAG,OAAO,MAAM,QAAQ,CAAC,CAAC;AACtD;AAEA,SAAS,SAAS,OAAyB;AACzC,SAAO,MAAM,KAAK,EAAE,QAAQ,OAAO,KAAK,EAAE,MAAM,KAAK,EAAE,OAAO,OAAO;AACvE;AAEA,SAAS,QAAQ,GAAmB;AAClC,MACE,EAAE,UAAU,MACV,EAAE,WAAW,GAAG,KAAK,EAAE,SAAS,GAAG,KAClC,EAAE,WAAW,GAAG,KAAK,EAAE,SAAS,GAAG,IACtC;AACA,WAAO,EAAE,MAAM,GAAG,EAAE;AAAA,EACtB;AACA,SAAO;AACT;AAEA,SAAS,kBAAkB,OAAuB;AAChD,QAAM,IAAI,WAAW,KAAK;AAC1B,MAAI,MAAM,CAAC,EAAG,QAAO;AACrB,MAAI,MAAM,SAAS,KAAK,EAAG,QAAO;AAClC,MAAI,MAAM,SAAS,MAAM,EAAG,QAAO,IAAI;AACvC,MAAI,MAAM,SAAS,KAAK,EAAG,QAAQ,IAAI,MAAO,KAAK;AACnD,MAAI,MAAM,SAAS,MAAM,EAAG,QAAO,IAAI;AACvC,SAAO;AACT;AAEA,SAAS,IAAI,GAAmB;AAC9B,SAAO,OAAO,KAAK,MAAM,IAAI,GAAI,IAAI,GAAI;AAC3C;AAEA,SAAS,SAAS,GAAkB;AAClC,SAAO,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;AAClC;;;AEr/BO,SAAS,sBACd,KACA,aACA,GACA,GACA,OACA,QACuB;AACvB,QAAM,UAAU,YAAY,KAAK;AAEjC,MAAI,QAAQ,WAAW,iBAAiB,GAAG;AACzC,WAAO,oBAAoB,KAAK,SAAS,GAAG,GAAG,OAAO,MAAM;AAAA,EAC9D;AAEA,MAAI,QAAQ,WAAW,iBAAiB,GAAG;AACzC,WAAO,oBAAoB,KAAK,SAAS,GAAG,GAAG,OAAO,MAAM;AAAA,EAC9D;AAEA,SAAO;AACT;AAEA,SAAS,oBACP,KACA,KACA,GACA,GACA,OACA,QACuB;AAEvB,QAAM,QAAQ,IAAI,MAAM,0BAA0B;AAClD,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,UAAU,MAAM,CAAC,EAAG,KAAK;AAC/B,QAAM,QAAQ,kBAAkB,OAAO;AAEvC,MAAI,QAAQ;AACZ,MAAI,gBAAgB;AAGpB,QAAM,QAAQ,MAAM,CAAC,GAAG,KAAK;AAC7B,MAAI,OAAO;AACT,QAAI,MAAM,WAAW,KAAK,GAAG;AAC3B,cAAQ,iBAAiB,KAAK;AAC9B,sBAAgB;AAAA,IAClB,WAAW,MAAM,SAAS,KAAK,GAAG;AAChC,cAAQ,WAAW,KAAK;AACxB,sBAAgB;AAAA,IAClB,WAAW,MAAM,SAAS,MAAM,GAAG;AACjC,cAAQ,WAAW,KAAK,IAAI;AAC5B,sBAAgB;AAAA,IAClB;AAAA,EACF;AAGA,QAAM,OAAQ,QAAQ,MAAM,KAAK,KAAM;AACvC,QAAM,KAAK,IAAI,QAAQ;AACvB,QAAM,KAAK,IAAI,SAAS;AACxB,QAAM,WACJ,KAAK,IAAI,QAAQ,KAAK,IAAI,GAAG,CAAC,IAAI,IAAI,KAAK,IAAI,SAAS,KAAK,IAAI,GAAG,CAAC,IAAI;AAE3E,QAAM,KAAK,KAAK,WAAW,KAAK,IAAI,GAAG;AACvC,QAAM,KAAK,KAAK,WAAW,KAAK,IAAI,GAAG;AACvC,QAAM,KAAK,KAAK,WAAW,KAAK,IAAI,GAAG;AACvC,QAAM,KAAK,KAAK,WAAW,KAAK,IAAI,GAAG;AAEvC,QAAM,WAAW,IAAI,qBAAqB,IAAI,IAAI,IAAI,EAAE;AAGxD,QAAM,QAAQ,MAAM,MAAM,aAAa;AACvC,gBAAc,UAAU,KAAK;AAE7B,SAAO;AACT;AAEA,SAAS,oBACP,KACA,KACA,GACA,GACA,OACA,QACuB;AACvB,QAAM,QAAQ,IAAI,MAAM,0BAA0B;AAClD,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,UAAU,MAAM,CAAC,EAAG,KAAK;AAC/B,QAAM,QAAQ,kBAAkB,OAAO;AAEvC,QAAM,KAAK,IAAI,QAAQ;AACvB,QAAM,KAAK,IAAI,SAAS;AACxB,QAAM,SAAS,KAAK,IAAI,OAAO,MAAM,IAAI;AAEzC,QAAM,WAAW,IAAI,qBAAqB,IAAI,IAAI,GAAG,IAAI,IAAI,MAAM;AAGnE,MAAI,gBAAgB;AACpB,QAAM,QAAQ,MAAM,CAAC,GAAG,KAAK,KAAK;AAClC,MACE,MAAM,WAAW,QAAQ,KACzB,MAAM,WAAW,SAAS,KAC1B,MAAM,WAAW,SAAS,KAC1B,MAAM,WAAW,UAAU,GAC3B;AACA,oBAAgB;AAAA,EAClB;AAEA,gBAAc,UAAU,MAAM,MAAM,aAAa,CAAC;AAElD,SAAO;AACT;AAEA,SAAS,cAAc,UAA0B,OAAuB;AACtE,MAAI,MAAM,WAAW,EAAG;AAExB,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,OAAO,MAAM,CAAC,EAAG,KAAK;AAC5B,UAAM,eAAe,KAAK,MAAM,6BAA6B;AAE7D,QAAI,cAAc;AAChB,YAAM,QAAQ,aAAa,CAAC;AAC5B,YAAM,MAAM,aAAa,CAAC;AAC1B,YAAM,SAAS,IAAI,SAAS,GAAG,IAC3B,WAAW,GAAG,IAAI,MAClB,WAAW,GAAG;AAClB,eAAS,aAAa,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,MAAM,CAAC,GAAG,KAAK;AAAA,IAC/D,OAAO;AAEL,YAAM,SAAS,MAAM,WAAW,IAAI,MAAM,KAAK,MAAM,SAAS;AAC9D,eAAS,aAAa,QAAQ,IAAI;AAAA,IACpC;AAAA,EACF;AACF;AAEA,SAAS,iBAAiB,KAAqB;AAC7C,QAAM,MAA8B;AAAA,IAClC,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,WAAW;AAAA,IACX,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,mBAAmB;AAAA,IACnB,kBAAkB;AAAA,EACpB;AACA,SAAO,IAAI,GAAG,KAAK;AACrB;AAEO,SAAS,kBAAkB,SAA2B;AAC3D,QAAM,QAAkB,CAAC;AACzB,MAAI,UAAU;AACd,MAAI,aAAa;AAEjB,aAAW,QAAQ,SAAS;AAC1B,QAAI,SAAS,IAAK;AAClB,QAAI,SAAS,IAAK;AAClB,QAAI,SAAS,OAAO,eAAe,GAAG;AACpC,YAAM,KAAK,OAAO;AAClB,gBAAU;AAAA,IACZ,OAAO;AACL,iBAAW;AAAA,IACb;AAAA,EACF;AACA,MAAI,QAAQ,KAAK,EAAG,OAAM,KAAK,OAAO;AAEtC,SAAO;AACT;;;AClKA,SAAS,YAAY,gBAAgB;AAQrC,SAAS,WAAW,QAAqC;AACvD,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,aAAa,OAAO,KAAK;AAC/B,SAAO,eAAe,MAAM,eAAe;AAC7C;AAOO,SAAS,kBACd,KACA,SACA,QACS;AACT,QAAM,YAAY,CAAC,WAAW,MAAM;AACpC,MAAI,WAAW,KAAK,CAAC,UAAW,QAAO;AACvC,aAAW,KAAK,EAAE,SAAS,QAAQ,YAAY,OAAQ,KAAK,IAAI,OAAU,CAAC;AAC3E,SAAO;AACT;AAEO,SAAS,gBAAgB,KAA0B;AACxD,WAAS,GAAG;AACd;AAgBO,SAAS,mBACd,KACA,QACA,GACA,GACA,OACA,QACA,cACA,SACM;AACN,MAAI,SAAS,KAAK,UAAU,EAAG;AAC/B,MAAI,WAAW,MAAM,EAAG;AACxB,MAAI,KAAK;AACT,YAAU,KAAK,GAAG,GAAG,OAAO,QAAQ,YAAY;AAChD,aAAW,KAAK,EAAE,gBAAgB,OAAO,KAAK,GAAG,QAAQ,CAAC;AAC1D,WAAS,GAAG;AACZ,MAAI,QAAQ;AACd;;;ACzDO,SAAS,aACd,MACA,MACA,MACA,MACA,MACA,MACS;AACT,QAAM,WAAW,OAAO;AACxB,QAAM,WAAW,OAAO;AAExB,MAAI,IAAY,IAAY,IAAY;AAExC,MAAI,WAAW,UAAU;AACvB,SAAK;AACL,SAAK,OAAO;AACZ,UAAM,OAAO,MAAM;AACnB,SAAK;AAAA,EACP,OAAO;AACL,SAAK;AACL,SAAK,OAAO;AACZ,SAAK;AACL,UAAM,OAAO,MAAM;AAAA,EACrB;AAEA,SAAO,EAAE,IAAI,IAAI,IAAI,IAAI,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,KAAK;AAClE;AAMO,SAAS,eACd,MACA,MACA,MACA,MACA,MACA,MACS;AACT,QAAM,WAAW,OAAO;AACxB,QAAM,WAAW,OAAO;AAExB,MAAI,IAAY;AAEhB,MAAI,WAAW,UAAU;AACvB,SAAK;AACL,SAAK,OAAO;AAAA,EACd,OAAO;AACL,SAAK;AACL,SAAK,OAAO;AAAA,EACd;AAEA,QAAM,KAAK,QAAQ,OAAO,MAAM;AAChC,QAAM,KAAK,QAAQ,OAAO,MAAM;AAEhC,SAAO,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,MAAM,IAAI,MAAM,IAAI,IAAI,IAAI,GAAG;AAC5D;;;AC1DA,eAAsB,UACpB,KACA,KACA,GACA,GACA,OACA,QACA,SACA,OACe;AACf,QAAM,QAAQ,MAAM;AAAA,IAClB,QAAQ;AAAA,IACR;AAAA,IACA,QAAQ;AAAA,EACV;AACA,QAAM,YAAY,OAAO,aAAa;AAEtC,MAAI,cAAc,QAAQ;AACxB,QAAI,UAAU,OAAO,GAAG,GAAG,OAAO,MAAM;AACxC;AAAA,EACF;AAEA,QAAM,OAAO,MAAM;AACnB,QAAM,OAAO,MAAM;AAEnB,MAAI,cAAc,WAAW;AAC3B,UAAM,IAAI,eAAe,MAAM,MAAM,GAAG,GAAG,OAAO,MAAM;AACxD,QAAI,UAAU,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;AAAA,EAC7C,WAAW,cAAc,SAAS;AAChC,UAAM,IAAI,aAAa,MAAM,MAAM,GAAG,GAAG,OAAO,MAAM;AACtD,QAAI,UAAU,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;AAAA,EACrE,WAAW,cAAc,QAAQ;AAC/B,UAAM,KAAK,KAAK,QAAQ,QAAQ;AAChC,UAAM,KAAK,KAAK,SAAS,QAAQ;AACjC,QAAI,UAAU,OAAO,IAAI,EAAE;AAAA,EAC7B,WAAW,cAAc,cAAc;AACrC,QAAI,QAAQ,SAAS,QAAQ,QAAQ;AACnC,YAAM,KAAK,KAAK,QAAQ,QAAQ;AAChC,YAAM,KAAK,KAAK,SAAS,QAAQ;AACjC,UAAI,UAAU,OAAO,IAAI,EAAE;AAAA,IAC7B,OAAO;AACL,YAAM,IAAI,eAAe,MAAM,MAAM,GAAG,GAAG,OAAO,MAAM;AACxD,UAAI,UAAU,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;AAAA,IAC7C;AAAA,EACF;AACF;;;AC7DO,SAAS,oBACd,OACA,OACoB;AACpB,MAAI,OAAO,YAAY,MAAM,eAAgB,QAAO;AACpD,SAAO;AACT;AAMO,SAAS,oBACd,OACyB;AACzB,QAAM,QAAQ,MAAM;AACpB,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,EAAE,GAAG,OAAO,GAAG,MAAM;AAC9B;AAMO,SAAS,UACd,OACA,WACA,WAAW,GACH;AACR,MAAI,SAAS,KAAM,QAAO;AAC1B,QAAM,IAAI,OAAO,KAAK;AACtB,MAAI,EAAE,SAAS,GAAG,EAAG,QAAQ,WAAW,CAAC,IAAI,MAAO;AACpD,QAAM,IAAI,OAAO,CAAC;AAClB,SAAO,MAAM,CAAC,IAAI,WAAW;AAC/B;AAGO,SAAS,YAAY,OAAoC;AAC9D,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,IAAI,MAAM,MAAM,gBAAgB;AACtC,SAAO,IAAI,CAAC;AACd;AAMO,SAAS,sBACd,QACA,OACA,QACmB;AACnB,SAAO;AAAA,IACL,MACE,oBAAoB,OAAO,MAA4B,KAAK,KAC5D,QAAQ,QACR;AAAA,IACF,QACE,oBAAoB,OAAO,QAA8B,KAAK,KAC9D,QAAQ;AAAA,IACV,aACI,OAAO,eAAe,OAAO,cAAc,KAG3B,QAAQ;AAAA,IAC5B,eACI,OAAO,iBAAiB,OAAO,gBAAgB,KAE/B,QAAQ;AAAA,IAC5B,gBACI,OAAO,kBAAkB,OAAO,iBAAiB,KAEjC,QAAQ;AAAA,IAC5B,eACI,OAAO,iBAAiB,OAAO,gBAAgB,KAG/B,QAAQ;AAAA,EAC9B;AACF;;;AC/EO,SAAS,kBAAkB,MAA4B;AAC5D,QAAM,MACJ,KAAK,YAAa,KAAK,MAAM;AAC/B,MAAI,OAAO,KAAM,QAAO,CAAC;AACzB,SAAQ,MAAM,QAAQ,GAAG,IAAI,IAAI,KAAK,QAAQ,IAAI,CAAC,GAAG;AACxD;;;ACAO,SAAS,YAAY,UAAsB,MAAM,GAAG,MAAM,GAAY;AAC3E,QAAM,QAAQ,oBAAI,IAAwB;AAC1C,QAAM,YAAY,oBAAI,IAAsB;AAC5C,QAAM,QAAQ,oBAAI,IAAwB;AAC1C,QAAM,UAAU,oBAAI,IAAsB;AAE1C,WAAS,UAAU,KAAqB;AACtC,QAAI,CAAC,OAAO,OAAO,QAAQ,YAAY,EAAE,WAAW,QAAQ,CAAC,IAAI;AAC/D;AACF,UAAM,KAAK,IAAI,MAAM;AACrB,QAAI,CAAC,GAAI;AACT,QAAI,IAAI,SAAS,WAAY,OAAM,IAAI,IAAI,kBAAkB,GAAG,CAAC;AAAA,aACxD,IAAI,SAAS,OAAQ,OAAM,IAAI,IAAI,kBAAkB,GAAG,CAAC;AAAA,aACzD,IAAI,SAAS,SAAU,SAAQ,IAAI,IAAI,GAAG;AAAA,aAC1C,IAAI,SAAS,oBAAoB,IAAI,SAAS;AACrD,gBAAU,IAAI,IAAI,GAAG;AAAA,EACzB;AAEA,aAAW,SAAS,UAAU;AAC5B,QAAI,MAAM,SAAS,QAAQ;AACzB,iBAAW,OAAO,kBAAkB,KAAK,EAAG,WAAU,GAAG;AAAA,IAC3D,OAAO;AAEL,gBAAU,KAAK;AAAA,IACjB;AAAA,EACF;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU,EAAE,OAAO,KAAK,QAAQ,IAAI;AAAA,EACtC;AACF;AAEO,IAAM,aAAsB;AAAA,EACjC,OAAO,oBAAI,IAAI;AAAA,EACf,WAAW,oBAAI,IAAI;AAAA,EACnB,OAAO,oBAAI,IAAI;AAAA,EACf,SAAS,oBAAI,IAAI;AAAA,EACjB,UAAU,EAAE,OAAO,GAAG,QAAQ,EAAE;AAClC;;;AC3CO,SAAS,yBACd,KACA,WACA,SACS;AACT,MAAI,CAAC,aAAa,WAAW,EAAG,QAAO;AACvC,MAAI,KAAK;AACT,MAAI,UAAW,mBAAkB,KAAK,SAAS;AAC/C,MAAI,UAAU,EAAG,KAAI,eAAe;AACpC,SAAO;AACT;AAQO,SAAS,kBAAkB,KAAoB,WAAyB;AAC7E,QAAM,KAAK;AACX,MAAI;AACJ,UAAQ,QAAQ,GAAG,KAAK,SAAS,OAAO,MAAM;AAC5C,UAAM,KAAK,MAAM,CAAC;AAClB,UAAM,OAAO,MAAM,CAAC,EACjB,MAAM,QAAQ,EACd,OAAO,OAAO,EACd,IAAI,MAAM;AAEb,YAAQ,IAAI;AAAA,MACV,KAAK;AACH,YAAI,UAAU,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;AACxC;AAAA,MACF,KAAK,SAAS;AACZ,cAAM,KAAK,KAAK,CAAC,KAAK;AACtB,YAAI,MAAM,IAAI,KAAK,CAAC,KAAK,EAAE;AAC3B;AAAA,MACF;AAAA,MACA,KAAK,UAAU;AACb,cAAM,SAAU,KAAK,CAAC,KAAK,KAAK,KAAK,KAAM;AAC3C,YAAI,KAAK,UAAU,GAAG;AACpB,gBAAM,KAAK,KAAK,CAAC;AACjB,gBAAM,KAAK,KAAK,CAAC;AACjB,cAAI,UAAU,IAAI,EAAE;AACpB,cAAI,OAAO,KAAK;AAChB,cAAI,UAAU,CAAC,IAAI,CAAC,EAAE;AAAA,QACxB,OAAO;AACL,cAAI,OAAO,KAAK;AAAA,QAClB;AACA;AAAA,MACF;AAAA,MACA,KAAK;AACH,YAAI;AAAA,UACF;AAAA,UACA;AAAA,UACA,KAAK,KAAM,KAAK,CAAC,KAAK,KAAK,KAAK,KAAM,GAAG;AAAA,UACzC;AAAA,UACA;AAAA,UACA;AAAA,QACF;AACA;AAAA,MACF,KAAK;AACH,YAAI;AAAA,UACF;AAAA,UACA,KAAK,KAAM,KAAK,CAAC,KAAK,KAAK,KAAK,KAAM,GAAG;AAAA,UACzC;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AACA;AAAA,MACF,KAAK;AACH,YAAI;AAAA,UACF,KAAK,CAAC,KAAK;AAAA,UACX,KAAK,CAAC,KAAK;AAAA,UACX,KAAK,CAAC,KAAK;AAAA,UACX,KAAK,CAAC,KAAK;AAAA,UACX,KAAK,CAAC,KAAK;AAAA,UACX,KAAK,CAAC,KAAK;AAAA,QACb;AACA;AAAA,IACJ;AAAA,EACF;AACF;;;ACxFA,SAAS,UAAAG,eAAc;AAOhB,SAAS,SAAS,GAAiB;AACxC,MAAI,OAAO;AACX,MAAI,OAAO;AACX,MAAI,OAAO;AACX,MAAI,OAAO;AACX,MAAI,KAAK;AACT,MAAI,KAAK;AAET,QAAM,SAAS,CAAC,GAAW,MAAc;AACvC,QAAI,IAAI,KAAM,QAAO;AACrB,QAAI,IAAI,KAAM,QAAO;AACrB,QAAI,IAAI,KAAM,QAAO;AACrB,QAAI,IAAI,KAAM,QAAO;AAAA,EACvB;AAGA,QAAM,SAAS,EAAE,MAAM,qDAAqD;AAC5E,MAAI,CAAC,OAAQ,QAAO,EAAE,GAAG,GAAG,GAAG,GAAG,OAAO,GAAG,QAAQ,EAAE;AAEtD,MAAI,MAAM;AACV,MAAI,IAAI;AACR,QAAM,MAAM,MAAM,OAAO,OAAO,GAAG,CAAC;AAEpC,SAAO,IAAI,OAAO,QAAQ;AACxB,UAAM,IAAI,OAAO,CAAC;AAClB,QAAI,WAAW,KAAK,CAAC,GAAG;AACtB,YAAM;AACN;AAAA,IACF;AAEA,YAAQ,KAAK;AAAA,MACX,KAAK;AACH,aAAK,IAAI;AACT,aAAK,IAAI;AACT,eAAO,IAAI,EAAE;AACb,cAAM;AACN;AAAA,MACF,KAAK;AACH,cAAM,IAAI;AACV,cAAM,IAAI;AACV,eAAO,IAAI,EAAE;AACb,cAAM;AACN;AAAA,MACF,KAAK;AACH,aAAK,IAAI;AACT,aAAK,IAAI;AACT,eAAO,IAAI,EAAE;AACb;AAAA,MACF,KAAK;AACH,cAAM,IAAI;AACV,cAAM,IAAI;AACV,eAAO,IAAI,EAAE;AACb;AAAA,MACF,KAAK;AACH,aAAK,IAAI;AACT,eAAO,IAAI,EAAE;AACb;AAAA,MACF,KAAK;AACH,cAAM,IAAI;AACV,eAAO,IAAI,EAAE;AACb;AAAA,MACF,KAAK;AACH,aAAK,IAAI;AACT,eAAO,IAAI,EAAE;AACb;AAAA,MACF,KAAK;AACH,cAAM,IAAI;AACV,eAAO,IAAI,EAAE;AACb;AAAA,MACF,KAAK,KAAK;AAER,iBAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,gBAAM,KAAK,IAAI;AACf,gBAAM,KAAK,IAAI;AACf,iBAAO,IAAI,EAAE;AAAA,QACf;AACA,aAAK,OAAO,OAAO,IAAI,CAAC,CAAC;AACzB,aAAK,OAAO,OAAO,IAAI,CAAC,CAAC;AACzB;AAAA,MACF;AAAA,MACA,KAAK,KAAK;AACR,iBAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,gBAAM,KAAK,IAAI;AACf,gBAAM,KAAK,IAAI;AACf,iBAAO,KAAK,IAAI,KAAK,EAAE;AACvB,cAAI,MAAM,GAAG;AACX,kBAAM;AACN,kBAAM;AAAA,UACR;AAAA,QACF;AACA;AAAA,MACF;AAAA,MACA,KAAK,KAAK;AACR,iBAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,gBAAM,KAAK,IAAI;AACf,gBAAM,KAAK,IAAI;AACf,iBAAO,IAAI,EAAE;AAAA,QACf;AACA,aAAK,OAAO,OAAO,IAAI,CAAC,CAAC;AACzB,aAAK,OAAO,OAAO,IAAI,CAAC,CAAC;AACzB;AAAA,MACF;AAAA,MACA,KAAK,KAAK;AACR,iBAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,gBAAM,KAAK,IAAI;AACf,gBAAM,KAAK,IAAI;AACf,iBAAO,KAAK,IAAI,KAAK,EAAE;AACvB,cAAI,MAAM,GAAG;AACX,kBAAM;AACN,kBAAM;AAAA,UACR;AAAA,QACF;AACA;AAAA,MACF;AAAA,MACA,KAAK,KAAK;AAER,YAAI;AACJ,YAAI;AACJ,YAAI;AACJ,YAAI;AACJ,YAAI;AACJ,aAAK,IAAI;AACT,aAAK,IAAI;AACT,eAAO,IAAI,EAAE;AACb;AAAA,MACF;AAAA,MACA,KAAK,KAAK;AACR,YAAI;AACJ,YAAI;AACJ,YAAI;AACJ,YAAI;AACJ,YAAI;AACJ,cAAM,IAAI;AACV,cAAM,IAAI;AACV,eAAO,IAAI,EAAE;AACb;AAAA,MACF;AAAA,MACA,KAAK;AAAA,MACL,KAAK;AACH;AAAA,MACF;AAEE;AACA;AAAA,IACJ;AAAA,EACF;AAEA,MAAI,CAAC,SAAS,IAAI,EAAG,QAAO,EAAE,GAAG,GAAG,GAAG,GAAG,OAAO,GAAG,QAAQ,EAAE;AAC9D,SAAO,EAAE,GAAG,MAAM,GAAG,MAAM,OAAO,OAAO,MAAM,QAAQ,OAAO,KAAK;AACrE;AAGO,SAAS,WAAW,QAAkC;AAC3D,MAAI,OAAO;AACX,MAAI,OAAO;AACX,MAAI,OAAO;AACX,MAAI,OAAO;AACX,aAAW,CAAC,GAAG,CAAC,KAAK,QAAQ;AAC3B,QAAI,IAAI,KAAM,QAAO;AACrB,QAAI,IAAI,KAAM,QAAO;AACrB,QAAI,IAAI,KAAM,QAAO;AACrB,QAAI,IAAI,KAAM,QAAO;AAAA,EACvB;AACA,MAAI,CAAC,SAAS,IAAI,EAAG,QAAO,EAAE,GAAG,GAAG,GAAG,GAAG,OAAO,GAAG,QAAQ,EAAE;AAC9D,SAAO,EAAE,GAAG,MAAM,GAAG,MAAM,OAAO,OAAO,MAAM,QAAQ,OAAO,KAAK;AACrE;AAMO,SAAS,UACd,OACA,KACA,KACoB;AACpB,QAAM,QAAQ,oBAAoB,MAAM,KAAK;AAC7C,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK,QAAQ;AACX,YAAM,IAAI,MAAM;AAChB,UAAI,CAAC,EAAG,QAAO;AACf,aAAO,IAAIC,QAAO,CAAC;AAAA,IACrB;AAAA,IACA,KAAK,UAAU;AACb,YAAM,KAAK,UAAU,MAAM,IAAI,GAAG;AAClC,YAAM,KAAK,UAAU,MAAM,IAAI,GAAG;AAClC,YAAM,IAAI,UAAU,MAAM,GAAG,KAAK,IAAI,KAAK,GAAG,CAAC;AAC/C,UAAI,KAAK,EAAG,QAAO;AACnB,YAAM,IAAI,IAAIA,QAAO;AACrB,QAAE,IAAI,IAAI,IAAI,GAAG,GAAG,KAAK,KAAK,CAAC;AAC/B,aAAO;AAAA,IACT;AAAA,IACA,KAAK,QAAQ;AACX,YAAM,IAAI,UAAU,MAAM,GAAG,GAAG;AAChC,YAAM,IAAI,UAAU,MAAM,GAAG,GAAG;AAChC,YAAM,IAAI,UAAU,MAAM,OAAO,GAAG;AACpC,YAAM,IAAI,UAAU,MAAM,QAAQ,GAAG;AACrC,UAAI,KAAK,KAAK,KAAK,EAAG,QAAO;AAC7B,YAAM,QAAQ,UAAU,MAAM,IAAI,KAAK,EAAE;AACzC,YAAM,QAAQ,UAAU,MAAM,IAAI,KAAK,EAAE;AACzC,UAAI,KAAK,SAAS,IAAI,QAAQ,SAAS,IAAI,QAAQ;AACnD,UAAI,KAAK,SAAS,IAAI,QAAQ;AAC9B,WAAK,KAAK,IAAI,IAAI,IAAI,CAAC;AACvB,WAAK,KAAK,IAAI,IAAI,IAAI,CAAC;AACvB,YAAM,IAAI,IAAIA,QAAO;AACrB,UAAI,KAAK,KAAK,KAAK,GAAG;AACpB,UAAE,UAAU,GAAG,GAAG,GAAG,GAAG,CAAC,EAAE,CAAC;AAAA,MAC9B,OAAO;AACL,UAAE,KAAK,GAAG,GAAG,GAAG,CAAC;AAAA,MACnB;AACA,aAAO;AAAA,IACT;AAAA,IACA,KAAK,WAAW;AACd,YAAM,KAAK,UAAU,MAAM,IAAI,GAAG;AAClC,YAAM,KAAK,UAAU,MAAM,IAAI,GAAG;AAClC,YAAM,KAAK,UAAU,MAAM,IAAI,GAAG;AAClC,YAAM,KAAK,UAAU,MAAM,IAAI,GAAG;AAClC,UAAI,MAAM,KAAK,MAAM,EAAG,QAAO;AAC/B,YAAM,IAAI,IAAIA,QAAO;AACrB,QAAE,QAAQ,IAAI,IAAI,IAAI,IAAI,GAAG,GAAG,KAAK,KAAK,CAAC;AAC3C,aAAO;AAAA,IACT;AAAA,IACA,KAAK,WAAW;AACd,YAAM,SAAS,YAAY,MAAM,MAA4B;AAC7D,UAAI,OAAO,SAAS,EAAG,QAAO;AAC9B,YAAM,IAAI,IAAIA,QAAO;AACrB,QAAE,OAAO,OAAO,CAAC,EAAG,CAAC,GAAG,OAAO,CAAC,EAAG,CAAC,CAAC;AACrC,eAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,UAAE,OAAO,OAAO,CAAC,EAAG,CAAC,GAAG,OAAO,CAAC,EAAG,CAAC,CAAC;AAAA,MACvC;AACA,QAAE,UAAU;AACZ,aAAO;AAAA,IACT;AAAA,IACA;AACE,aAAO;AAAA,EACX;AACF;AAKO,SAAS,cACd,QACA,KACA,KACoB;AACpB,MAAI;AACJ,aAAW,SAAS,QAAQ;AAC1B,UAAM,IAAI,UAAU,OAAO,KAAK,GAAG;AACnC,QAAI,CAAC,EAAG;AACR,QAAI,CAAC,UAAU;AACb,iBAAW;AAAA,IACb,OAAO;AACL,eAAS,QAAQ,CAAC;AAAA,IACpB;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,YAAY,OAA+C;AACzE,MAAI,CAAC,MAAO,QAAO,CAAC;AACpB,QAAM,OAAO,MACV,KAAK,EACL,MAAM,QAAQ,EACd,IAAI,MAAM;AACb,QAAM,SAA6B,CAAC;AACpC,WAAS,IAAI,GAAG,IAAI,IAAI,KAAK,QAAQ,KAAK,GAAG;AAC3C,WAAO,KAAK,CAAC,KAAK,CAAC,GAAI,KAAK,IAAI,CAAC,CAAE,CAAC;AAAA,EACtC;AACA,SAAO;AACT;;;ACpRA,SAAS,gBAAAC,qBAAoB;AAE7B,IAAM,aAAa,oBAAI,IAA+B;AAE/C,SAAS,iBACd,GACA,GACyB;AACzB,QAAM,MAAM,GAAG,CAAC,IAAI,CAAC;AACrB,QAAM,QAAQ,WAAW,IAAI,GAAG;AAChC,MAAI,OAAO;AACT,WAAO,MAAM,SAAS,GAAG;AACvB,YAAM,MAAM,MAAM,IAAI;AACtB,YAAMC,UAAS,IAAI,MAAM;AACzB,UAAIA,SAAQ;AACV,cAAM,MAAMA,QAAO,WAAW,IAAI;AAClC,YAAI,MAAM;AACV,eAAO,CAACA,SAAQ,GAAG;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AACA,QAAM,SAASD,cAAa,GAAG,CAAC;AAChC,SAAO,CAAC,QAAQ,OAAO,WAAW,IAAI,CAAC;AACzC;AAEO,SAAS,iBAAiB,QAAsB;AACrD,QAAM,MAAM,GAAG,OAAO,KAAK,IAAI,OAAO,MAAM;AAC5C,MAAI,QAAQ,WAAW,IAAI,GAAG;AAC9B,MAAI,CAAC,OAAO;AACV,YAAQ,CAAC;AACT,eAAW,IAAI,KAAK,KAAK;AAAA,EAC3B;AACA,QAAM,KAAK,IAAI,QAAQ,MAAM,CAAC;AAChC;;;AC5BA,SAAS,cACP,OACA,IACA,IACA,GACA,GACQ;AACR,QAAM,CAAC,QAAQ,GAAG,IAAI,iBAAiB,GAAG,CAAC;AAC3C,MAAI,UAAU,OAAO,IAAI,EAAE;AAC3B,SAAO;AACT;AAEA,SAAS,oBACP,OACA,cACA,GACA,GACQ;AACR,QAAM,CAAC,QAAQ,GAAG,IAAI,iBAAiB,GAAG,CAAC;AAC3C,MAAI,SAAS,QAAQ,YAAY;AACjC,MAAI,UAAU,OAAO,GAAG,CAAC;AACzB,MAAI,SAAS;AACb,SAAO;AACT;AAEA,SAAS,mBACP,OACA,MACA,QACA,GACA,GACQ;AACR,QAAM,CAAC,QAAQ,GAAG,IAAI,iBAAiB,GAAG,CAAC;AAC3C,MAAI,UAAU,OAAO,GAAG,CAAC;AAEzB,MAAI,SAAS,YAAY,QAAQ;AAC/B,UAAM,IAAI,OACP,KAAK,EACL,MAAM,QAAQ,EACd,IAAI,MAAM;AACb,QAAI,EAAE,UAAU,IAAI;AAClB,YAAM,YAAY,IAAI,aAAa,GAAG,GAAG,GAAG,CAAC;AAC7C,YAAM,IAAI,UAAU;AACpB,eAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK,GAAG;AACpC,cAAM,IAAI,EAAE,CAAC;AACb,cAAM,IAAI,EAAE,IAAI,CAAC;AACjB,cAAM,IAAI,EAAE,IAAI,CAAC;AACjB,cAAM,IAAI,EAAE,IAAI,CAAC;AACjB,UAAE,CAAC,IAAI,KAAK;AAAA,UACV;AAAA,UACA,KAAK;AAAA,YACH;AAAA,YACA,EAAE,CAAC,IAAK,IAAI,EAAE,CAAC,IAAK,IAAI,EAAE,CAAC,IAAK,IAAI,EAAE,CAAC,IAAK,IAAI,EAAE,CAAC,IAAK;AAAA,UAC1D;AAAA,QACF;AACA,UAAE,IAAI,CAAC,IAAI,KAAK;AAAA,UACd;AAAA,UACA,KAAK;AAAA,YACH;AAAA,YACA,EAAE,CAAC,IAAK,IAAI,EAAE,CAAC,IAAK,IAAI,EAAE,CAAC,IAAK,IAAI,EAAE,CAAC,IAAK,IAAI,EAAE,CAAC,IAAK;AAAA,UAC1D;AAAA,QACF;AACA,UAAE,IAAI,CAAC,IAAI,KAAK;AAAA,UACd;AAAA,UACA,KAAK;AAAA,YACH;AAAA,YACA,EAAE,EAAE,IAAK,IAAI,EAAE,EAAE,IAAK,IAAI,EAAE,EAAE,IAAK,IAAI,EAAE,EAAE,IAAK,IAAI,EAAE,EAAE,IAAK;AAAA,UAC/D;AAAA,QACF;AACA,UAAE,IAAI,CAAC,IAAI,KAAK;AAAA,UACd;AAAA,UACA,KAAK;AAAA,YACH;AAAA,YACA,EAAE,EAAE,IAAK,IAAI,EAAE,EAAE,IAAK,IAAI,EAAE,EAAE,IAAK,IAAI,EAAE,EAAE,IAAK,IAAI,EAAE,EAAE,IAAK;AAAA,UAC/D;AAAA,QACF;AAAA,MACF;AACA,UAAI,aAAa,WAAW,GAAG,CAAC;AAAA,IAClC;AAAA,EACF;AAEA,SAAO;AACT;AAEA,IAAM,iBAA2D;AAAA,EAC/D,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AACX;AAEA,SAAS,aACP,KACA,KACA,MACA,GACA,GACQ;AACR,QAAM,CAAC,QAAQ,GAAG,IAAI,iBAAiB,GAAG,CAAC;AAC3C,MAAI,UAAU,KAAK,GAAG,CAAC;AACvB,MAAI,2BAA2B,eAAe,IAAI,KAAK;AACvD,MAAI,UAAU,KAAK,GAAG,CAAC;AACvB,MAAI,2BAA2B;AAC/B,SAAO;AACT;AAOA,SAAS,mBAAmB,OAAe,GAAW,GAAmB;AACvE,QAAM,CAAC,QAAQ,GAAG,IAAI,iBAAiB,GAAG,CAAC;AAC3C,MAAI,YAAY;AAChB,MAAI,SAAS,GAAG,GAAG,GAAG,CAAC;AACvB,MAAI,2BAA2B;AAC/B,MAAI,UAAU,OAAO,GAAG,CAAC;AACzB,MAAI,2BAA2B;AAC/B,SAAO;AACT;AAOO,SAAS,YACd,WACA,eACA,GACA,GACQ;AACR,QAAM,UAAU,oBAAI,IAAoB;AACxC,UAAQ,IAAI,iBAAiB,aAAa;AAE1C,MAAI;AACJ,QAAM,iBAAiB,MAAM;AAC3B,QAAI,CAAC,aAAa;AAChB,oBAAc,mBAAmB,eAAe,GAAG,CAAC;AACpD,cAAQ,IAAI,eAAe,WAAW;AAAA,IACxC;AACA,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,kBAAkB,SAAS;AAC5C,MAAI,aAAqB;AAEzB,aAAW,QAAQ,UAAU;AAC3B,UAAM,IAAI,KAAK;AACf,UAAM,SAAU,EAAE,MAA6B;AAC/C,UAAM,UAAU,CAAC,SAAyB;AACxC,UAAI,SAAS,cAAe,QAAO,eAAe;AAClD,aAAO,QAAQ,IAAI,IAAI,KAAK;AAAA,IAC9B;AACA,UAAM,QAAQ,SAAS,QAAQ,MAAM,IAAI;AACzC,QAAI;AAEJ,YAAQ,KAAK,MAAM;AAAA,MACjB,KAAK;AACH,iBAAS;AAAA,UACP;AAAA,UACA,OAAO,EAAE,MAAM,CAAC;AAAA,UAChB,OAAO,EAAE,MAAM,CAAC;AAAA,UAChB;AAAA,UACA;AAAA,QACF;AACA;AAAA,MACF,KAAK,kBAAkB;AACrB,cAAM,MAAM,OAAO,EAAE,gBAAgB,CAAC;AACtC,iBAAS,MAAM,IAAI,oBAAoB,OAAO,KAAK,GAAG,CAAC,IAAI;AAC3D;AAAA,MACF;AAAA,MACA,KAAK;AACH,iBAAS;AAAA,UACP;AAAA,UACC,EAAE,QAAmB;AAAA,UACtB,EAAE;AAAA,UACF;AAAA,UACA;AAAA,QACF;AACA;AAAA,MACF,KAAK,WAAW;AACd,cAAM,UAAW,EAAE,OAA8B;AACjD,cAAM,MAAM,UAAU,QAAQ,OAAO,IAAI;AACzC,iBAAS,aAAa,OAAO,KAAM,EAAE,QAAmB,UAAU,GAAG,CAAC;AACtE;AAAA,MACF;AAAA,MACA;AACE,iBAAS;AACT;AAAA,IACJ;AAEA,UAAM,aAAa,EAAE;AACrB,QAAI,WAAY,SAAQ,IAAI,YAAY,MAAM;AAC9C,iBAAa;AAAA,EACf;AAEA,SAAO;AACT;;;AC9MA,SAAS,UAAAE,eAAc;;;ACAvB,SAAS,UAAAC,eAAc;AAOvB,OAAO,mBAAmB;AAQ1B,SAAS,UAAU,OAAgB,UAA0B;AAC3D,MAAI,SAAS,KAAM,QAAO;AAC1B,QAAM,IAAI,OAAO,KAAK;AACtB,MAAI,EAAE,SAAS,GAAG,EAAG,QAAO,WAAW,CAAC,IAAI;AAC5C,SAAO,OAAO,CAAC;AACjB;AAGA,SAAS,iBAAiB,OAAyC;AACjE,SAAO,MAAM,kBAAkB;AACjC;AAMA,SAAS,gBACP,OACA,UACA,WACQ;AACR,MAAI,SAAS,KAAM,QAAO;AAC1B,QAAM,IAAI,OAAO,KAAK;AACtB,MAAI,EAAE,SAAS,GAAG,EAAG,QAAQ,WAAW,CAAC,IAAI,MAAO;AACpD,SAAO,OAAO,CAAC;AACjB;AAGO,SAAS,aAAa,OAAe,SAAyB;AACnE,MAAI,WAAW,EAAG,QAAO;AACzB,QAAM,SAAS,cAAc,KAAK;AAClC,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,CAAC,GAAG,GAAG,CAAC,IAAI,OAAO;AACzB,SAAO,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,OAAO,QAAQ,OAAO;AACzD;AAGA,SAAS,iBAAiB,UAA0B,KAAqB;AACvE,aAAW,QAAQ,kBAAkB,GAAG,GAAG;AACzC,QAAI,KAAK,SAAS,OAAQ;AAC1B,UAAM,KAAK,KAAK;AAChB,UAAM,YAAa,GAAG,UAA8B;AACpD,UAAM,SACJ,OAAO,cAAc,YAAY,UAAU,SAAS,GAAG,IACnD,WAAW,SAAS,IAAI,MACxB,OAAO,SAAS;AACtB,UAAM,YACF,GAAG,aAAa,GAAG,YAAY,KAA6B;AAChE,UAAM,cAAc,OAAO,GAAG,eAAe,GAAG,cAAc,KAAK,CAAC;AACpE,aAAS,aAAa,QAAQ,aAAa,WAAW,WAAW,CAAC;AAAA,EACpE;AACF;AAGA,SAAS,6BACP,KACA,OACA,MACA,KACgB;AAChB,QAAM,KAAK,KAAK,IAAI,UAAU,MAAM,IAAI,CAAC,IAAI,KAAK;AAClD,QAAM,KAAK,KAAK,IAAI,UAAU,MAAM,IAAI,CAAC,IAAI,KAAK;AAClD,QAAM,KAAK,KAAK,IAAI,UAAU,MAAM,IAAI,CAAC,IAAI,KAAK;AAClD,QAAM,KAAK,KAAK,IAAI,UAAU,MAAM,IAAI,CAAC,IAAI,KAAK;AAClD,QAAM,WAAW,IAAI,qBAAqB,IAAI,IAAI,IAAI,EAAE;AACxD,mBAAiB,UAAU,GAAG;AAC9B,SAAO;AACT;AAQA,SAAS,8BACP,KACA,OACA,UACA,KACgB;AAChB,QAAM,KAAK,gBAAgB,MAAM,IAAI,GAAG,SAAS,KAAK;AACtD,QAAM,KAAK,gBAAgB,MAAM,IAAI,GAAG,SAAS,MAAM;AACvD,QAAM,KAAK,gBAAgB,MAAM,IAAI,SAAS,OAAO,SAAS,KAAK;AACnE,QAAM,KAAK,gBAAgB,MAAM,IAAI,GAAG,SAAS,MAAM;AACvD,QAAM,WAAW,IAAI,qBAAqB,IAAI,IAAI,IAAI,EAAE;AACxD,mBAAiB,UAAU,GAAG;AAC9B,SAAO;AACT;AAQA,SAAS,8BACP,KACA,OACA,UACA,KACgB;AAChB,QAAM,WAAW,KAAK,MAAM,SAAS,OAAO,SAAS,MAAM,IAAI,KAAK;AACpE,QAAM,KAAK,gBAAgB,MAAM,IAAI,SAAS,QAAQ,GAAG,SAAS,KAAK;AACvE,QAAM,KAAK,gBAAgB,MAAM,IAAI,SAAS,SAAS,GAAG,SAAS,MAAM;AACzE,QAAM,IAAI,gBAAgB,MAAM,GAAG,WAAW,GAAG,QAAQ;AACzD,QAAM,KAAK,gBAAgB,MAAM,IAAI,IAAI,SAAS,KAAK;AACvD,QAAM,KAAK,gBAAgB,MAAM,IAAI,IAAI,SAAS,MAAM;AACxD,QAAM,WAAW,IAAI,qBAAqB,IAAI,IAAI,GAAG,IAAI,IAAI,CAAC;AAC9D,mBAAiB,UAAU,GAAG;AAC9B,SAAO;AACT;AAeO,SAAS,oBACd,KACA,KACA,MACA,MACA,UACA,UACS;AACT,QAAM,QAAQ,IAAI;AAElB,MAAI,IAAI,SAAS,kBAAkB;AACjC,QAAI,YAAY,iBAAiB,KAAK,IAClC,8BAA8B,KAAK,OAAO,UAAU,GAAG,IACvD,6BAA6B,KAAK,OAAO,MAAM,GAAG;AACtD,QAAI,KAAK,MAAM,QAAQ;AACvB,WAAO;AAAA,EACT;AAEA,MAAI,IAAI,SAAS,oBAAoB,iBAAiB,KAAK,GAAG;AAC5D,QAAI,YAAY,8BAA8B,KAAK,OAAO,UAAU,GAAG;AACvE,QAAI,KAAK,MAAM,QAAQ;AACvB,WAAO;AAAA,EACT;AAEA,MAAI,IAAI,SAAS,kBAAkB;AACjC,UAAM,MAAM,UAAU,MAAM,IAAI,GAAG;AACnC,UAAM,MAAM,UAAU,MAAM,IAAI,GAAG;AACnC,UAAM,KAAK,UAAU,MAAM,GAAG,GAAG;AACjC,UAAM,MAAM,UAAU,MAAM,IAAI,GAAG;AACnC,UAAM,MAAM,UAAU,MAAM,IAAI,GAAG;AAInC,QAAI,KAAK;AACT,QAAI,UAAU,KAAK,GAAG,KAAK,CAAC;AAC5B,QAAI,MAAM,KAAK,OAAO,KAAK,MAAM;AAEjC,UAAM,WAAW,IAAI,qBAAqB,KAAK,KAAK,GAAG,KAAK,KAAK,EAAE;AACnE,qBAAiB,UAAU,GAAG;AAC9B,QAAI,YAAY;AAKhB,UAAM,WAAW,IAAIC,QAAO;AAC5B,UAAM,eAAgC;AAAA,MACpC,GAAG,IAAI,KAAK;AAAA,MACZ,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG,IAAI,KAAK;AAAA,MACZ,GAAG,CAAC,KAAK,IAAI,KAAK;AAAA,MAClB,GAAG,CAAC,KAAK,IAAI,KAAK;AAAA,IACpB;AACA,aAAS,QAAQ,MAAM,YAAY;AAEnC,QAAI,KAAK,UAAU,QAAQ;AAC3B,QAAI,QAAQ;AACZ,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAKO,SAAS,sBACd,KACA,KACA,MACA,MACA,UACS;AACT,QAAM,QAAQ,IAAI;AAElB,MAAI,IAAI,SAAS,kBAAkB;AACjC,QAAI,cAAc,iBAAiB,KAAK,IACpC,8BAA8B,KAAK,OAAO,UAAU,GAAG,IACvD,6BAA6B,KAAK,OAAO,MAAM,GAAG;AACtD,QAAI,OAAO,IAAI;AACf,WAAO;AAAA,EACT;AAEA,MAAI,IAAI,SAAS,oBAAoB,iBAAiB,KAAK,GAAG;AAC5D,QAAI,cAAc,8BAA8B,KAAK,OAAO,UAAU,GAAG;AACzE,QAAI,OAAO,IAAI;AACf,WAAO;AAAA,EACT;AAEA,MAAI,IAAI,SAAS,kBAAkB;AAEjC,UAAM,QAAQ,KAAK,IAAI,UAAU,MAAM,IAAI,GAAG,IAAI,KAAK;AACvD,UAAM,QAAQ,KAAK,IAAI,UAAU,MAAM,IAAI,GAAG,IAAI,KAAK;AACvD,UAAM,OAAO,UAAU,MAAM,GAAG,GAAG,IAAI,KAAK,KAAK,KAAK,QAAQ,KAAK,MAAM;AACzE,UAAM,QAAQ,KAAK,IAAI,UAAU,MAAM,IAAI,GAAG,IAAI,KAAK;AACvD,UAAM,QAAQ,KAAK,IAAI,UAAU,MAAM,IAAI,GAAG,IAAI,KAAK;AACvD,UAAM,WAAW,IAAI;AAAA,MACnB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,qBAAiB,UAAU,GAAG;AAC9B,QAAI,cAAc;AAClB,QAAI,OAAO,IAAI;AACf,WAAO;AAAA,EACT;AAEA,SAAO;AACT;;;ACjPO,SAAS,mBACd,KACA,OACA,MACA,WACA,OACA,MACA,MACM;AAEN,QAAM,OACJ,oBAAoB,MAAM,MAA4B,KAAK,KAC3D,UAAU;AACZ,QAAM,WAAY,MAAM,YAAY,MAAM,WAAW;AAErD,QAAM,cAAc,OAAO,MAAM,eAAe,MAAM,cAAc,KAAK,CAAC;AAG1E,QAAM,UAAU,YAAY,IAAI;AAChC,MAAI,SAAS;AACX,UAAM,cAAc,KAAK,UAAU,IAAI,OAAO;AAC9C,QAAI,aAAa;AACf,UAAI,cAAc,GAAG;AACnB,YAAI,KAAK;AACT,YAAI,eAAe;AACnB;AAAA,UACE;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,YAAY;AAAA,UACZ,KAAK;AAAA,QACP;AACA,YAAI,QAAQ;AAAA,MACd,OAAO;AACL;AAAA,UACE;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,YAAY;AAAA,UACZ,KAAK;AAAA,QACP;AAAA,MACF;AAAA,IACF;AAAA,EACF,WAAW,SAAS,QAAQ;AAC1B,QAAI,YAAY,aAAa,MAAM,WAAW;AAC9C,QAAI,KAAK,MAAM,YAAY,SAAS;AAAA,EACtC;AAEA,cAAY,KAAK,OAAO,MAAM,WAAW,OAAO,MAAM,IAAI;AAC5D;AAEO,SAAS,YACd,KACA,OACA,MACA,WACA,OACA,MACA,MACM;AACN,QAAM,SACJ,oBAAoB,MAAM,QAA8B,KAAK,KAC7D,UAAU;AACZ,MAAI,CAAC,UAAU,WAAW,OAAQ;AAElC,QAAM,gBAAgB;AAAA,IACpB,MAAM,iBACJ,MAAM,gBAAgB,KACtB,UAAU,iBACV;AAAA,EACJ;AAEA,MAAI,YAAY;AAAA,IACd,MAAM,eAAe,MAAM,cAAc,KAAK,UAAU,eAAe;AAAA,EACzE;AACA,MAAI,UAAa,MAAM,iBACrB,MAAM,gBAAgB,KACtB,UAAU,iBACV;AACF,MAAI,WAAc,MAAM,kBACtB,MAAM,iBAAiB,KACvB,UAAU,kBACV;AAGF,QAAM,YAAY,YAAY,MAAM;AACpC,MAAI,WAAW;AACb,UAAM,cAAc,KAAK,UAAU,IAAI,SAAS;AAChD,QAAI,aAAa;AACf,UAAI,gBAAgB,GAAG;AACrB,YAAI,KAAK;AACT,YAAI,eAAe;AACnB,8BAAsB,KAAK,aAAa,MAAM,MAAM,KAAK,QAAQ;AACjE,YAAI,QAAQ;AAAA,MACd,OAAO;AACL,8BAAsB,KAAK,aAAa,MAAM,MAAM,KAAK,QAAQ;AAAA,MACnE;AACA;AAAA,IACF;AAAA,EACF;AAEA,MAAI,cAAc,aAAa,QAAQ,aAAa;AACpD,MAAI,OAAO,IAAI;AACjB;;;AF5GO,SAAS,SACd,KACA,OACA,WACA,OACA,MACM;AACN,QAAM,IAAI,MAAM;AAChB,MAAI,CAAC,EAAG;AAER,QAAM,OAAO,IAAIC,QAAO,CAAC;AACzB,QAAM,OAAO,SAAS,CAAC;AACvB,qBAAmB,KAAK,OAAO,MAAM,WAAW,OAAO,MAAM,IAAI;AACnE;AAEO,SAAS,WACd,KACA,OACA,WACA,OACA,MACA,MAAM,GACN,MAAM,GACA;AACN,QAAM,KAAK,UAAU,MAAM,IAAI,GAAG;AAClC,QAAM,KAAK,UAAU,MAAM,IAAI,GAAG;AAClC,QAAM,IAAI,UAAU,MAAM,GAAG,KAAK,IAAI,KAAK,GAAG,CAAC;AAC/C,MAAI,KAAK,EAAG;AAEZ,QAAM,OAAO,IAAIA,QAAO;AACxB,OAAK,IAAI,IAAI,IAAI,GAAG,GAAG,KAAK,KAAK,CAAC;AAClC,QAAM,OAAa,EAAE,GAAG,KAAK,GAAG,GAAG,KAAK,GAAG,OAAO,IAAI,GAAG,QAAQ,IAAI,EAAE;AACvE,qBAAmB,KAAK,OAAO,MAAM,WAAW,OAAO,MAAM,IAAI;AACnE;AAEO,SAAS,YACd,KACA,OACA,WACA,OACA,MACA,MAAM,GACN,MAAM,GACA;AACN,QAAM,IAAI,UAAU,MAAM,GAAG,GAAG;AAChC,QAAM,IAAI,UAAU,MAAM,GAAG,GAAG;AAChC,QAAM,IAAI,UAAU,MAAM,OAAO,GAAG;AACpC,QAAM,IAAI,UAAU,MAAM,QAAQ,GAAG;AACrC,MAAI,KAAK,KAAK,KAAK,EAAG;AAEtB,QAAM,QAAQ,UAAU,MAAM,IAAI,KAAK,EAAE;AACzC,QAAM,QAAQ,UAAU,MAAM,IAAI,KAAK,EAAE;AACzC,MAAI,KAAK,SAAS,IAAI,QAAQ,SAAS,IAAI,QAAQ;AACnD,MAAI,KAAK,SAAS,IAAI,QAAQ;AAC9B,OAAK,KAAK,IAAI,IAAI,IAAI,CAAC;AACvB,OAAK,KAAK,IAAI,IAAI,IAAI,CAAC;AAEvB,QAAM,OAAO,IAAIA,QAAO;AACxB,MAAI,KAAK,KAAK,KAAK,GAAG;AACpB,SAAK,UAAU,GAAG,GAAG,GAAG,GAAG,CAAC,EAAE,CAAC;AAAA,EACjC,OAAO;AACL,SAAK,KAAK,GAAG,GAAG,GAAG,CAAC;AAAA,EACtB;AACA,QAAM,OAAa,EAAE,GAAG,GAAG,OAAO,GAAG,QAAQ,EAAE;AAC/C,qBAAmB,KAAK,OAAO,MAAM,WAAW,OAAO,MAAM,IAAI;AACnE;AAEO,SAAS,SACd,KACA,OACA,WACA,OACA,MACA,MAAM,GACN,MAAM,GACA;AACN,QAAM,KAAK,UAAU,MAAM,IAAI,GAAG;AAClC,QAAM,KAAK,UAAU,MAAM,IAAI,GAAG;AAClC,QAAM,KAAK,UAAU,MAAM,IAAI,GAAG;AAClC,QAAM,KAAK,UAAU,MAAM,IAAI,GAAG;AAElC,QAAM,OAAO,IAAIA,QAAO;AACxB,OAAK,OAAO,IAAI,EAAE;AAClB,OAAK,OAAO,IAAI,EAAE;AAElB,QAAM,OAAa;AAAA,IACjB,GAAG,KAAK,IAAI,IAAI,EAAE;AAAA,IAClB,GAAG,KAAK,IAAI,IAAI,EAAE;AAAA,IAClB,OAAO,KAAK,IAAI,KAAK,EAAE;AAAA,IACvB,QAAQ,KAAK,IAAI,KAAK,EAAE;AAAA,EAC1B;AACA,cAAY,KAAK,OAAO,MAAM,WAAW,OAAO,MAAM,IAAI;AAC5D;AAEO,SAAS,YACd,KACA,OACA,WACA,OACA,MACA,MAAM,GACN,MAAM,GACA;AACN,QAAM,KAAK,UAAU,MAAM,IAAI,GAAG;AAClC,QAAM,KAAK,UAAU,MAAM,IAAI,GAAG;AAClC,QAAM,KAAK,UAAU,MAAM,IAAI,GAAG;AAClC,QAAM,KAAK,UAAU,MAAM,IAAI,GAAG;AAClC,MAAI,MAAM,KAAK,MAAM,EAAG;AAExB,QAAM,OAAO,IAAIA,QAAO;AACxB,OAAK,QAAQ,IAAI,IAAI,IAAI,IAAI,GAAG,GAAG,KAAK,KAAK,CAAC;AAC9C,QAAM,OAAa;AAAA,IACjB,GAAG,KAAK;AAAA,IACR,GAAG,KAAK;AAAA,IACR,OAAO,IAAI;AAAA,IACX,QAAQ,IAAI;AAAA,EACd;AACA,qBAAmB,KAAK,OAAO,MAAM,WAAW,OAAO,MAAM,IAAI;AACnE;AAEO,SAAS,YACd,KACA,OACA,WACA,OACA,MACM;AACN,QAAM,SAAS,YAAY,MAAM,MAA4B;AAC7D,MAAI,OAAO,SAAS,EAAG;AAEvB,QAAM,OAAO,IAAIA,QAAO;AACxB,OAAK,OAAO,OAAO,CAAC,EAAG,CAAC,GAAG,OAAO,CAAC,EAAG,CAAC,CAAC;AACxC,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,SAAK,OAAO,OAAO,CAAC,EAAG,CAAC,GAAG,OAAO,CAAC,EAAG,CAAC,CAAC;AAAA,EAC1C;AACA,OAAK,UAAU;AACf,QAAM,OAAO,WAAW,MAAM;AAC9B,qBAAmB,KAAK,OAAO,MAAM,WAAW,OAAO,MAAM,IAAI;AACnE;AAEO,SAAS,aACd,KACA,OACA,WACA,OACA,MACM;AACN,QAAM,SAAS,YAAY,MAAM,MAA4B;AAC7D,MAAI,OAAO,SAAS,EAAG;AAEvB,QAAM,OAAO,IAAIA,QAAO;AACxB,OAAK,OAAO,OAAO,CAAC,EAAG,CAAC,GAAG,OAAO,CAAC,EAAG,CAAC,CAAC;AACxC,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,SAAK,OAAO,OAAO,CAAC,EAAG,CAAC,GAAG,OAAO,CAAC,EAAG,CAAC,CAAC;AAAA,EAC1C;AACA,QAAM,OAAO,WAAW,MAAM;AAC9B,qBAAmB,KAAK,OAAO,MAAM,WAAW,OAAO,MAAM,IAAI;AACnE;;;AG7IO,SAAS,aACd,KACA,OACA,WACA,OACA,OAAgB,YAChB,MAAM,GACN,MAAM,GACA;AACN,QAAM,EAAE,KAAK,IAAI;AACjB,QAAM,QAAQ,oBAAoB,MAAM,KAAK;AAG7C,MACE,SAAS,UACT,SAAS,cACT,SAAS,UACT,SAAS;AAET;AAGF,QAAM,YACJ,SAAS,MAAO,MAAM,YAAmC;AAC3D,QAAM,UAAU,SAAS,MAAM,OAAO,MAAM,WAAW,CAAC,IAAI;AAC5D,QAAM,iBAAiB,yBAAyB,KAAK,WAAW,OAAO;AAGvE,QAAM,UAAU,YAAY,MAAM,YAAY,MAAM,WAAW,CAAC;AAChE,QAAM,aAAa,UAAU,KAAK,MAAM,IAAI,OAAO,IAAI;AACvD,QAAM,WAAW,aAAa,cAAc,YAAY,KAAK,GAAG,IAAI;AAGpE,QAAM,UAAU,YAAY,MAAM,IAA0B;AAC5D,QAAM,aAAa,UAAU,KAAK,MAAM,IAAI,OAAO,IAAI;AAGvD,QAAM,YAAY,YAAY,MAAM,MAA4B;AAChE,QAAM,YAAY,YAAY,KAAK,QAAQ,IAAI,SAAS,IAAI;AAE5D,MAAI,UAAU;AACZ,QAAI,KAAK;AACT,QAAI,KAAK,QAAQ;AAAA,EACnB;AAIA,QAAM,iBAAiB,cAAc;AACrC,MAAI;AACJ,MAAI;AACJ,MAAI,gBAAgB;AAClB,UAAM,CAAC,GAAG,IAAI,IAAI,iBAAiB,KAAK,KAAK,GAAG,GAAG,KAAK,KAAK,GAAG,CAAC;AACjE,iBAAa;AACb,gBAAY;AAAA,EACd,OAAO;AACL,gBAAY;AAAA,EACd;AAEA,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,eAAS,WAAW,OAAO,WAAW,OAAO,IAAI;AACjD;AAAA,IACF,KAAK;AACH,iBAAW,WAAW,OAAO,WAAW,OAAO,MAAM,KAAK,GAAG;AAC7D;AAAA,IACF,KAAK;AACH,kBAAY,WAAW,OAAO,WAAW,OAAO,MAAM,KAAK,GAAG;AAC9D;AAAA,IACF,KAAK;AACH,eAAS,WAAW,OAAO,WAAW,OAAO,MAAM,KAAK,GAAG;AAC3D;AAAA,IACF,KAAK;AACH,kBAAY,WAAW,OAAO,WAAW,OAAO,MAAM,KAAK,GAAG;AAC9D;AAAA,IACF,KAAK;AACH,kBAAY,WAAW,OAAO,WAAW,OAAO,IAAI;AACpD;AAAA,IACF,KAAK;AACH,mBAAa,WAAW,OAAO,WAAW,OAAO,IAAI;AACrD;AAAA,IACF,KAAK;AACH,gBAAU,WAAW,OAAO,OAAO,WAAW,OAAO,MAAM,KAAK,GAAG;AACnE;AAAA,EACJ;AAEA,MAAI,kBAAkB,YAAY;AAChC;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,MAAI,SAAU,KAAI,QAAQ;AAC1B,MAAI,eAAgB,KAAI,QAAQ;AAClC;AAEA,SAAS,UACP,KACA,MACA,aACA,WACA,OACA,OAAgB,YAChB,MAAM,GACN,MAAM,GACA;AACN,QAAM,WAAW,kBAAkB,IAAI;AACvC,MAAI,SAAS,WAAW,EAAG;AAC3B,QAAM,iBAAiB,sBAAsB,aAAa,OAAO,SAAS;AAE1E,QAAM,UAAU,OAAO,YAAY,WAAW,CAAC;AAC/C,QAAM,YAAY,YAAY;AAC9B,QAAM,QAAQ,yBAAyB,KAAK,WAAW,OAAO;AAE9D,aAAW,SAAS,UAAU;AAC5B,QAAI,SAAS,QAAQ,OAAO,UAAU,UAAU;AAC9C,mBAAa,KAAK,OAAO,gBAAgB,OAAO,MAAM,KAAK,GAAG;AAAA,IAChE;AAAA,EACF;AAEA,MAAI,MAAO,KAAI,QAAQ;AACzB;AAGA,SAAS,sBACP,KACA,YACA,WACA,YACA,WACA,OACA,MACA,KACA,KACM;AAEN,MAAI,YAAY;AACd,UAAM,CAAC,YAAY,OAAO,IAAI;AAAA,MAC5B,KAAK,KAAK,GAAG;AAAA,MACb,KAAK,KAAK,GAAG;AAAA,IACf;AACA,eAAW,SAAS,YAAY;AAC9B,mBAAa,SAAS,OAAO,EAAE,MAAM,QAAQ,GAAG,SAAS,MAAM,KAAK,GAAG;AAAA,IACzE;AACA,cAAU,2BAA2B;AACrC,cAAU,UAAU,YAAY,GAAG,CAAC;AACpC,cAAU,2BAA2B;AACrC,qBAAiB,UAAU;AAAA,EAC7B;AAGA,MAAI,WAAW;AACb,UAAM,iBAAiB;AAAA,MACrB;AAAA,MACA;AAAA,MACA,KAAK,KAAK,GAAG;AAAA,MACb,KAAK,KAAK,GAAG;AAAA,IACf;AACA,QAAI,UAAU,gBAAgB,GAAG,CAAC;AAElC,QAAI,mBAAmB,WAAY,kBAAiB,cAAc;AAAA,EACpE,OAAO;AACL,QAAI,UAAU,YAAY,GAAG,CAAC;AAAA,EAChC;AACA,mBAAiB,UAAU;AAC7B;;;ACtLO,SAAS,iBACd,KACA,MACA,GACA,GACA,OACA,QACM;AACN,MAAI,KAAK;AACT,MAAI,UAAU,GAAG,CAAC;AAGlB,QAAM,UAAU,KAAK,MAAM;AAC3B,MAAI,MAAM;AACV,MAAI,MAAM;AACV,MAAI,SAAS;AACX,UAAM,QAAQ,QAAQ,MAAM,QAAQ,EAAE,IAAI,MAAM;AAChD,QAAI,MAAM,WAAW,GAAG;AACtB,YAAM,CAAC,KAAK,KAAK,SAAS,OAAO,IAAI;AAMrC,YAAM;AACN,YAAM;AACN,YAAM,SAAS,QAAQ;AACvB,YAAM,SAAS,SAAS;AACxB,UAAI,MAAM,QAAQ,MAAM;AACxB,UAAI,UAAU,CAAC,KAAK,CAAC,GAAG;AAAA,IAC1B;AAAA,EACF;AAGA,QAAM,QAAS,KAAK,MAAM,SAAgC;AAG1D,QAAM,SAAS,oBAAoB,KAAK,KAAK;AAC7C,QAAM,YAAY,sBAAsB,QAAQ,KAAK;AAGrD,QAAM,WAAW,KAAK,MAAM;AAC5B,MAAI,YAAY,MAAM;AAGpB,UAAM,aACJ,MAAM,QAAQ,QAAQ,IAAI,SAAS,KAAK,QAAQ,IAAI,CAAC,QAAQ;AAE/D,UAAM,cAAc,WAAW;AAAA,MAC7B,CAAC,MACC,KAAK,QAAQ,OAAO,MAAM,YAAY,CAAC,MAAM,QAAQ,CAAC;AAAA,IAC1D;AAGA,UAAM,OAAO,YAAY,aAAa,KAAK,GAAG;AAG9C,eAAW,SAAS,aAAa;AAC/B,mBAAa,KAAK,OAAO,WAAW,OAAO,MAAM,KAAK,GAAG;AAAA,IAC3D;AAAA,EACF;AAEA,MAAI,QAAQ;AACd;;;AC7EA,SAAS,aAAAC,kBAAiB;AAE1B,SAAS,eAAe,uBAAuB;AAE/C,OAAOC,oBAAmB;;;ACQ1B,IAAM,OAAO;AACb,IAAM,MAAM;AACZ,IAAM,SAAS;AAEf,IAAMC,cAAa;AAGnB,IAAM,qBAAqB,IAAI;AAAA,EAC7B,OAAO,6BAA6B,uBAAuB;AAAA,EAC3D;AACF;AACA,IAAM,iBAAiB;AAQvB,SAAS,oBAAoB,OAAyB;AACpD,QAAM,QAAQ,CAAC,GAAG,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC,MAAM,IAAI;AAChE,QAAM,aAAuB,CAAC;AAC9B,QAAM,QAAQ,CAAC,MAAM,MAAM;AACzB,eAAW,KAAK,KAAK,YAAY,CAAC,CAAE;AACpC,UAAM,gBAAgB,MAAM,KAAK,MAAM,IAAI,CAAC,MAAM;AAClD,QACE,iBACAA,YAAW,KAAK,IAAI,KACpB,CAAC,mBAAmB,KAAK,IAAI,KAC7B,CAAC,eAAe,KAAK,MAAM,IAAI,CAAC,KAAK,EAAE,GACvC;AACA,iBAAW,KAAK,IAAI;AAAA,IACtB;AAAA,EACF,CAAC;AACD,SAAO;AACT;AAEA,SAAS,IAAI,YAAsB,MAAM,GAAW;AAClD,SAAO,WAAW,IAAI,CAAC,OAAO,GAAG,SAAS,EAAE,EAAE,SAAS,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG;AAC5E;AAOA,SAAS,YAAY,YAA8B;AACjD,QAAM,OAAO;AAAA,IACX,WAAW,SAAS,GAAG,IACnB,aACA,WAAW,OAAO,CAAC,OAAO,OAAO,IAAI;AAAA,EAC3C;AACA,SAAO,SAAS,+BAA+B,qBAAqB;AACtE;AAOA,SAAS,YAAY,YAA8B;AACjD,QAAM,WAAW,WAAW,SAAS,GAAG,KAAK,WAAW,SAAS,MAAM;AACvE,SAAO;AAAA,IACL,WAAW,aAAa,WAAW,OAAO,CAAC,OAAO,OAAO,IAAI;AAAA,IAC7D;AAAA,EACF,EAAE,YAAY;AAChB;AAOA,SAAS,WAAW,YAA8B;AAChD,SAAO,mBAAmB,OAAO,cAAc,GAAG,UAAU,CAAC;AAC/D;AAEA,IAAM,YAAkE;AAAA,EACtE,SAAS,CAAC,QACR,6DAA6D,YAAY,GAAG,CAAC;AAAA,EAC/E,UAAU,CAAC,QACT,4DAA4D,YAAY,GAAG,CAAC;AAAA,EAC9E,UAAU,CAAC,QACT,wDAAwD,YAAY,GAAG,CAAC;AAAA,EAC1E,MAAM,CAAC,QACL,0EAA0E,YAAY,GAAG,CAAC;AAAA,EAC5F,QAAQ,CAAC,QACP,qEAAqE,WAAW,GAAG,CAAC;AAAA,EACtF,YAAY,CAAC,QACX,qEAAqE,WAAW,GAAG,CAAC;AACxF;AAUO,SAAS,SAAS,OAAmB,OAAuB;AACjE,SAAO,UAAU,KAAK,EAAE,oBAAoB,KAAK,CAAC;AACpD;AAEA,IAAM,aAA8C,CAAC;AAQrD,eAAsB,UACpB,OACA,OACiB;AACjB,QAAM,MAAM,SAAS,OAAO,KAAK;AACjC,SAAQ,WAAW,GAAG,MAAM,MAAM,GAAG,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC;AAC7D;;;ADnHA,IAAM,kBAAkB,oBAAI,IAAmC;AAE/D,SAAS,eACP,OACA,OACuB;AACvB,QAAM,MAAM,SAAS,OAAO,KAAK;AACjC,MAAI,SAAS,gBAAgB,IAAI,GAAG;AACpC,MAAI,CAAC,QAAQ;AACX,aAAS,UAAU,OAAO,KAAK,EAC5B,KAAK,CAAC,YAAY;AACjB,UAAI,CAAC,WAAW,CAAC,QAAQ,SAAS,MAAM,EAAG,QAAO;AAClD,YAAM,UACJ,+BACA,OAAO,KAAK,OAAO,EAAE,SAAS,QAAQ;AACxC,aAAOC,WAAU,OAAO;AAAA,IAC1B,CAAC,EACA,MAAM,MAAM,IAAI;AACnB,oBAAgB,IAAI,KAAK,MAAM;AAAA,EACjC;AACA,SAAO;AACT;AAcA,eAAsB,SACpB,KACA,QACA,SACA,SACA,YACA,YACe;AACf,QAAM,EAAE,WAAW,UAAU,MAAM,IAAI;AACvC,QAAM,QAAQ,SAAS,CAAC;AACxB,MAAI,CAAC,MAAO;AACZ,QAAM,IAAI;AACV,QAAM,IAAI,UAAU,OAAO;AAC3B,QAAM,SAAS,aAAa,YAAY,UAAU,IAAI;AACtD,MAAI,YAAY,MAAM;AAGtB,MAAI,QAAQ;AACV;AAAA,MAAe;AAAA,MAAK;AAAA,MAAQ,cAAc,MAAM,KAAK;AAAA,MAAG,MACtD,cAAc,KAAK,WAAW,GAAG,CAAC;AAAA,IACpC;AAAA,EACF;AACA,MAAI,MAAM,oBAAoB,UAAa,MAAM,kBAAkB,GAAG;AACpE,QAAI,KAAK;AACT,QAAI,YAAY,MAAM;AACtB,QAAI,cAAc,MAAM,mBAAmB,MAAM;AACjD,QAAI,WAAW;AACf,oBAAgB,KAAK,WAAW,GAAG,CAAC;AACpC,QAAI,QAAQ;AAAA,EACd;AACA,gBAAc,KAAK,WAAW,GAAG,CAAC;AAElC,MAAI,cAAc,MAAM,SAAS,GAAG;AAClC,UAAM,UAAU,KAAK,OAAO,OAAO,SAAS,SAAS,UAAU;AAAA,EACjE;AAEA,aAAW,OAAO,UAAU;AAC1B,QAAI,IAAI,gBAAgB;AACtB,yBAAmB,KAAK,KAAK,SAAS,OAAO;AAAA,IAC/C;AAAA,EACF;AACF;AAEA,eAAe,UACb,KACA,OACA,MACA,SACA,SACA,YACe;AACf,QAAM,SAAS,MAAM,QAAQ;AAAA,IAC3B,MAAM,IAAI,CAAC,MAAM,eAAe,YAAY,EAAE,QAAQ,CAAC;AAAA,EACzD;AACA,QAAM,QAAQ,CAAC,GAAG,MAAM;AACtB,UAAM,MAAM,OAAO,CAAC;AACpB,QAAI,KAAK;AACP,UAAI,UAAU,KAAK,UAAU,EAAE,GAAG,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI;AAC/D;AAAA,IACF;AAEA;AAAA,MACE;AAAA,MACA,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,IACP;AACA,UAAM,gBAAgB,IAAI;AAC1B,QAAI,gBAAgB;AACpB,QAAI,SAAS,EAAE,UAAU,UAAU,EAAE,GAAG,UAAU,EAAE,QAAQ;AAC5D,QAAI,gBAAgB;AAAA,EACtB,CAAC;AACH;AASA,SAAS,YAAY,QAAqC;AACxD,QAAM,QAAQ,OAAO;AAAA,IACnB;AAAA,EACF;AACA,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO;AAAA,IACL,SAAS,WAAW,MAAM,CAAC,CAAE;AAAA,IAC7B,SAAS,WAAW,MAAM,CAAC,CAAE;AAAA,IAC7B,MAAM,WAAW,MAAM,CAAC,CAAE;AAAA,IAC1B,OAAO,MAAM,CAAC,EAAG,KAAK;AAAA,EACxB;AACF;AAGA,SAAS,cAAc,OAAuB;AAC5C,QAAM,SAASC,eAAc,KAAK;AAClC,SAAO,SAAS,OAAO,QAAQ;AACjC;AAYA,SAAS,eACP,KACA,QACA,WACA,QACM;AACN,MAAI,KAAK;AACT,MAAI,YAAY,OAAO;AACvB,MAAI,YAAY,EAAG,KAAI,eAAe;AACtC,MAAI,OAAO,OAAO,EAAG,KAAI,SAAS,QAAQ,OAAO,OAAO,CAAC;AACzD,MAAI,UAAU,OAAO,SAAS,OAAO,OAAO;AAC5C,SAAO;AACP,MAAI,QAAQ;AACd;AAEA,SAAS,mBACP,KACA,KACA,SACA,SACM;AACN,QAAM,aAAa,IAAI;AACvB,MAAI,CAAC,cAAc,eAAe,OAAQ;AAE1C,MAAI,cAAc,IAAI;AACtB,MAAI,YAAY,KAAK,IAAI,GAAG,IAAI,WAAW,GAAG;AAE9C,QAAM,IAAI,UAAU,IAAI;AACxB,QAAM,QAAQ,UAAU,IAAI;AAE5B,MAAI,WAAW,SAAS,WAAW,GAAG;AACpC,UAAM,IAAI,QAAQ,IAAI,SAAS;AAC/B,QAAI,UAAU;AACd,QAAI,OAAO,GAAG,CAAC;AACf,QAAI,OAAO,IAAI,IAAI,OAAO,CAAC;AAC3B,QAAI,OAAO;AAAA,EACb;AAEA,MAAI,WAAW,SAAS,cAAc,GAAG;AACvC,UAAM,IAAI,QAAQ,IAAI,WAAW;AACjC,QAAI,UAAU;AACd,QAAI,OAAO,GAAG,CAAC;AACf,QAAI,OAAO,IAAI,IAAI,OAAO,CAAC;AAC3B,QAAI,OAAO;AAAA,EACb;AAEA,MAAI,WAAW,SAAS,UAAU,GAAG;AACnC,UAAM,IAAI,QAAQ,IAAI,WAAW;AACjC,QAAI,UAAU;AACd,QAAI,OAAO,GAAG,CAAC;AACf,QAAI,OAAO,IAAI,IAAI,OAAO,CAAC;AAC3B,QAAI,OAAO;AAAA,EACb;AACF;;;AEzLA,eAAsB,SACpB,KACA,MACA,SACA,SACA,SACA,YACe;AACf,QAAM,IAAI,UAAU,KAAK;AACzB,QAAM,IAAI,UAAU,KAAK;AACzB,QAAM,EAAE,MAAM,IAAI;AAGlB,QAAM,gBAA+B,WAAW;AAAA,IAC9C,YAAY,oBAAI,IAAI;AAAA,IACpB,OAAO;AAAA,EACT;AAEA,MAAI,MAAM,YAAY,OAAQ;AAI9B,QAAM,aAAa,OAAO,MAAM,WAAW,CAAC;AAC5C,QAAM,UAAU,OAAO,SAAS,UAAU,IAAI,aAAa;AAC3D,MAAI,WAAW,EAAG;AAKlB,QAAM,QAAQ,EAAE,MAAM,MAAM;AAC5B,MAAI,KAAK;AACT,MAAI;AACF,UAAM,UAAU,KAAK,MAAM,GAAG,GAAG,SAAS,eAAe,YAAY,KAAK;AAAA,EAC5E,UAAE;AACA,QAAI,MAAM,KAAM,iBAAgB,GAAG;AACnC,QAAI,QAAQ;AAAA,EACd;AACF;AAGA,eAAe,UACb,KACA,MACA,GACA,GACA,SACA,eACA,YACA,OACe;AACf,QAAM,EAAE,OAAO,QAAQ,MAAM,IAAI;AAEjC,MAAI,MAAM,WAAW;AACnB;AAAA,MACE;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM;AAAA,IACR;AAAA,EACF;AAKA,MAAI,MAAM,UAAU;AAClB,kBAAc,KAAK,MAAM,UAAU,OAAO,GAAG,GAAG,OAAO,MAAM;AAAA,EAC/D;AAEA,QAAM,eAAe,yBAAyB,OAAO,OAAO,MAAM;AAKlE,MAAI,MAAM,gBAAgB;AACxB;AAAA,MACE;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAMA,QAAM,OAAO,kBAAkB,KAAK,SAAS,MAAM,MAAM;AAIzD,MAAI,MAAM,WAAW;AACnB,kBAAc,KAAK,GAAG,GAAG,OAAO,QAAQ,MAAM,WAAW,YAAY;AAAA,EACvE;AAGA,QAAM,YACJ,MAAM,aAAa,YACnB,MAAM,cAAc,YACpB,MAAM,cAAc;AAEtB,MAAI,WAAW;AACb,cAAU,KAAK,GAAG,GAAG,OAAO,QAAQ,YAAY;AAAA,EAClD;AAGA,MACE,MAAM,mBACN,MAAM,kBACN,MAAM,oBACN,MAAM,qBACN,MAAM,iBACN;AACA,aAAS,KAAK,GAAG,GAAG,OAAO,QAAQ,KAAK;AAAA,EAC1C;AAGA,MAAI,MAAM,iBAAiB;AACzB,UAAM,SAAS,kBAAkB,MAAM,eAAe;AAEtD,aAAS,IAAI,OAAO,SAAS,GAAG,KAAK,GAAG,KAAK;AAC3C,YAAM,QAAQ,OAAO,CAAC,EAAG,KAAK;AAC9B,YAAM,WAAW,sBAAsB,KAAK,OAAO,GAAG,GAAG,OAAO,MAAM;AACtE,UAAI,UAAU;AACZ,YAAI,YAAY;AAChB,YAAI,UAAU,YAAY,GAAG;AAC3B,cAAI,UAAU;AACd;AAAA,YACE;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,aAAa;AAAA,YACb,aAAa;AAAA,YACb,aAAa;AAAA,YACb,aAAa;AAAA,UACf;AACA,cAAI,KAAK;AAAA,QACX,OAAO;AACL,cAAI,SAAS,GAAG,GAAG,OAAO,MAAM;AAAA,QAClC;AAAA,MACF,OAAO;AAEL,cAAM,WAAW,MAAM,MAAM,wBAAwB;AACrD,YAAI,UAAU;AACZ,cAAI,UAAU,YAAY,GAAG;AAC3B,sBAAU,KAAK,GAAG,GAAG,OAAO,QAAQ,YAAY;AAAA,UAClD;AAEA,gBAAM,QAAQ,MAAM;AAAA,YAClB,cAAc;AAAA,YACd,SAAS,CAAC;AAAA,YACV,cAAc;AAAA,UAChB;AACA,gBAAM,SAAS,MAAM;AAErB,cAAI,WAAW,SAAS;AAEtB,kBAAM,IAAI;AAAA,cACR,MAAM;AAAA,cACN,MAAM;AAAA,cACN;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YACF;AACA,gBAAI;AAAA,cACF;AAAA,cACA,EAAE;AAAA,cACF,EAAE;AAAA,cACF,EAAE;AAAA,cACF,EAAE;AAAA,cACF,EAAE;AAAA,cACF,EAAE;AAAA,cACF,EAAE;AAAA,cACF,EAAE;AAAA,YACJ;AAAA,UACF,OAAO;AAEL,gBAAI,OAAe;AACnB,gBAAI,WAAW,WAAW;AACxB,oBAAM,IAAI;AAAA,gBACR,MAAM;AAAA,gBACN,MAAM;AAAA,gBACN;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,cACF;AACA,sBAAQ,EAAE;AACV,sBAAQ,EAAE;AAAA,YACZ,WAAW,WAAW,aAAa;AACjC,sBAAQ;AACR,sBAAQ;AAAA,YACV,OAAO;AAEL,sBAAQ,MAAM;AACd,sBAAQ,MAAM;AAAA,YAChB;AACA,kBAAM,SAAS,MAAM,oBAAoB;AACzC,kBAAM,QACJ,WAAW,YAAY,WAAW,aAAa,QAAQ;AACzD,kBAAM,QACJ,WAAW,YAAY,WAAW,aAAa,QAAQ;AACzD,qBAAS,KAAK,GAAG,KAAK,IAAI,QAAQ,MAAM,OAAO;AAC7C,uBAAS,KAAK,GAAG,KAAK,IAAI,OAAO,MAAM,OAAO;AAC5C,oBAAI,UAAU,OAAO,IAAI,IAAI,OAAO,KAAK;AAAA,cAC3C;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,cAAc,OAAO;AACvB,QAAI,cAAc;AAClB,QAAI,YAAY;AAChB,QAAI,WAAW,GAAG,GAAG,OAAO,MAAM;AAAA,EACpC;AAGA,MAAI,KAAK,gBAAgB,UAAa,KAAK,gBAAgB,IAAI;AAC7D,UAAM,aAAa,gBAAgB,MAAM,YAAY,KAAK;AAC1D,UAAM,cAAc,gBAAgB,MAAM,aAAa,KAAK;AAC5D,UAAM,eAAe,gBAAgB,MAAM,cAAc,KAAK;AAE9D,UAAM,aAAa,gBAAgB,MAAM,gBAAgB,KAAK;AAC9D,UAAM,cAAc,gBAAgB,MAAM,iBAAiB,KAAK;AAChE,UAAM,eAAe,gBAAgB,MAAM,kBAAkB,KAAK;AAElE,UAAM,WAAW,IAAI,cAAc;AACnC,UAAM,WAAW,IAAI,aAAa;AAClC,UAAM,eACJ,QAAQ,cAAc,eAAe,cAAc;AAGrD,UAAM,aACJ,KAAK,cAAc,iBAAiB,KAAK,QACrC,KAAK,aACL,WAAW,KAAK,aAAa,OAAO,cAAc,CAAC,CAAC,UAAU;AACpE,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAGA,MAAI,KAAK,SAAS,SAAS,KAAK,MAAM,KAAK;AACzC,UAAM,aAAa,gBAAgB,MAAM,YAAY,KAAK;AAC1D,UAAM,cAAc,gBAAgB,MAAM,aAAa,KAAK;AAC5D,UAAM,eAAe,gBAAgB,MAAM,cAAc,KAAK;AAC9D,UAAM,gBAAgB,gBAAgB,MAAM,eAAe,KAAK;AAEhE,UAAM,aAAa,gBAAgB,MAAM,gBAAgB,KAAK;AAC9D,UAAM,cAAc,gBAAgB,MAAM,iBAAiB,KAAK;AAChE,UAAM,eAAe,gBAAgB,MAAM,kBAAkB,KAAK;AAClE,UAAM,gBAAgB,gBAAgB,MAAM,mBAAmB,KAAK;AAEpE,UAAM,OAAO,IAAI,cAAc;AAC/B,UAAM,OAAO,IAAI,aAAa;AAC9B,UAAM,OACJ,QAAQ,cAAc,eAAe,cAAc;AACrD,UAAM,OACJ,SAAS,aAAa,gBAAgB,aAAa;AAIrD,QAAI,CAAC,WAAW;AACd,UAAI,UAAU,YAAY,GAAG;AAC3B,kBAAU,KAAK,MAAM,MAAM,MAAM,MAAM,YAAY;AAAA,MACrD;AAAA,IACF;AAEA,UAAM;AAAA,MACJ;AAAA,MACA,KAAK,MAAM;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAGA,MAAI,KAAK,SAAS,OAAO;AACvB,qBAAiB,KAAK,MAAM,GAAG,GAAG,OAAO,MAAM;AAAA,EACjD,OAAO;AACL,eAAW,SAAS,KAAK,UAAU;AACjC,YAAM,SAAS,KAAK,OAAO,GAAG,GAAG,eAAe,UAAU;AAAA,IAC5D;AAAA,EACF;AACF;AAEA,SAAS,eACP,KACA,WACA,GACA,GACA,OACA,QACA,iBACM;AAEN,MAAI,KAAK,IAAI,QAAQ;AACrB,MAAI,KAAK,IAAI,SAAS;AAEtB,MAAI,iBAAiB;AACnB,UAAM,QAAQ,gBAAgB,MAAM,KAAK;AACzC,SAAK,cAAc,MAAM,CAAC,GAAG,GAAG,KAAK;AACrC,SAAK,cAAc,MAAM,CAAC,GAAG,GAAG,MAAM;AAAA,EACxC;AAEA,MAAI,UAAU,IAAI,EAAE;AAGpB,QAAM,QAAQ,UAAU,SAAS,mBAAmB;AAEpD,aAAW,CAAC,EAAE,MAAM,IAAI,KAAK,OAAO;AAClC,UAAM,SAAS,KAAM,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AAEnD,YAAQ,MAAM;AAAA,MACZ,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK,cAAc;AACjB,cAAM,KACJ,SAAS,eAAe,IAAI,eAAe,OAAO,CAAC,GAAI,KAAK;AAC9D,cAAM,KACJ,SAAS,eACL,IACA;AAAA,UACE,OAAO,SAAS,cAAc,IAAI,CAAC,KAAK;AAAA,UACxC;AAAA,QACF;AACN,YAAI,UAAU,IAAI,EAAE;AACpB;AAAA,MACF;AAAA,MACA,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK,UAAU;AACb,cAAM,KAAK,SAAS,WAAW,IAAI,WAAW,OAAO,CAAC,CAAE;AACxD,cAAM,KACJ,SAAS,WACL,IACA,WAAW,OAAO,SAAS,UAAU,IAAI,CAAC,KAAK,OAAO,EAAE,CAAC;AAC/D,YAAI,MAAM,IAAI,EAAE;AAChB;AAAA,MACF;AAAA,MACA,KAAK,UAAU;AACb,cAAM,QAAQ,WAAW,OAAO,CAAC,CAAE;AACnC,YAAI,OAAO,KAAK;AAChB;AAAA,MACF;AAAA,MACA,KAAK,SAAS;AACZ,cAAM,QAAQ,WAAW,OAAO,CAAC,CAAE;AACnC,YAAI,UAAU,GAAG,GAAG,KAAK,IAAI,KAAK,GAAG,GAAG,GAAG,CAAC;AAC5C;AAAA,MACF;AAAA,MACA,KAAK,SAAS;AACZ,cAAM,QAAQ,WAAW,OAAO,CAAC,CAAE;AACnC,YAAI,UAAU,GAAG,KAAK,IAAI,KAAK,GAAG,GAAG,GAAG,GAAG,CAAC;AAC5C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,UAAU,CAAC,IAAI,CAAC,EAAE;AACxB;AAEA,SAAS,cACP,OACA,MACA,MACQ;AACR,MAAI,CAAC,MAAO,QAAO,OAAO,OAAO;AACjC,MAAI,UAAU,UAAU,UAAU,MAAO,QAAO;AAChD,MAAI,UAAU,WAAW,UAAU,SAAU,QAAO,OAAO;AAC3D,MAAI,UAAU,SAAU,QAAO,OAAO,OAAO;AAC7C,SAAO,OAAO,eAAe,OAAO,IAAI;AAC1C;AAEA,SAAS,WAAW,OAAuB;AACzC,MAAI,MAAM,SAAS,KAAK,EAAG,QAAQ,WAAW,KAAK,IAAI,KAAK,KAAM;AAClE,MAAI,MAAM,SAAS,KAAK,EAAG,QAAO,WAAW,KAAK;AAClD,MAAI,MAAM,SAAS,MAAM,EAAG,QAAO,WAAW,KAAK,IAAI,IAAI,KAAK;AAChE,SAAO,WAAW,KAAK;AACzB;;;AC7aA,SAAS,mBAAmB;AAI5B,IAAM,kBAAkB,oBAAI,IAAY;AAejC,SAAS,aAAa,MAAsB;AACjD,QAAM,MAAM,GAAG,KAAK,IAAI,IAAI,KAAK,MAAM,IAAI,KAAK,KAAK;AACrD,MAAI,gBAAgB,IAAI,GAAG,EAAG;AAE9B,QAAM,SAAS,OAAO,SAAS,KAAK,IAAI,IACpC,KAAK,OACL,OAAO,KAAK,KAAK,IAAI;AAEzB,cAAY,SAAS,QAAQ,KAAK,IAAI;AAEtC,kBAAgB,IAAI,GAAG;AACzB;AAQO,SAAS,qBAAqB,MAAc,WAA0B;AAC3E,cAAY,iBAAiB,MAAM,aAAa,EAAE;AACpD;AAOO,SAAS,qBAA+B;AAC7C,SAAO,YAAY,SAAS,IAAI,CAAC,MAA0B,EAAE,MAAM;AACrE;AAMO,SAAS,sBAAsB,OAAyB;AAC7D,aAAW,QAAQ,OAAO;AACxB,iBAAa,IAAI;AAAA,EACnB;AACF;;;AClDA,IAAM,QAAQ,CAAC,OAAO,SAAS,UAAU,MAAM;AAK/C,SAAS,WAAW,OAAyB;AAC3C,QAAM,QAAQ,MAAM,SAAS,EAAE,MAAM,KAAK,EAAE,OAAO,OAAO;AAC1D,UAAQ,MAAM,QAAQ;AAAA,IACpB,KAAK;AACH,aAAO,CAAC,MAAM,CAAC,GAAI,MAAM,CAAC,GAAI,MAAM,CAAC,GAAI,MAAM,CAAC,CAAE;AAAA,IACpD,KAAK;AACH,aAAO,CAAC,MAAM,CAAC,GAAI,MAAM,CAAC,GAAI,MAAM,CAAC,GAAI,MAAM,CAAC,CAAE;AAAA,IACpD,KAAK;AACH,aAAO,CAAC,MAAM,CAAC,GAAI,MAAM,CAAC,GAAI,MAAM,CAAC,GAAI,MAAM,CAAC,CAAE;AAAA,IACpD;AACE,aAAO,CAAC,MAAM,CAAC,GAAI,MAAM,CAAC,GAAI,MAAM,CAAC,GAAI,MAAM,CAAC,CAAE;AAAA,EACtD;AACF;AAEA,SAAS,WAAW,GAAyC;AAC3D,MAAI,MAAM,UAAa,MAAM,KAAM,QAAO;AAC1C,QAAM,IAAI,OAAO,CAAC;AAClB,MAAI,MAAM,OAAQ,QAAO;AACzB,QAAM,IAAI,OAAO,CAAC;AAClB,MAAI,MAAM,MAAM,CAAC,MAAM,CAAC,EAAG,QAAO;AAClC,SAAO;AACT;AAMO,SAAS,YACd,KACA,cACe;AACf,QAAM,QAAQ,EAAE,GAAG,IAAI;AAGvB,MAAI,MAAM,WAAW,QAAW;AAC9B,UAAM,QAAQ,WAAW,OAAO,MAAM,MAAM,CAAC;AAC7C,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,YAAM,MAAM,SAAS,MAAM,CAAC,CAAC;AAC7B,UAAI,MAAM,GAAG,MAAM,OAAW,OAAM,GAAG,IAAI,WAAW,MAAM,CAAC,CAAC;AAAA,IAChE;AACA,WAAO,MAAM;AAAA,EACf;AAGA,MAAI,MAAM,YAAY,QAAW;AAC/B,UAAM,QAAQ,WAAW,OAAO,MAAM,OAAO,CAAC;AAC9C,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,YAAM,MAAM,UAAU,MAAM,CAAC,CAAC;AAC9B,UAAI,MAAM,GAAG,MAAM,OAAW,OAAM,GAAG,IAAI,WAAW,MAAM,CAAC,CAAC;AAAA,IAChE;AACA,WAAO,MAAM;AAAA,EACf;AAGA,MAAI,MAAM,iBAAiB,QAAW;AACpC,UAAM,QAAQ,WAAW,OAAO,MAAM,YAAY,CAAC;AACnD,UAAM,UAAU;AAAA,MACd;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAI,MAAM,QAAQ,CAAC,CAAE,MAAM;AACzB,cAAM,QAAQ,CAAC,CAAE,IAAI,WAAW,MAAM,CAAC,CAAC;AAAA,IAC5C;AACA,WAAO,MAAM;AAAA,EACf;AAGA,MAAI,MAAM,gBAAgB,QAAW;AACnC,UAAM,QAAQ,WAAW,OAAO,MAAM,WAAW,CAAC;AAClD,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,YAAM,MAAM,SAAS,MAAM,CAAC,CAAC;AAC7B,UAAI,MAAM,GAAG,MAAM,OAAW,OAAM,GAAG,IAAI,WAAW,MAAM,CAAC,CAAC;AAAA,IAChE;AACA,WAAO,MAAM;AAAA,EACf;AAGA,MAAI,MAAM,gBAAgB,QAAW;AACnC,UAAM,MAAM,MAAM;AAClB,eAAW,QAAQ,OAAO;AACxB,YAAM,MAAM,SAAS,IAAI;AACzB,UAAI,MAAM,GAAG,MAAM,OAAW,OAAM,GAAG,IAAI;AAAA,IAC7C;AACA,WAAO,MAAM;AAAA,EACf;AAGA,MAAI,MAAM,gBAAgB,QAAW;AACnC,UAAM,MAAM,MAAM;AAClB,eAAW,QAAQ,OAAO;AACxB,YAAM,MAAM,SAAS,IAAI;AACzB,UAAI,MAAM,GAAG,MAAM,OAAW,OAAM,GAAG,IAAI;AAAA,IAC7C;AACA,WAAO,MAAM;AAAA,EACf;AAGA,MAAI,MAAM,WAAW,QAAW;AAC9B,UAAM,QAAQ,OAAO,MAAM,MAAM,EAAE,MAAM,KAAK;AAC9C,UAAM,QAAQ,WAAW,MAAM,CAAC,CAAC;AACjC,UAAM,cAAc,MAAM,CAAC,KAAK;AAChC,UAAM,QAAQ,MAAM,CAAC,KAAK;AAC1B,eAAW,QAAQ,OAAO;AACxB,UAAI,MAAM,SAAS,IAAI,OAAO,MAAM;AAClC,cAAM,SAAS,IAAI,OAAO,IAAI;AAChC,UAAI,MAAM,SAAS,IAAI,OAAO,MAAM;AAClC,cAAM,SAAS,IAAI,OAAO,IAAI;AAChC,UAAI,MAAM,SAAS,IAAI,OAAO,MAAM;AAClC,cAAM,SAAS,IAAI,OAAO,IAAI;AAAA,IAClC;AACA,WAAO,MAAM;AAAA,EACf;AAGA,aAAW,QAAQ,OAAO;AACxB,UAAM,MAAM,SAAS,IAAI;AACzB,QAAI,MAAM,GAAG,MAAM,QAAW;AAC5B,YAAM,QAAQ,OAAO,MAAM,GAAG,CAAC,EAAE,MAAM,KAAK;AAC5C,YAAM,QAAQ,WAAW,MAAM,CAAC,CAAC;AACjC,YAAM,cAAc,MAAM,CAAC,KAAK;AAChC,YAAM,QAAQ,MAAM,CAAC,KAAK;AAC1B,UAAI,MAAM,GAAG,GAAG,OAAO,MAAM,OAAW,OAAM,GAAG,GAAG,OAAO,IAAI;AAC/D,UAAI,MAAM,GAAG,GAAG,OAAO,MAAM;AAC3B,cAAM,GAAG,GAAG,OAAO,IAAI;AACzB,UAAI,MAAM,GAAG,GAAG,OAAO,MAAM,OAAW,OAAM,GAAG,GAAG,OAAO,IAAI;AAC/D,aAAO,MAAM,GAAG;AAAA,IAClB;AAAA,EACF;AAGA,MAAI,MAAM,SAAS,QAAW;AAC5B,UAAM,MAAM,OAAO,MAAM,IAAI;AAC7B,QAAI,QAAQ,QAAQ;AAClB,UAAI,MAAM,aAAa,OAAW,OAAM,WAAW;AACnD,UAAI,MAAM,eAAe,OAAW,OAAM,aAAa;AACvD,UAAI,MAAM,cAAc,OAAW,OAAM,YAAY;AAAA,IACvD,OAAO;AACL,YAAM,QAAQ,IAAI,MAAM,KAAK;AAC7B,UAAI,MAAM,WAAW,GAAG;AACtB,cAAM,IAAI,WAAW,MAAM,CAAC,CAAE;AAC9B,YAAI,CAAC,MAAM,CAAC,GAAG;AACb,cAAI,MAAM,aAAa,OAAW,OAAM,WAAW;AACnD,cAAI,MAAM,eAAe,OAAW,OAAM,aAAa;AACvD,cAAI,MAAM,cAAc,OAAW,OAAM,YAAY;AAAA,QACvD;AAAA,MACF,WAAW,MAAM,WAAW,GAAG;AAC7B,YAAI,MAAM,aAAa;AACrB,gBAAM,WAAW,WAAW,MAAM,CAAC,CAAE;AACvC,YAAI,MAAM,eAAe;AACvB,gBAAM,aAAa,WAAW,MAAM,CAAC,CAAE;AAAA,MAC3C,WAAW,MAAM,UAAU,GAAG;AAC5B,YAAI,MAAM,aAAa;AACrB,gBAAM,WAAW,WAAW,MAAM,CAAC,CAAE;AACvC,YAAI,MAAM,eAAe;AACvB,gBAAM,aAAa,WAAW,MAAM,CAAC,CAAE;AACzC,YAAI,MAAM,cAAc;AACtB,gBAAM,YAAY,WAAW,MAAM,CAAC,CAAC;AAAA,MACzC;AAAA,IACF;AACA,WAAO,MAAM;AAAA,EACf;AAGA,MAAI,MAAM,QAAQ,QAAW;AAC3B,UAAM,QAAQ,WAAW,OAAO,MAAM,GAAG,CAAC;AAC1C,QAAI,MAAM,WAAW,OAAW,OAAM,SAAS,WAAW,MAAM,CAAC,CAAC;AAClE,QAAI,MAAM,cAAc,OAAW,OAAM,YAAY,WAAW,MAAM,CAAC,CAAC;AACxE,WAAO,MAAM;AAAA,EACf;AAGA,MAAI,MAAM,eAAe,QAAW;AAClC,UAAM,QAAQ,yBAAyB,OAAO,MAAM,UAAU,CAAC;AAC/D,QAAI,MAAM,UAAU,UAAa,MAAM,oBAAoB;AACzD,YAAM,kBAAkB,MAAM;AAChC,QAAI,MAAM,WAAW,UAAa,MAAM,qBAAqB;AAC3D,YAAM,mBAAmB,MAAM;AACjC,QAAI,MAAM,SAAS,UAAa,MAAM,mBAAmB;AACvD,YAAM,iBAAiB,MAAM;AAC/B,QAAI,MAAM,UAAU,UAAa,MAAM,oBAAoB;AACzD,YAAM,kBAAkB,MAAM;AAChC,WAAO,MAAM;AAAA,EACf;AAGA,MAAI,MAAM,aAAa,QAAW;AAChC,QAAI,MAAM,cAAc,OAAW,OAAM,YAAY,MAAM;AAC3D,QAAI,MAAM,cAAc,OAAW,OAAM,YAAY,MAAM;AAAA,EAC7D;AAGA,MAAI,MAAM,YAAY,QAAW;AAC/B,UAAM,MAAM,OAAO,MAAM,OAAO;AAChC,QAAI,QAAQ,YAAY,QAAQ,QAAQ;AACtC,YAAM,gBAAgB;AAAA,IACxB,OAAO;AACL,YAAM,QAAQ,IAAI,MAAM,KAAK;AAC7B,YAAM,gBAAgB,MAAM,CAAC;AAC7B,UAAI,MAAM,SAAS,GAAG;AACpB,cAAM,gBAAgB,MAAM,MAAM,CAAC,EAAE,KAAK,GAAG;AAAA,MAC/C;AAAA,IACF;AACA,WAAO,MAAM;AAAA,EACf;AAGA,MAAI,MAAM,qBAAqB,QAAW;AACxC,UAAM,MAAM,OAAO,MAAM,gBAAgB,EAAE,KAAK;AAChD,UAAM,QAAQ,IAAI,MAAM,gBAAgB;AACxC,QAAI,OAAO;AACT,UAAI,MAAM,0BAA0B;AAClC,cAAM,wBAAwB,WAAW,MAAM,CAAC,CAAC;AACnD,UAAI,MAAM,0BAA0B;AAClC,cAAM,wBAAwB,MAAM,CAAC;AAAA,IACzC,OAAO;AAEL,UAAI,MAAM,0BAA0B;AAClC,cAAM,wBAAwB,WAAW,GAAG;AAAA,IAChD;AACA,WAAO,MAAM;AAAA,EACf;AAGA,MAAI,MAAM,yBAAyB,QAAW;AAC5C,QAAI,MAAM,mBAAmB;AAC3B,YAAM,iBAAiB,MAAM;AAC/B,WAAO,MAAM;AAAA,EACf;AAEA,MAAI,MAAM,aAAa,QAAW;AAChC,QAAI,MAAM,iBAAiB,OAAW,OAAM,eAAe,MAAM;AACjE,WAAO,MAAM;AAAA,EACf;AACA,MAAI,MAAM,mBAAmB,QAAW;AACtC,QAAI,MAAM,aAAa,OAAW,OAAM,WAAW,MAAM;AACzD,WAAO,MAAM;AAAA,EACf;AAGA,MAAI,OAAO,MAAM,eAAe,UAAU;AACxC,UAAM,WAAW,MAAM,WACpB,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,gBAAgB,EAAE,CAAC,EAC/C,OAAO,OAAO;AACjB,QAAI,cAAc;AAChB,YAAM,UAAU,IAAI,IAAI,QAAQ;AAChC,iBAAW,QAAQ,cAAc;AAC/B,YAAI,CAAC,QAAQ,IAAI,IAAI,EAAG,UAAS,KAAK,IAAI;AAAA,MAC5C;AAAA,IACF;AACA,UAAM,aAAa,SAAS,KAAK,IAAI;AAAA,EACvC;AAEA,SAAO;AACT;AAEA,IAAM,qBAAqB,oBAAI,IAAI;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AACD,IAAM,uBAAuB,oBAAI,IAAI;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AACD,IAAM,yBAAyB,oBAAI,IAAI,CAAC,UAAU,SAAS,OAAO,CAAC;AACnE,IAAM,kBAAkB,oBAAI,IAAI,CAAC,cAAc,eAAe,aAAa,CAAC;AAC5E,IAAM,cACJ;AAIF,SAAS,mBAAmB,OAAyB;AACnD,QAAM,SAAmB,CAAC;AAC1B,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,IAAI,MAAM,CAAC;AACjB,QAAI,MAAM,KAAK;AACb,UAAI,QAAQ;AACZ,aAAO;AACP;AACA,aAAO,IAAI,MAAM,UAAU,QAAQ,GAAG;AACpC,cAAM,KAAK,MAAM,CAAC;AAClB,YAAI,OAAO,IAAK;AAAA,iBACP,OAAO,IAAK;AACrB,eAAO;AACP;AAAA,MACF;AACA;AAAA,IACF,WAAW,KAAK,KAAK,CAAC,GAAG;AACvB,UAAI,KAAK;AACP,eAAO,KAAK,GAAG;AACf,cAAM;AAAA,MACR;AAAA,IACF,WAAW,MAAM,KAAK;AACpB,UAAI,KAAK;AACP,eAAO,KAAK,GAAG;AACf,cAAM;AAAA,MACR;AACA,aAAO,KAAK,GAAG;AAAA,IACjB,OAAO;AACL,aAAO;AAAA,IACT;AAAA,EACF;AACA,MAAI,IAAK,QAAO,KAAK,GAAG;AACxB,SAAO;AACT;AASA,SAAS,WAAW,OAAgC;AAClD,QAAM,MAAuB,CAAC;AAC9B,QAAM,aAAuB,CAAC;AAC9B,MAAI,aAAa;AACjB,aAAW,OAAO,mBAAmB,KAAK,GAAG;AAC3C,QAAI,QAAQ,KAAK;AACf,mBAAa;AACb;AAAA,IACF;AACA,QAAI,YAAY;AACd,iBAAW,KAAK,GAAG;AACnB;AAAA,IACF;AACA,QAAI,YAAY,KAAK,GAAG,GAAG;AACzB,UAAI,QAAQ;AACZ;AAAA,IACF;AACA,QAAI,QAAQ,OAAQ;AACpB,QAAI,mBAAmB,IAAI,GAAG,GAAG;AAC/B,UAAI,SAAS;AACb;AAAA,IACF;AAGA,QACE,qBAAqB,IAAI,GAAG,KAC5B,uBAAuB,IAAI,GAAG,KAC9B,gBAAgB,IAAI,GAAG,KACvB,QAAQ,KAAK,GAAG,GAChB;AACA;AAAA,IACF;AACA,QAAI,QAAQ;AAAA,EACd;AACA,MAAI,WAAW,SAAS,EAAG,KAAI,OAAO,WAAW,KAAK,GAAG;AACzD,SAAO;AACT;AAOO,SAAS,yBAAyB,OAAgC;AACvE,QAAM,SAAS,kBAAkB,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AAC3D,MAAI,OAAO,UAAU,EAAG,QAAO,WAAW,OAAO,CAAC,KAAK,EAAE;AAEzD,QAAM,SAAS,OAAO,IAAI,UAAU;AACpC,QAAM,MAAuB,CAAC;AAC9B,QAAM,SAAS,OAAO,IAAI,CAAC,MAAM,EAAE,SAAS,MAAM;AAClD,MAAI,OAAO,KAAK,CAAC,MAAM,MAAM,MAAM,EAAG,KAAI,QAAQ,OAAO,KAAK,IAAI;AAClE,aAAW,KAAK,QAAQ;AACtB,QAAI,EAAE,WAAW,UAAa,IAAI,WAAW;AAC3C,UAAI,SAAS,EAAE;AACjB,QAAI,EAAE,SAAS,UAAa,IAAI,SAAS,OAAW,KAAI,OAAO,EAAE;AAAA,EACnE;AACA,QAAM,aAAa,OAAO,OAAO,SAAS,CAAC,GAAG;AAC9C,MAAI,eAAe,OAAW,KAAI,QAAQ;AAC1C,SAAO;AACT;;;AC7YA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAmBA,SAAS,iBAA2B;AACzC,SAAO,KAAK,KAAK,OAAO;AAC1B;AAEA,IAAI;AAQG,SAAS,qBAA+B;AAC7C,MAAI,CAAC,YAAY;AACf,iBAAa,KAAK,OAAO,OAAO;AAChC,eAAW,oBAAoB,CAAC;AAAA,EAClC;AACA,SAAO,KAAK,KAAK,OAAO,UAAU;AACpC;AAEO,SAAS,aAAa,MAAsB;AACjD,OAAK,cAAc;AACrB;;;ACnCO,SAAS,kBAAkB,MAAgB,OAA4B;AAE5E,MAAI,MAAM,YAAY,QAAQ;AAC5B,SAAK,WAAW,QAAQ,IAAI;AAAA,EAC9B,OAAO;AACL,SAAK,WAAW,QAAQ,IAAI;AAAA,EAC9B;AAGA;AACE,UAAM,MAAqC;AAAA,MACzC,KAAK,cAAc;AAAA,MACnB,eAAe,cAAc;AAAA,MAC7B,QAAQ,cAAc;AAAA,MACtB,kBAAkB,cAAc;AAAA,IAClC;AACA,SAAK;AAAA,MACH,IAAI,MAAM,iBAAiB,KAAK,KAAK,cAAc;AAAA,IACrD;AAAA,EACF;AAGA,MAAI,MAAM,gBAAgB;AACxB,UAAM,MAA+B;AAAA,MACnC,cAAc,QAAQ;AAAA,MACtB,YAAY,QAAQ;AAAA,MACpB,QAAQ,QAAQ;AAAA,MAChB,iBAAiB,QAAQ;AAAA,MACzB,gBAAgB,QAAQ;AAAA,MACxB,gBAAgB,QAAQ;AAAA,IAC1B;AACA,UAAM,KAAK,IAAI,MAAM,cAAc;AACnC,QAAI,OAAO,OAAW,MAAK,kBAAkB,EAAE;AAAA,EACjD;AASA,MAAI,MAAM,YAAY;AACpB,UAAM,MAA6B;AAAA,MACjC,cAAc,MAAM;AAAA,MACpB,YAAY,MAAM;AAAA,MAClB,QAAQ,MAAM;AAAA,MACd,SAAS,MAAM;AAAA,MACf,UAAU,MAAM;AAAA,IAClB;AACA,UAAM,KAAK,IAAI,MAAM,UAAU;AAC/B,QAAI,OAAO,OAAW,MAAK,cAAc,EAAE;AAAA,EAC7C;AAGA,MAAI,MAAM,WAAW;AACnB,UAAM,MAA6B;AAAA,MACjC,MAAM,MAAM;AAAA,MACZ,cAAc,MAAM;AAAA,MACpB,YAAY,MAAM;AAAA,MAClB,QAAQ,MAAM;AAAA,MACd,SAAS,MAAM;AAAA,MACf,UAAU,MAAM;AAAA,IAClB;AACA,UAAM,MAAM,IAAI,MAAM,SAAS;AAC/B,QAAI,QAAQ,OAAW,MAAK,aAAa,GAAG;AAAA,EAC9C;AAGA,MAAI,MAAM,cAAc;AACtB,UAAM,MAA6B;AAAA,MACjC,cAAc,MAAM;AAAA,MACpB,YAAY,MAAM;AAAA,MAClB,QAAQ,MAAM;AAAA,MACd,SAAS,MAAM;AAAA,MACf,iBAAiB,MAAM;AAAA,MACvB,gBAAgB,MAAM;AAAA,IACxB;AACA,UAAM,KAAK,IAAI,MAAM,YAAY;AACjC,QAAI,OAAO,OAAW,MAAK,gBAAgB,EAAE;AAAA,EAC/C;AAGA,MAAI,MAAM,UAAU;AAClB,UAAM,MAA4B;AAAA,MAChC,QAAQ,KAAK;AAAA,MACb,MAAM,KAAK;AAAA,MACX,gBAAgB,KAAK;AAAA,IACvB;AACA,UAAM,KAAK,IAAI,MAAM,QAAQ;AAC7B,QAAI,OAAO,OAAW,MAAK,YAAY,EAAE;AAAA,EAC3C;AAGA,MAAI,MAAM,aAAa,OAAW,MAAK,YAAY,MAAM,QAAQ;AAEjE,OAAK,cAAc,MAAM,cAAc,CAAC;AACxC,MAAI,MAAM,cAAc,QAAW;AACjC,QAAI,OAAO,MAAM,cAAc,UAAU;AACvC,WAAK,aAAa,MAAM,SAAS;AAAA,IACnC,WAAW,OAAO,MAAM,SAAS,EAAE,SAAS,GAAG,GAAG;AAChD,WAAK,aAAa,OAAO,MAAM,SAAS,CAAiB;AAAA,IAC3D,WAAW,MAAM,cAAc,QAAQ;AACrC,WAAK,aAAa,MAAM;AAAA,IAC1B,OAAO;AACL,YAAM,IAAI,WAAW,OAAO,MAAM,SAAS,CAAC;AAC5C,UAAI,CAAC,MAAM,CAAC,EAAG,MAAK,aAAa,CAAC;AAAA,IACpC;AAAA,EACF;AAGA,iBAAe,MAAM,YAAY,MAAM,KAAK;AAC5C,iBAAe,MAAM,aAAa,MAAM,MAAM;AAC9C,iBAAe,MAAM,eAAe,MAAM,QAAQ;AAClD,iBAAe,MAAM,gBAAgB,MAAM,SAAS;AACpD,iBAAe,MAAM,eAAe,MAAM,QAAQ;AAClD,iBAAe,MAAM,gBAAgB,MAAM,SAAS;AAGpD,MAAI,MAAM,aAAa,YAAY;AACjC,SAAK,gBAAgB,aAAa,QAAQ;AAAA,EAC5C,OAAO;AACL,SAAK,gBAAgB,aAAa,QAAQ;AAAA,EAC5C;AAGA,iBAAe,MAAM,eAAe,KAAK,KAAK,MAAM,GAAG;AACvD,iBAAe,MAAM,eAAe,KAAK,OAAO,MAAM,KAAK;AAC3D,iBAAe,MAAM,eAAe,KAAK,QAAQ,MAAM,MAAM;AAC7D,iBAAe,MAAM,eAAe,KAAK,MAAM,MAAM,IAAI;AAGzD,iBAAe,MAAM,aAAa,KAAK,KAAK,MAAM,SAAS;AAC3D,iBAAe,MAAM,aAAa,KAAK,OAAO,MAAM,WAAW;AAC/D,iBAAe,MAAM,aAAa,KAAK,QAAQ,MAAM,YAAY;AACjE,iBAAe,MAAM,aAAa,KAAK,MAAM,MAAM,UAAU;AAG7D,iBAAe,MAAM,cAAc,KAAK,KAAK,MAAM,UAAU;AAC7D,iBAAe,MAAM,cAAc,KAAK,OAAO,MAAM,YAAY;AACjE,iBAAe,MAAM,cAAc,KAAK,QAAQ,MAAM,aAAa;AACnE,iBAAe,MAAM,cAAc,KAAK,MAAM,MAAM,WAAW;AAG/D,MAAI,MAAM,mBAAmB;AAC3B,SAAK,UAAU,KAAK,KAAK,MAAM,cAAwB;AACzD,MAAI,MAAM,qBAAqB;AAC7B,SAAK,UAAU,KAAK,OAAO,MAAM,gBAA0B;AAC7D,MAAI,MAAM,sBAAsB;AAC9B,SAAK,UAAU,KAAK,QAAQ,MAAM,iBAA2B;AAC/D,MAAI,MAAM,oBAAoB;AAC5B,SAAK,UAAU,KAAK,MAAM,MAAM,eAAyB;AAG3D,MAAI,MAAM,WAAW,OAAW,MAAK,OAAO,OAAO,KAAK,MAAM,MAAM;AACpE,MAAI,MAAM,cAAc;AACtB,SAAK,OAAO,OAAO,QAAQ,MAAM,SAAS;AAG5C,MACE,MAAM,aAAa,YACnB,MAAM,cAAc,YACpB,MAAM,cAAc,UACpB;AACA,SAAK,YAAY,SAAS,MAAM;AAAA,EAClC,OAAO;AACL,SAAK,YAAY,SAAS,OAAO;AAAA,EACnC;AACF;AAEA,SAAS,eACP,MACA,QAOA,OACM;AACN,MAAI,UAAU,OAAW;AACzB,MAAI,UAAU,QAAQ;AACpB,QAAI,WAAW,cAAc,WAAW,aAAa;AACnD,WAAK,MAAM,EAAE,MAAM;AAAA,IACrB;AACA;AAAA,EACF;AACA,MAAI,OAAO,UAAU,UAAU;AAC7B,SAAK,MAAM,EAAE,KAAK;AAClB;AAAA,EACF;AACA,QAAM,IAAI,OAAO,KAAK;AACtB,MAAI,EAAE,SAAS,GAAG,GAAG;AACnB,SAAK,MAAM,EAAE,CAAiB;AAAA,EAChC,OAAO;AACL,UAAM,IAAI,WAAW,CAAC;AACtB,QAAI,CAAC,MAAM,CAAC,EAAG,MAAK,MAAM,EAAE,CAAC;AAAA,EAC/B;AACF;AAEA,SAAS,eACP,MACA,QACA,MACA,OACM;AACN,MAAI,UAAU,OAAW;AACzB,MAAI,UAAU,UAAU,WAAW,aAAa;AAC9C,SAAK,UAAU,MAAM,MAAM;AAC3B;AAAA,EACF;AACA,MAAI,OAAO,UAAU,UAAU;AAC7B,SAAK,MAAM,EAAE,MAAM,KAAK;AACxB;AAAA,EACF;AACA,QAAM,IAAI,OAAO,KAAK;AACtB,MAAI,EAAE,SAAS,GAAG,GAAG;AACnB,SAAK,MAAM,EAAE,MAAM,CAAiB;AAAA,EACtC,OAAO;AACL,UAAM,IAAI,WAAW,CAAC;AACtB,QAAI,CAAC,MAAM,CAAC,EAAG,MAAK,MAAM,EAAE,MAAM,CAAC;AAAA,EACrC;AACF;;;ACxLA,eAAsB,gBACpB,SACA,gBACA,iBACA,cACA,cACA,SACuD;AACvD,QAAM,gBAA+B,WAAW;AAAA,IAC9C,YAAY,oBAAI,IAAI;AAAA,IACpB,OAAO;AAAA,EACT;AACA,QAAM,cAAc,iBAAiB,OAAO;AAC5C,QAAM,kBAAkB,OAAO,WAAW,IACtC,mBAAmB,IACnB,eAAe;AAGnB,QAAM,YAAY,cAAc,SAC5B,EAAE,GAAG,eAAe,YAAY,aAAa,KAAK,IAAI,EAAE,IACxD;AAGJ,QAAM,cAAc,MAAM;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAIA,QAAM,eAAe,eAAe;AACpC,eAAa,SAAS,cAAc;AACpC,eAAa,UAAU,eAAe;AACtC,eAAa,iBAAiB,cAAc,GAAG;AAC/C,eAAa,YAAY,iBAAiB,CAAC;AAE3C,eAAa,gBAAgB,gBAAgB,eAAe;AAC5D;AAAA,IACE;AAAA,IACA,MAAM,aAAa,gBAAgB,gBAAgB,eAAe;AAAA,IAClE,cAAc;AAAA,EAChB;AAEA,QAAM,gBAAgB,cAAc,aAAa,eAAe;AAChE,eAAa,YAAY;AAEzB,QAAM,OAAmB;AAAA,IACvB,MAAM;AAAA,IACN,OAAO;AAAA,IACP,UAAU,CAAC,aAAa;AAAA,IACxB,OAAO,CAAC;AAAA,IACR,GAAG;AAAA,IACH,GAAG;AAAA,IACH,OAAO;AAAA,IACP,QAAQ;AAAA,EACV;AACA,SAAO,EAAE,MAAM,YAAY,cAAc,WAAW;AACtD;AAOA,eAAe,UACb,SACA,aACA,UACA,eACA,gBACA,cACA,cACA,SAC2B;AAE3B,MACE,YAAY,QACZ,YAAY,UACZ,OAAO,YAAY,WACnB;AACA,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,UAAU,CAAC;AAAA,MACX,OAAO,CAAC;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAGA,MAAI,OAAO,YAAY,YAAY,OAAO,YAAY,UAAU;AAC9D,UAAM,OAAO,OAAO,OAAO;AAC3B,UAAMC,SAAQ,aAAa,QAAW,WAAW;AAGjD,UAAM,cAAc,IAAI,YAAY,MAAMA,QAAO,YAAY;AAC7D,mBAAe,UAAU,WAAW;AAEpC,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAAA;AAAA,MACA,UAAU,CAAC;AAAA,MACX,aAAa;AAAA,MACb;AAAA,MACA,OAAO,CAAC;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAGA,QAAM,KAAK;AACX,QAAM,OAAO,GAAG;AAEhB,QAAM,QAAS,GAAG,SAAS,CAAC;AAC5B,QAAM,WAAY,MAAM,SAAS,CAAC;AAClC,QAAM,WAAW,YAAY,UAAU,YAAY;AACnD,QAAM,QAAQ,aAAa,UAAU,WAAW;AAChD,eAAa,OAAO,eAAe,cAAc;AAEjD,QAAM,UAAU,OAAO,IAAI;AAG3B,MAAI,YAAY,OAAO;AACrB,QAAI,MAAM,SAAS,QAAQ,MAAM,UAAU,QAAW;AACpD,YAAM,IAAI,MAAM;AAChB,UAAI,OAAO,MAAM,UAAU;AACzB,cAAM,WAAW,YAAY,GAAG,eAAe,gBAAgB,IAAI,EAAE;AACrE,cAAM,QACJ,OAAO,aAAa,YAAY,SAAS,SAAS,GAAG,IACjD,WACA,OAAO,QAAQ;AAAA,MACvB,OAAO;AACL,cAAM,QAAQ,OAAO,CAAC;AAAA,MACxB;AAAA,IACF;AACA,QAAI,MAAM,UAAU,QAAQ,MAAM,WAAW,QAAW;AACtD,YAAM,IAAI,MAAM;AAChB,UAAI,OAAO,MAAM,UAAU;AACzB,cAAM,WAAW,YAAY,GAAG,eAAe,gBAAgB,IAAI,EAAE;AACrE,cAAM,SACJ,OAAO,aAAa,YAAY,SAAS,SAAS,GAAG,IACjD,WACA,OAAO,QAAQ;AAAA,MACvB,OAAO;AACL,cAAM,SAAS,OAAO,CAAC;AAAA,MACzB;AAAA,IACF;AAGA,UAAM,UAAU,MAAM;AACtB,QAAI,SAAS;AACX,YAAM,QAAQ,QAAQ,MAAM,QAAQ,EAAE,IAAI,MAAM;AAChD,UAAI,MAAM,WAAW,GAAG;AACtB,cAAM,CAAC,EAAE,EAAE,KAAK,GAAG,IAAI;AACvB,YAAI,MAAM,KAAK,MAAM,GAAG;AACtB,gBAAM,OAAO,MAAM,UAAU;AAC7B,gBAAM,OAAO,MAAM,WAAW;AAC9B,cAAI,CAAC,QAAQ,CAAC,MAAM;AAClB,kBAAM,QAAQ;AACd,kBAAM,SAAS;AAAA,UACjB,WAAW,CAAC,QAAQ,OAAO,MAAM,UAAU,UAAU;AACnD,kBAAM,SAAS,MAAM,SAAS,MAAM;AAAA,UACtC,WAAW,CAAC,QAAQ,OAAO,MAAM,WAAW,UAAU;AACpD,kBAAM,QAAQ,MAAM,UAAU,MAAM;AAAA,UACtC;AAAA,QAEF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,YAAY,OAAO;AAErB,QAAI,MAAM,SAAS,QAAQ,MAAM,UAAU,QAAW;AACpD,YAAM,IAAI,MAAM;AAChB,YAAM,QAAQ,OAAO,MAAM,YAAY,EAAE,SAAS,GAAG,IAAI,IAAI,OAAO,CAAC;AAAA,IACvE;AACA,QAAI,MAAM,UAAU,QAAQ,MAAM,WAAW,QAAW;AACtD,YAAM,IAAI,MAAM;AAChB,YAAM,SAAS,OAAO,MAAM,YAAY,EAAE,SAAS,GAAG,IAAI,IAAI,OAAO,CAAC;AAAA,IACxE;AAEA,UAAM,MAAM,MAAM;AAClB,QAAI,KAAK;AACP,UAAI;AACF,cAAM,QAAQ,MAAM;AAAA,UAClB,SAAS,cAAc,oBAAI,IAAI;AAAA,UAC/B;AAAA,UACA,SAAS;AAAA,QACX;AACA,cAAM,WAAW,MAAM;AACvB,cAAM,WAAW,MAAM;AAEvB,cAAM,OAAO,MAAM,UAAU;AAC7B,cAAM,OAAO,MAAM,WAAW;AAE9B,YAAI,WAAW,KAAK,WAAW,KAAK,EAAE,QAAQ,OAAO;AACnD,cAAI,CAAC,QAAQ,CAAC,MAAM;AAElB,kBAAM,QAAQ;AAAA,UAChB;AACA,mBAAS,eAAe,WAAW,QAAQ;AAAA,QAC7C;AAAA,MACF,SAAS,KAAK;AAKZ,YAAI,SAAS,OAAO;AAClB,gBAAM,KAAK,OAAO,SAAS,GAAG,IAAI,aAAa;AAC/C,kBAAQ;AAAA,YACN,qDAAqD,EAAE,MACrD,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CACjD;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,oBAAkB,UAAU,KAAK;AAIjC,MAAI,YAAY,OAAO;AACrB,UAAM,mBAAmB,eAAe,MAAM,QAAqB;AACnE,WAAO;AAAA,MACL,MAAM;AAAA,MACN;AAAA,MACA,UAAU,CAAC;AAAA,MACX,OAAO,EAAE,GAAG,OAAO,UAAU,iBAAiB;AAAA,MAC9C;AAAA,IACF;AAAA,EACF;AAIA,QAAM,QAAQ,gBAAgB,MAAM,QAAqB;AAOzD,QAAM,WAAW,MAAM,WAAW,KAAK,OAAO,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,IAAI;AACrE,MAAI,aAAa,QAAQ,CAAC,iBAAiB,OAAO,QAAQ,CAAC,GAAG;AAC5D,UAAM,cAAc,OAAO,QAAQ;AACnC,UAAM,aAAa,aAAa,QAAW,KAAK;AAChD,UAAM,gBAAgB,mBAAmB;AACzC,UAAM,cAAc,IAAI,YAAY,aAAa,YAAY,YAAY;AACzE,mBAAe,eAAe,WAAW;AACzC,UAAM,KAAK,MAAM;AACjB,QAAI,CAAC,MAAM,OAAO,cAAc;AAC9B,oBAAc,YAAY,CAAC;AAAA,IAC7B;AACA,kBAAc,cAAc,CAAC;AAC7B,aAAS,YAAY,eAAe,CAAC;AAKrC,QAAI,MAAM,eAAe,QAAW;AAClC,eAAS,cAAc,CAAC;AAAA,IAC1B;AAEA,WAAO;AAAA,MACL,MAAM;AAAA,MACN;AAAA,MACA,UAAU;AAAA,QACR;AAAA,UACE,MAAM;AAAA,UACN,OAAO;AAAA,UACP,UAAU,CAAC;AAAA,UACX;AAAA,UACA;AAAA,UACA,OAAO,CAAC;AAAA,UACR,UAAU;AAAA,QACZ;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAOA,QAAM,WAA+B,CAAC;AACtC,aAAW,YAAY,OAAO;AAC5B,QAAI,OAAO,aAAa,YAAY,iBAAiB,QAAQ,EAAG;AAChE,UAAM,gBAAgB,OAAO,QAAQ,IACjC,mBAAmB,IACnB,eAAe;AACnB,aAAS,YAAY,eAAe,SAAS,MAAM;AACnD,aAAS;AAAA,MACP,MAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAmBA,IAAM,qBAAqB;AAM3B,SAAS,WACP,MACA,UACA,OACM;AACN,QAAM,YAAgC,CAAC;AACvC,QAAM,UAAU,CAAC,SAA2B;AAE1C,QAAI,KAAK,MAAM,YAAY,OAAQ;AACnC,QAAI,KAAK,YAAa,WAAU,KAAK,IAAI;AACzC,SAAK,SAAS,QAAQ,OAAO;AAAA,EAC/B;AACA,UAAQ,IAAI;AAEZ,QAAM,SAAS,CAAC,MAAwB,QACtC,KAAK,YAAa,OAAO,KAAK,SAAS,iBAAiB,GAAG,GAAG;AAEhE,WAAS,OAAO,GAAG,OAAO,oBAAoB,QAAQ;AACpD,QAAIC,aAAY;AAChB,eAAW,QAAQ,WAAW;AAC5B,UAAI,OAAO,MAAM,IAAI,GAAG;AACtB,aAAK,SAAS,UAAU;AACxB,QAAAA,aAAY;AAAA,MACd;AAAA,IACF;AACA,QAAI,CAACA,WAAW;AAChB,aAAS;AAAA,EACX;AACA,MAAI,CAAC,UAAU,KAAK,CAAC,SAAS,OAAO,MAAM,KAAK,CAAC,EAAG;AAKpD,aAAW,QAAQ,WAAW;AAC5B,QAAI,KAAK,YAAa,MAAM,EAAG,MAAK,SAAS,UAAU;AAAA,EACzD;AACA,WAAS;AACT,QAAM,YAAY,UAAU,OAAO,CAAC,SAAS,OAAO,MAAM,KAAK,CAAC,EAAE;AAClE,MAAI,SAAS,YAAY,GAAG;AAC1B,YAAQ;AAAA,MACN,oBAAoB,SAAS,+EACgB,kBAAkB;AAAA,IACjE;AAAA,EACF;AACF;AAGA,SAAS,eAAe,UAAoB,aAAgC;AAC1E,WAAS;AAAA,IAAe,CAAC,OAAO,cAC9B,YAAY;AAAA,MACV,cAAc,YAAY,aAAa,OAAO,MAAM,KAAK,IACrD,WACA;AAAA,IACN;AAAA,EACF;AACF;AAEA,IAAM,SAAS,CAAC,SACd,OAAO,SAAS,YAAY,OAAO,SAAS;AAG9C,SAAS,iBAAiB,MAA4B;AACpD,SACE,SAAS,QACT,OAAO,SAAS,YAChB,UAAU,QACV,OAAO,KAAK,SAAS,YACrB;AACA,UAAM,KAAK;AACX,WAAQ,GAAG;AAAA,MACT,GAAG,SAAS,CAAC;AAAA,IACf;AAAA,EACF;AACA,SAAO;AACT;AAOA,SAAS,gBACP,MACA,QAAqB,CAAC,GACT;AACb,QAAM,WAAW,iBAAiB,IAAI;AACtC,MACE,aAAa,QACb,aAAa,UACb,OAAO,aAAa,WACpB;AACA,WAAO;AAAA,EACT;AACA,MAAI,MAAM,QAAQ,QAAQ,GAAG;AAC3B,eAAW,SAAS,SAAyB,iBAAgB,OAAO,KAAK;AACzE,WAAO;AAAA,EACT;AACA,QAAM,KAAK;AACX,MAAI,OAAO,aAAa,YAAa,GAAG,SAAqB,gBAAgB;AAC3E,WAAO,gBAAgB,GAAG,OAAO,UAAU,KAAK;AAAA,EAClD;AACA,QAAM,OAAO,MAAM,MAAM,SAAS,CAAC;AACnC,MAAI,OAAO,QAAQ,KAAK,MAAM,SAAS,KAAK,OAAO,IAAI,GAAG;AACxD,UAAM,MAAM,SAAS,CAAC,IAAI,GAAG,IAAI,GAAG,QAAQ;AAAA,EAC9C,OAAO;AACL,UAAM,KAAK,QAAQ;AAAA,EACrB;AACA,SAAO;AACT;AAGA,SAAS,aAAa,OAAuB;AAC3C,QAAM,UAAU,KAAK,MAAM,KAAK;AAChC,SAAO,KAAK,IAAI,QAAQ,OAAO,IAAI,OAAO,UAAU,KAAK,MAAM,KAAK;AACtE;AAEA,SAAS,cAAc,MAAwB,UAAgC;AAC7E,QAAM,SAAS,SAAS,kBAAkB;AAG1C,QAAM,QAAQ,KAAK,cAAc,eAAe,CAAC,MAAc;AAE/D,SAAO;AAAA,IACL,MAAM,KAAK;AAAA,IACX,OAAO,KAAK;AAAA,IACZ,UAAU,KAAK,SAAS,IAAI,CAAC,OAAO,MAAM;AACxC,YAAM,YAAY,SAAS,SAAS,CAAC;AACrC,aAAO,cAAc,OAAO,SAAS;AAAA,IACvC,CAAC;AAAA,IACD,aAAa,KAAK;AAAA,IAClB,YAAY,KAAK,aAAa;AAAA,IAC9B,OAAO,KAAK;AAAA,IACZ,GAAG,MAAM,OAAO,IAAI;AAAA,IACpB,GAAG,MAAM,OAAO,GAAG;AAAA,IACnB,OAAO,OAAO;AAAA,IACd,QAAQ,OAAO;AAAA,EACjB;AACF;AAMA,IAAM,iBAAiB,uBAAO,IAAI,gBAAgB;AASlD,SAAS,eAAe,MAA4B;AAClD,MAAI,SAAS,QAAQ,SAAS,UAAa,OAAO,SAAS;AACzD,WAAO;AACT,MAAI,OAAO,SAAS,YAAY,OAAO,SAAS,SAAU,QAAO;AAEjE,MAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,UAAM,MAAmB,CAAC;AAC1B,QAAI,UAAU;AACd,eAAW,SAAS,MAAqB;AACvC,YAAM,WAAW,eAAe,KAAK;AACrC,UAAI,aAAa,QAAQ,aAAa,QAAW;AAC/C,kBAAU;AACV;AAAA,MACF;AACA,UAAI,MAAM,QAAQ,QAAQ,GAAG;AAC3B,kBAAU;AACV,mBAAW,KAAK,SAAU,KAAI,KAAK,CAAC;AAAA,MACtC,OAAO;AACL,YAAI,aAAa,MAAO,WAAU;AAClC,YAAI,KAAK,QAAQ;AAAA,MACnB;AAAA,IACF;AACA,WAAO,UAAU,MAAM;AAAA,EACzB;AAEA,QAAM,KAAK;AACX,MAAI,OAAO,GAAG,SAAS,YAAY;AACjC,UAAM,WAAY,GAAG;AAAA,MACnB,GAAG,SAAS,CAAC;AAAA,IACf;AACA,WAAO,eAAe,QAAQ;AAAA,EAChC;AAIA,MAAK,GAAG,SAAqB,gBAAgB;AAC3C,WAAO,gBAAgB,GAAG,SAAS,CAAC,GAAG,QAAqB;AAAA,EAC9D;AAEA,QAAM,UAAW,GAAG,SAAS,CAAC;AAC9B,MAAI,QAAQ,aAAa,QAAW;AAClC,UAAM,mBAAmB,eAAe,QAAQ,QAAqB;AACrE,QAAI,qBAAqB,QAAQ,UAAU;AACzC,aAAO,EAAE,GAAG,IAAI,OAAO,EAAE,GAAG,SAAS,UAAU,iBAAiB,EAAE;AAAA,IACpE;AAAA,EACF;AACA,SAAO;AACT;;;AC/hBA,eAAsB,mBACpB,KACA,SACA,UAAqC,CAAC,GACvB;AACf,QAAM,QAAQ,QAAQ,SAAS,CAAC;AAGhC,wBAAsB,KAAK;AAG3B,QAAM,QAAQ,QAAQ,SAAS,IAAI,OAAO;AAC1C,QAAM,SAAS,QAAQ,UAAU,IAAI,OAAO;AAK5C,QAAM,gBAA+B;AAAA,IACnC,YAAY,QAAQ,cAAc,oBAAI,IAAI;AAAA,IAC1C,WAAW,QAAQ;AAAA,IACnB,OAAO,QAAQ,SAAS;AAAA,EAC1B;AAGA,QAAM,aACJ,QAAQ,UAAU,SAAS,SAAa,QAAQ,SAAS;AAC3D,QAAM,eAAe,CAAC,GAAG,IAAI,IAAI,MAAM,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAC1D,QAAM,EAAE,MAAM,WAAW,IAAI,MAAM;AAAA,IACjC;AAAA,IACA;AAAA,IACA;AAAA,IACA,CAAC,CAAC;AAAA,IACF;AAAA,IACA;AAAA,EACF;AAGA,QAAM,SAAS,KAAK,YAAY,GAAG,GAAG,eAAe,UAAU;AAI/D,QAAM,kBAAkB;AAC1B;;;AC7DO,SAAS,0BACd,SACQ;AACR,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa;AAAA,IACb;AAAA,IACA,cAAc;AAAA,IACd,cAAc;AAAA,EAChB,IAAI;AAEJ,eAAa,IAAI;AAEjB,MAAI,KAAK;AACT,MAAI,KAAK;AACT,MAAI,OAAO;AAEX,SAAO,MAAM,IAAI;AACf,UAAM,MAAM,KAAK,OAAO,KAAK,MAAM,CAAC;AACpC,UAAM,QAAuB;AAAA,MAC3B,UAAU;AAAA,MACV,YAAY,KAAK;AAAA,MACjB,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,MAChB,YAAY,eAAe,WAAW,SAAY;AAAA,MAClD;AAAA,IACF;AAEA,UAAM,SAAS,WAAW,MAAM,OAAO,QAAQ;AAE/C,QAAI,OAAO,SAAS,YAAY,OAAO,UAAU,WAAW;AAC1D,aAAO;AACP,WAAK,MAAM;AAAA,IACb,OAAO;AACL,WAAK,MAAM;AAAA,IACb;AAAA,EACF;AAEA,SAAO;AACT;;;AtC/CO,SAASC,cAAa,OAAe,QAAgB;AAC1D,SAAO,cAAc,OAAO,MAAM;AACpC;","names":["GlobalFonts","Path2D","resolveRadius","x","y","Path2D","Path2D","createCanvas","canvas","Path2D","Path2D","Path2D","Path2D","loadImage","parseCssColor","EMOJI_CHAR","loadImage","parseCssColor","style","unsettled","createCanvas"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/image.ts","../src/lottie.ts","../src/jsx/draw/utils.ts","../src/jsx/style/compute.ts","../src/jsx/text/native.ts","../src/jsx/language.ts","../src/jsx/text/measure.ts","../src/jsx/text/white-space.ts","../src/jsx/text/index.ts","../src/jsx/draw/clip.ts","../src/jsx/draw/clip-path.ts","../src/jsx/draw/rect.ts","../src/jsx/draw/gradient.ts","../src/jsx/draw/group.ts","../src/jsx/draw/object-fit.ts","../src/jsx/draw/image.ts","../src/jsx/draw/shadow.ts","../src/jsx/draw/svg/style.ts","../src/jsx/draw/svg/tree.ts","../src/jsx/draw/svg/defs.ts","../src/jsx/draw/svg/transform.ts","../src/jsx/draw/svg/path.ts","../src/jsx/draw/offscreen.ts","../src/jsx/draw/svg/filters.ts","../src/jsx/draw/svg/shapes.ts","../src/jsx/draw/svg/gradients.ts","../src/jsx/draw/svg/paint.ts","../src/jsx/draw/svg/traverse.ts","../src/jsx/draw/svg/index.ts","../src/jsx/draw/text.ts","../src/jsx/emoji.ts","../src/jsx/draw/index.ts","../src/jsx/font.ts","../src/jsx/style/expand.ts","../src/jsx/yoga.ts","../src/jsx/style/properties.ts","../src/jsx/layout.ts","../src/jsx/index.ts","../src/fit-text.ts"],"sourcesContent":["// Re-export canvas primitives from @effing/skia so consumers never need a\n// direct dependency on it (it's a dependency of this package, which pnpm does\n// not expose to the consuming project). Re-exporting also guarantees a single\n// native copy:\n// a Path2D from one copy of @effing/skia cannot be used with a context from\n// another.\nimport { createCanvas as _createCanvas } from \"@effing/skia\";\nexport {\n Canvas,\n type SKRSContext2D,\n GlobalFonts,\n Image,\n ImageData,\n Path2D,\n DOMMatrix,\n DOMPoint,\n DOMRect,\n PathOp,\n FillType,\n StrokeJoin,\n StrokeCap,\n} from \"@effing/skia\";\n\n// loadImage is wrapped (not re-exported) so remote URLs go through the same\n// fetch path as <img> sources — see ./image.ts.\nexport {\n loadImage,\n type ImageCache,\n type LoadImageOptions,\n type LoadImageSource,\n} from \"./image.ts\";\n\n// encode() needs no patching: it snapshots the canvas when called, so later\n// drawing can't reach a pending encode, and the Buffer it resolves with owns\n// its native memory until the Buffer itself is collected (see\n// ./encode.test.ts). This used to copy the result to the JS heap, to guard\n// against lifetime bugs in @napi-rs/canvas's async encode that were fixed\n// upstream (napi-rs/canvas#1314, #1323) before @effing/skia was forked.\nexport function createCanvas(width: number, height: number) {\n return _createCanvas(width, height);\n}\n\n// Lottie API\nexport { LottieAnimation, loadLottie, renderLottieFrame } from \"./lottie.ts\";\n\n// JSX API\nexport { renderReactElement } from \"./jsx/index.ts\";\n\n// Font management\nexport {\n registerFont,\n registerFontFromPath,\n registeredFamilies,\n} from \"./jsx/font.ts\";\n\n// Fit text\nexport {\n findLargestUsableFontSize,\n type FindLargestUsableFontSizeOptions,\n} from \"./fit-text.ts\";\n\n// Types\nexport type {\n FontData,\n RenderReactElementOptions,\n EmojiStyle,\n} from \"./types.ts\";\n","import type { Image } from \"@effing/skia\";\nimport { loadImage as nativeLoadImage } from \"@effing/skia\";\n\n/** Source types accepted by {@link loadImage}, mirroring @effing/skia. */\nexport type LoadImageSource = Parameters<typeof nativeLoadImage>[0];\n\n/** Options for {@link loadImage}. */\nexport interface LoadImageOptions {\n /**\n * User-Agent header sent on remote (http/https) fetches. Matches the\n * `userAgent` option of `renderReactElement`, so `loadImage(url)` and an\n * `<img src={url}>` behave identically. An empty string is sent as an\n * explicit empty header; values with CR/LF cause fetch to throw `TypeError`.\n * Ignored for non-remote sources (paths, Buffers, data URIs).\n */\n userAgent?: string;\n}\n\n/**\n * Load an image from a path, Buffer, data URI, or remote URL.\n *\n * Remote http/https URLs are fetched via global fetch() and passed to the\n * native loader as bytes — the same path `<img>` sources take in\n * `renderReactElement`. This keeps `loadImage(url)` and `<img src={url}>`\n * consistent: both honor a global dispatcher / proxy (undici's\n * setGlobalDispatcher) and the `userAgent` option. @effing/skia's own URL\n * loader uses Node's raw http modules, which bypass any dispatcher, so it is\n * only used for non-remote sources here.\n *\n * Note: @effing/skia's `maxRedirects` / `requestOptions` load options are\n * intentionally not exposed — they only configure its built-in URL loader,\n * which this wrapper bypasses. Control remote fetches via fetch/undici instead.\n */\nexport function loadImage(\n source: LoadImageSource,\n options?: LoadImageOptions,\n): Promise<Image> {\n const remoteUrl =\n typeof source === \"string\" && isRemoteUrl(source)\n ? source\n : source instanceof URL && isRemoteUrl(source.href)\n ? source.href\n : undefined;\n if (remoteUrl !== undefined) {\n return loadRemoteImage(remoteUrl, options?.userAgent);\n }\n return nativeLoadImage(source);\n}\n\n/**\n * Per-render cache of image load promises, keyed by source string.\n * Shared between layout and draw phases to avoid duplicate loads.\n */\nexport type ImageCache = Map<string, Promise<Image>>;\n\n/**\n * Load an image via {@link loadImage}, deduplicating by source string through\n * the cache. Buffer sources are never cached (no stable key). `userAgent`, when\n * set, is forwarded to remote (http/https) fetches. The cache key is the URL\n * alone — the userAgent of the first call for a given URL is the one that hits\n * the wire; a later call with a different userAgent reuses the cached promise.\n *\n * Failed loads are evicted, so only successful loads stay cached: callers\n * sharing one cache across many renders (`options.imageCache`) retry a\n * transiently-failed source on the next call instead of replaying the\n * rejection forever.\n */\nexport function cachedLoadImage(\n cache: ImageCache,\n src: string | Buffer,\n userAgent?: string,\n): Promise<Image> {\n if (Buffer.isBuffer(src)) return loadImage(src);\n let entry = cache.get(src);\n if (!entry) {\n const created = loadImage(\n src,\n userAgent === undefined ? undefined : { userAgent },\n );\n created.catch(() => {\n if (cache.get(src) === created) cache.delete(src);\n });\n cache.set(src, created);\n entry = created;\n }\n return entry;\n}\n\n/**\n * True for http/https URLs, which are loaded via fetch() rather than the\n * native loader. Scheme match is case-insensitive (RFC 3986 §3.1).\n */\nexport function isRemoteUrl(src: string): boolean {\n return /^https?:\\/\\//i.test(src);\n}\n\n/**\n * Fetch a remote image via global fetch() and decode the bytes with the native\n * loader. Routing through fetch (rather than @effing/skia's raw-http URL\n * loader) lets a global dispatcher / proxy and the `userAgent` apply.\n */\nexport async function loadRemoteImage(\n url: string,\n userAgent?: string,\n): Promise<Image> {\n const init: RequestInit | undefined =\n userAgent !== undefined\n ? { headers: { \"User-Agent\": userAgent } }\n : undefined;\n const response = await fetch(url, init);\n if (!response.ok) {\n throw new Error(\n `Failed to fetch image ${url}: ${response.status} ${response.statusText}`,\n );\n }\n const buffer = Buffer.from(await response.arrayBuffer());\n return nativeLoadImage(buffer);\n}\n","import { LottieAnimation } from \"@effing/skia\";\nimport type { SKRSContext2D } from \"@effing/skia\";\n\nexport { LottieAnimation };\n\n/**\n * Load a Lottie animation from a JSON string or Buffer.\n *\n * @param data - Lottie JSON string or Buffer\n * @param options - Optional resource path for external assets\n * @returns A `LottieAnimation` handle ready for rendering\n *\n * @example\n * ```ts\n * const anim = loadLottie(fs.readFileSync(\"animation.json\", \"utf-8\"));\n * ```\n */\nexport function loadLottie(\n data: string | Buffer,\n options?: { resourcePath?: string },\n): LottieAnimation {\n const jsonString = typeof data === \"string\" ? data : data.toString(\"utf-8\");\n return LottieAnimation.loadFromData(jsonString, {\n resourcePath: options?.resourcePath,\n });\n}\n\n/**\n * Render a specific frame of a Lottie animation to a canvas context.\n *\n * Seeks the animation to the given frame, then renders it onto the\n * provided context. The canvas dimensions determine the render size.\n *\n * @param ctx - Canvas 2D rendering context to draw into\n * @param animation - Lottie animation handle (from {@link loadLottie})\n * @param frame - Zero-based frame number to render\n *\n * @example\n * ```ts\n * import { createCanvas, loadLottie, renderLottieFrame } from \"@effing/canvas\";\n *\n * const canvas = createCanvas(1080, 1080);\n * const ctx = canvas.getContext(\"2d\");\n * const anim = loadLottie(jsonString);\n *\n * renderLottieFrame(ctx, anim, 0);\n * const png = canvas.encodeSync(\"png\");\n * ```\n */\nexport function renderLottieFrame(\n ctx: SKRSContext2D,\n animation: LottieAnimation,\n frame: number,\n): void {\n animation.seekFrame(frame);\n animation.render(ctx);\n}\n","/**\n * Shared CSS utility functions used by the draw system.\n */\n\nexport function parseCSSLength(value: string, referenceSize: number): number {\n if (value.endsWith(\"%\")) return (parseFloat(value) / 100) * referenceSize;\n return parseFloat(value);\n}\n\nexport function toNumber(v: unknown): number {\n if (typeof v === \"number\") return v;\n if (v === undefined || v === null) return 0;\n const n = parseFloat(String(v));\n return isNaN(n) ? 0 : n;\n}\n\n/**\n * Resolve a box-model value (padding, border-width) that may be a percentage.\n * Per CSS spec, percentage padding/border resolves against the element's width\n * (even for top/bottom).\n */\nexport function resolveBoxValue(v: unknown, referenceWidth: number): number {\n if (typeof v === \"number\") return v;\n if (v === undefined || v === null) return 0;\n const s = String(v);\n if (s.endsWith(\"%\")) return (parseFloat(s) / 100) * referenceWidth;\n const n = parseFloat(s);\n return isNaN(n) ? 0 : n;\n}\n\n/**\n * Format a number for embedding in a CSS string. `String(n)` switches to\n * exponent notation for very small or large magnitudes (`1e-7`), which CSS\n * parsers reject, so round to six decimals and print positionally.\n */\nexport function formatCSSNumber(n: number): string {\n const fixed = n.toFixed(6).replace(/\\.?0+$/, \"\");\n return fixed === \"-0\" || fixed === \"\" ? \"0\" : fixed;\n}\n","// This file contains code adapted from Satori (https://github.com/vercel/satori)\n// Licensed under the Mozilla Public License 2.0 (MPL-2.0)\n// See NOTICE.md in the package root for details.\n\nimport { formatCSSNumber } from \"../draw/utils.ts\";\n\n/**\n * Style after shorthand expansion but before unit resolution.\n * Properties like fontSize may still contain CSS unit strings (e.g. \"4em\").\n */\nexport type ExpandedStyle = Omit<ComputedStyle, \"fontSize\"> & {\n fontSize?: number | string;\n};\n\n/**\n * Normalized, computed CSS style after shorthand expansion.\n * All dimension values are numbers (pixels) or percentage strings.\n */\nexport type ComputedStyle = {\n // Display & layout\n display?: \"flex\" | \"none\";\n flexDirection?: \"row\" | \"column\" | \"row-reverse\" | \"column-reverse\";\n justifyContent?:\n | \"flex-start\"\n | \"flex-end\"\n | \"center\"\n | \"space-between\"\n | \"space-around\"\n | \"space-evenly\";\n alignItems?: \"flex-start\" | \"flex-end\" | \"center\" | \"stretch\" | \"baseline\";\n alignSelf?:\n \"auto\" | \"flex-start\" | \"flex-end\" | \"center\" | \"stretch\" | \"baseline\";\n alignContent?:\n | \"flex-start\"\n | \"flex-end\"\n | \"center\"\n | \"stretch\"\n | \"space-between\"\n | \"space-around\";\n flexWrap?: \"nowrap\" | \"wrap\" | \"wrap-reverse\";\n flexGrow?: number;\n flexShrink?: number;\n flexBasis?: number | string;\n\n // Dimensions\n width?: number | string;\n height?: number | string;\n minWidth?: number | string;\n minHeight?: number | string;\n maxWidth?: number | string;\n maxHeight?: number | string;\n\n // Position\n position?: \"relative\" | \"absolute\";\n top?: number | string;\n right?: number | string;\n bottom?: number | string;\n left?: number | string;\n\n // Margin\n marginTop?: number | string;\n marginRight?: number | string;\n marginBottom?: number | string;\n marginLeft?: number | string;\n\n // Padding\n paddingTop?: number | string;\n paddingRight?: number | string;\n paddingBottom?: number | string;\n paddingLeft?: number | string;\n\n // Border\n borderTopWidth?: number | string;\n borderRightWidth?: number | string;\n borderBottomWidth?: number | string;\n borderLeftWidth?: number | string;\n borderTopColor?: string;\n borderRightColor?: string;\n borderBottomColor?: string;\n borderLeftColor?: string;\n borderTopStyle?: string;\n borderRightStyle?: string;\n borderBottomStyle?: string;\n borderLeftStyle?: string;\n borderTopLeftRadius?: number | string;\n borderTopRightRadius?: number | string;\n borderBottomRightRadius?: number | string;\n borderBottomLeftRadius?: number | string;\n\n // Gap\n rowGap?: number;\n columnGap?: number;\n\n // Overflow\n overflow?: string;\n overflowX?: string;\n overflowY?: string;\n\n // Colors & background\n backgroundColor?: string;\n color?: string;\n opacity?: number;\n backgroundImage?: string;\n backgroundSize?: string;\n backgroundRepeat?:\n \"repeat\" | \"no-repeat\" | \"repeat-x\" | \"repeat-y\" | \"space\" | \"round\";\n\n // Typography\n fontSize?: number;\n fontFamily?: string;\n fontWeight?: number | string;\n fontStyle?: \"normal\" | \"italic\";\n textAlign?: \"left\" | \"center\" | \"right\" | \"justify\";\n textDecoration?: string;\n textTransform?: \"none\" | \"uppercase\" | \"lowercase\" | \"capitalize\";\n lineHeight?: number | string;\n letterSpacing?: number | string;\n whiteSpace?: \"normal\" | \"nowrap\" | \"pre\" | \"pre-wrap\" | \"pre-line\";\n wordBreak?: \"normal\" | \"break-all\" | \"break-word\" | \"keep-all\";\n overflowWrap?: \"normal\" | \"break-word\" | \"anywhere\";\n textOverflow?: \"clip\" | \"ellipsis\";\n lineClamp?: number;\n\n // Box shadow\n boxShadow?: string;\n textShadow?: string;\n\n // Transform\n transform?: string;\n transformOrigin?: string;\n\n // Image\n objectFit?: \"contain\" | \"cover\" | \"fill\" | \"none\" | \"scale-down\";\n\n // Filter\n filter?: string;\n backdropFilter?: string;\n\n // Clipping\n clipPath?: string;\n\n // Text box trim\n textBoxTrim?: \"none\" | \"trim-start\" | \"trim-end\" | \"trim-both\";\n textBoxEdge?: string;\n\n // Text stroke\n WebkitTextStrokeWidth?: number | string;\n WebkitTextStrokeColor?: string;\n};\n\nconst ROOT_FONT_SIZE = 16;\n\n/**\n * Default font family. Uses concrete system font names so @effing/skia\n * resolves real font metrics instead of generic ratios for unnamed families.\n */\nexport const DEFAULT_FONT_FAMILY = \"Helvetica, Arial, sans-serif\";\n\n/**\n * Default styles for the root element.\n */\nexport const DEFAULT_STYLE: ComputedStyle = {\n display: \"flex\",\n flexDirection: \"row\",\n flexWrap: \"nowrap\",\n flexGrow: 0,\n flexShrink: 0,\n alignItems: \"stretch\",\n justifyContent: \"flex-start\",\n position: \"relative\",\n fontSize: ROOT_FONT_SIZE,\n fontWeight: 400,\n fontStyle: \"normal\",\n fontFamily: DEFAULT_FONT_FAMILY,\n color: \"black\",\n lineHeight: \"normal\",\n textAlign: \"left\",\n whiteSpace: \"normal\",\n wordBreak: \"normal\",\n textOverflow: \"clip\",\n opacity: 1,\n overflow: \"visible\",\n};\n\n/**\n * CSS properties that are inherited by child elements.\n */\nconst INHERITABLE_PROPS: (keyof ComputedStyle)[] = [\n \"color\",\n \"fontSize\",\n \"fontFamily\",\n \"fontWeight\",\n \"fontStyle\",\n \"textAlign\",\n \"textTransform\",\n \"textDecoration\",\n \"lineHeight\",\n \"letterSpacing\",\n \"whiteSpace\",\n \"wordBreak\",\n \"overflowWrap\",\n \"textOverflow\",\n \"lineClamp\",\n \"textBoxTrim\",\n \"textBoxEdge\",\n \"textShadow\",\n \"WebkitTextStrokeWidth\",\n \"WebkitTextStrokeColor\",\n];\n\n/** A CSS `<number>`: no trailing dot (`550.`), as `ctx.font` reads it. */\nconst CSS_NUMBER = /^[+-]?(\\d+(\\.\\d+)?|\\.\\d+)([eE][+-]?\\d+)?$/;\n\n/** The font-weight keywords CSS accepts, left to `ctx.font` to read. */\nconst FONT_WEIGHT_KEYWORDS = new Set([\"normal\", \"bold\", \"bolder\", \"lighter\"]);\n\n/** Whether `weight` is a font-weight CSS accepts: a keyword, or 1 to 1000. */\nfunction isValidFontWeight(weight: number | string): boolean {\n if (typeof weight === \"string\") {\n const text = weight.trim();\n if (FONT_WEIGHT_KEYWORDS.has(text.toLowerCase())) return true;\n if (!CSS_NUMBER.test(text)) return false;\n weight = Number(text);\n }\n return Number.isFinite(weight) && weight >= 1 && weight <= 1000;\n}\n\n/**\n * Resolve the computed style for a node, inheriting from parent where appropriate.\n */\nexport function resolveStyle(\n rawStyle: ExpandedStyle | undefined,\n parentStyle: ComputedStyle,\n): ComputedStyle {\n const style = { ...rawStyle };\n\n // A font-weight outside 1–1000 is invalid, and ignored as in CSS: the\n // element inherits its parent's (`ctx.font` throws on one).\n if (style.fontWeight !== undefined && !isValidFontWeight(style.fontWeight)) {\n delete style.fontWeight;\n }\n\n // Apply inherited properties\n for (const prop of INHERITABLE_PROPS) {\n if (style[prop] === undefined && parentStyle[prop] !== undefined) {\n (style as Record<string, unknown>)[prop] = parentStyle[prop];\n }\n }\n\n // Resolve fontSize (ensure it's a number, respecting em/rem/etc units)\n if (typeof style.fontSize === \"string\") {\n const parentFontSize =\n typeof parentStyle.fontSize === \"number\"\n ? parentStyle.fontSize\n : ROOT_FONT_SIZE;\n const resolved = resolveUnit(\n style.fontSize,\n 0,\n 0,\n parentFontSize,\n ROOT_FONT_SIZE,\n );\n style.fontSize = typeof resolved === \"number\" ? resolved : parentFontSize;\n }\n\n // Resolve lineHeight: parse string values to numbers but keep multipliers\n // as-is so they're recalculated per-element in text layout (using each\n // element's own fontSize rather than the parent's).\n if (typeof style.lineHeight === \"string\") {\n const str = style.lineHeight;\n if (str.endsWith(\"%\")) {\n style.lineHeight = parseFloat(str) / 100;\n } else {\n const parsed = parseFloat(str);\n if (!isNaN(parsed)) {\n style.lineHeight = parsed;\n }\n }\n }\n\n // Resolve letterSpacing (respecting em/rem/etc units)\n if (typeof style.letterSpacing === \"string\") {\n const currentFontSize =\n typeof style.fontSize === \"number\"\n ? style.fontSize\n : typeof parentStyle.fontSize === \"number\"\n ? parentStyle.fontSize\n : ROOT_FONT_SIZE;\n const resolved = resolveUnit(\n style.letterSpacing,\n 0,\n 0,\n currentFontSize,\n ROOT_FONT_SIZE,\n );\n if (typeof resolved === \"number\") {\n style.letterSpacing = resolved;\n }\n }\n\n return style as ComputedStyle;\n}\n\n/**\n * Dimension properties that may contain CSS units needing resolution.\n */\nconst DIMENSION_PROPS: (keyof ComputedStyle)[] = [\n \"width\",\n \"height\",\n \"minWidth\",\n \"minHeight\",\n \"maxWidth\",\n \"maxHeight\",\n \"top\",\n \"right\",\n \"bottom\",\n \"left\",\n \"marginTop\",\n \"marginRight\",\n \"marginBottom\",\n \"marginLeft\",\n \"paddingTop\",\n \"paddingRight\",\n \"paddingBottom\",\n \"paddingLeft\",\n \"rowGap\",\n \"columnGap\",\n \"flexBasis\",\n \"borderTopWidth\",\n \"borderRightWidth\",\n \"borderBottomWidth\",\n \"borderLeftWidth\",\n \"borderTopLeftRadius\",\n \"borderTopRightRadius\",\n \"borderBottomRightRadius\",\n \"borderBottomLeftRadius\",\n \"WebkitTextStrokeWidth\",\n];\n\n/**\n * Resolve a single CSS dimension string to a pixel number.\n * Returns the original value for `%` and `auto` (Yoga handles those),\n * and for values that are already numbers or unrecognised strings.\n */\nexport function resolveUnit(\n value: string,\n viewportWidth: number,\n viewportHeight: number,\n fontSize: number,\n rootFontSize: number,\n): number | string {\n // Percentages and auto are handled downstream by Yoga\n if (value.endsWith(\"%\") || value === \"auto\") return value;\n\n // Viewport-relative units\n if (value.endsWith(\"vmin\")) {\n const n = parseFloat(value);\n return isNaN(n)\n ? value\n : (n / 100) * Math.min(viewportWidth, viewportHeight);\n }\n if (value.endsWith(\"vmax\")) {\n const n = parseFloat(value);\n return isNaN(n)\n ? value\n : (n / 100) * Math.max(viewportWidth, viewportHeight);\n }\n if (value.endsWith(\"vw\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : (n / 100) * viewportWidth;\n }\n if (value.endsWith(\"vh\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : (n / 100) * viewportHeight;\n }\n\n // Font-relative units\n if (value.endsWith(\"rem\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * rootFontSize;\n }\n if (value.endsWith(\"em\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * fontSize;\n }\n\n // Absolute units (CSS reference pixel = 1/96 inch)\n if (value.endsWith(\"px\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n;\n }\n if (value.endsWith(\"pt\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * (96 / 72);\n }\n if (value.endsWith(\"pc\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * 16;\n }\n if (value.endsWith(\"in\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * 96;\n }\n if (value.endsWith(\"cm\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * (96 / 2.54);\n }\n if (value.endsWith(\"mm\")) {\n const n = parseFloat(value);\n return isNaN(n) ? value : n * (96 / 25.4);\n }\n\n return value;\n}\n\n/**\n * Resolve CSS units (vw, vh, vmin, vmax, em, rem, px, pt, pc, in, cm, mm)\n * in a style object to pixel values. Percentages and `auto` pass through\n * unchanged for Yoga to handle.\n */\nexport function resolveUnits(\n style: ComputedStyle,\n viewportWidth: number,\n viewportHeight: number,\n rootFontSize: number = ROOT_FONT_SIZE,\n): ComputedStyle {\n const fontSize =\n typeof style.fontSize === \"number\" ? style.fontSize : rootFontSize;\n\n for (const prop of DIMENSION_PROPS) {\n const value = style[prop];\n if (typeof value !== \"string\") continue;\n const resolved = resolveUnit(\n value,\n viewportWidth,\n viewportHeight,\n fontSize,\n rootFontSize,\n );\n if (resolved !== value) {\n (style as Record<string, unknown>)[prop] = resolved;\n }\n }\n\n // Resolve CSS length units inside transform, clip-path, filter and shadow\n // strings so that by draw time values are either bare numbers or `%` (which\n // need element dimensions).\n for (const [prop, suffix] of LENGTH_STRING_PROPS) {\n const value = style[prop];\n if (typeof value !== \"string\") continue;\n (style as Record<string, unknown>)[prop] = resolveLengthUnits(\n value,\n viewportWidth,\n viewportHeight,\n fontSize,\n rootFontSize,\n suffix,\n );\n }\n\n return style;\n}\n\n/**\n * String-valued properties whose embedded CSS lengths are resolved to pixels,\n * with the suffix the resolved numbers are written with. The transform parser\n * takes bare numbers; clip-path, filter and shadow strings keep an explicit `px` so\n * they stay valid CSS for the parsers downstream (Skia's filter parser\n * rejects a unitless `blur(6)`).\n */\nconst LENGTH_STRING_PROPS: [keyof ComputedStyle, string][] = [\n [\"transform\", \"\"],\n [\"transformOrigin\", \"\"],\n [\"clipPath\", \"px\"],\n [\"filter\", \"px\"],\n [\"backdropFilter\", \"px\"],\n [\"boxShadow\", \"px\"],\n [\"textShadow\", \"px\"],\n];\n\n/**\n * Resolve CSS length units (vw, vh, em, rem, px, etc.) inside a string value\n * such as a transform, clip-path or filter. Percentages and angle units (deg,\n * rad, turn) are left untouched — percentages need element dimensions\n * (available at draw time) and angle units are not lengths.\n */\nfunction resolveLengthUnits(\n transform: string,\n viewportWidth: number,\n viewportHeight: number,\n fontSize: number,\n rootFontSize: number,\n suffix = \"\",\n): string {\n return transform.replace(\n // The lookbehind keeps a number from being matched mid-token (`1e1em`).\n /(?<![\\w.])(-?\\d*\\.?\\d+)(vw|vh|vmin|vmax|em|rem|px|pt|pc|in|cm|mm)\\b/g,\n (match) => {\n const resolved = resolveUnit(\n match,\n viewportWidth,\n viewportHeight,\n fontSize,\n rootFontSize,\n );\n return typeof resolved === \"number\"\n ? `${formatCSSNumber(resolved)}${suffix}`\n : match;\n },\n );\n}\n\n/**\n * Resolve a dimension value (width, height, margin, etc.) to pixels.\n * Percentage values are resolved relative to the provided container size.\n */\nexport function resolveDimension(\n value: number | string | undefined,\n containerSize: number,\n): number | undefined {\n if (value === undefined || value === \"auto\") return undefined;\n if (typeof value === \"number\") return value;\n const s = String(value);\n if (s.endsWith(\"%\")) {\n return (parseFloat(s) / 100) * containerSize;\n }\n const n = parseFloat(s);\n return isNaN(n) ? undefined : n;\n}\n","// Native paragraph layout through @effing/skia's `Paragraph`: Skia breaks,\n// shapes and paints the text in one place, instead of this package measuring\n// it word by word across the native boundary. The paragraph follows the CSS\n// line model (every line box exactly `lineHeight` tall, baseline placed by\n// half-leading from the font's hhea metrics) and paints unhinted, unsnapped\n// glyphs.\n\nimport { Paragraph } from \"@effing/skia/extensions\";\nimport type {\n ParagraphLine,\n ParagraphPlaceholder,\n ParagraphStyle,\n} from \"@effing/skia/extensions\";\n\nimport type { ComputedStyle } from \"../style/compute.ts\";\nimport { DEFAULT_FONT_FAMILY } from \"../style/compute.ts\";\nimport { isEmoji } from \"../language.ts\";\nimport { measureTrimMetrics, quoteFontFamilies } from \"./measure.ts\";\nimport type { PlacedEmoji, TextLayoutResult, TextSegment } from \"./index.ts\";\n\nexport type NativeParagraph = Paragraph;\n\nfunction toWeight(weight: number | string | undefined): number {\n if (typeof weight === \"number\") return weight;\n // A number as `ctx.font` reads it, so \"1e3\" is 1000 here too.\n const text = String(weight ?? \"400\")\n .trim()\n .toLowerCase();\n if (text === \"bold\") return 700;\n const parsed = text === \"\" ? NaN : Number(text);\n return Number.isFinite(parsed) ? parsed : 400;\n}\n\nfunction toFontStyle(\n fontStyle: string | undefined,\n): ParagraphStyle[\"fontStyle\"] {\n if (fontStyle?.startsWith(\"italic\")) return \"italic\";\n if (fontStyle?.startsWith(\"oblique\")) return \"oblique\";\n return \"normal\";\n}\n\nconst TEXT_ALIGNS = new Set([\n \"left\",\n \"right\",\n \"center\",\n \"justify\",\n \"start\",\n \"end\",\n]);\n\nfunction toTextAlign(\n textAlign: string | undefined,\n): ParagraphStyle[\"textAlign\"] {\n return textAlign !== undefined && TEXT_ALIGNS.has(textAlign)\n ? (textAlign as ParagraphStyle[\"textAlign\"])\n : \"left\";\n}\n\n/** CSS `word-break`, as the paragraph's `wordBreak`. */\nfunction toWordBreak(style: ComputedStyle): ParagraphStyle[\"wordBreak\"] {\n const { wordBreak } = style;\n return wordBreak === \"break-all\" || wordBreak === \"keep-all\"\n ? wordBreak\n : \"normal\";\n}\n\n/**\n * CSS `overflow-wrap`, as the paragraph's `overflowWrap`. The deprecated\n * `word-break: break-word` is `overflow-wrap: anywhere`, which breaks an\n * overlong word as `break-word` does (it only adds to min-content). The\n * legacy `word-wrap` arrives as `overflowWrap` (see `expandStyle`).\n */\nfunction toOverflowWrap(style: ComputedStyle): ParagraphStyle[\"overflowWrap\"] {\n const { overflowWrap, wordBreak } = style;\n return overflowWrap === \"break-word\" ||\n overflowWrap === \"anywhere\" ||\n wordBreak === \"break-word\"\n ? \"break-word\"\n : \"normal\";\n}\n\n// Skia treats a width of 0 as unbounded; a box with no room wraps at every\n// opportunity instead.\nconst MIN_WIDTH = 0.01;\n\n// A paragraph needs a font size > 0. CSS draws `font-size: 0` text as\n// nothing, in line boxes of no height under `line-height: normal`.\nconst MIN_FONT_SIZE = 1e-3;\n\n/**\n * Where an emoji drawn as an image sits on its line: its bottom 0.1em below\n * the baseline, as CSS `vertical-align: -0.1em`. That's where Chrome draws an\n * emoji glyph (Apple Color Emoji's 🌍 ink spans 0.115em below the baseline to\n * 0.865em above it, at any line height), and what twemoji's own stylesheet\n * gives its images.\n */\nconst EMOJI_DROP = 0.1;\n\n// A paragraph's native memory (some 20 KB) is released by a finalizer, and\n// Node only runs finalizers on a later turn of the event loop. A frame loop\n// that awaits nothing but microtasks never gets there, and would grow by every\n// paragraph it has built. So they are counted per turn, and a render that\n// finds too many outstanding yields one turn itself.\nconst MAX_PENDING_PARAGRAPHS = 2000;\nlet pendingParagraphs = 0;\nlet turnWatched = false;\n\nfunction countParagraph(): void {\n pendingParagraphs++;\n if (turnWatched) return;\n turnWatched = true;\n // Runs once the event loop turns, by whoever's doing.\n setImmediate(() => {\n pendingParagraphs = 0;\n turnWatched = false;\n });\n}\n\n/**\n * Give Node a turn of the event loop to release the paragraphs built so far,\n * if enough have piled up since the last one.\n */\nexport async function releaseParagraphs(): Promise<void> {\n if (pendingParagraphs < MAX_PENDING_PARAGRAPHS) return;\n await new Promise<void>((resolve) => setImmediate(resolve));\n}\n\n/**\n * A line box's height, the baseline in it, and the font's ascent and descent\n * it's built from, in px.\n */\ntype LineBox = {\n lineHeight: number;\n baseline: number;\n ascent: number;\n descent: number;\n};\n\n/**\n * A line box, as the paragraph lays it out by Chrome's half-leading (Blink's\n * `CalculateLeadingSpace`): the ascent and descent rounded to whole pixels,\n * and the half of the leading above them floored to whole pixels, after\n * halving it in Chrome's 1/64px layout units. For Liberation Sans at 20px in a\n * 30px line, the baseline is at 22px; in a `normal` one, 23px tall, at 18px.\n *\n * @param lineHeight - The line height in px, as the paragraph reports it\n * (rounded to 1/64px)\n * @param ascent - The font's hhea ascent in px\n * @param descent - Its hhea descent in px, positive below the baseline\n */\nfunction halfLeadingLineBox(\n lineHeight: number,\n ascent: number,\n descent: number,\n): LineBox {\n const a = Math.round(ascent);\n const d = Math.round(descent);\n const leading = (lineHeight - a - d) * 64;\n return {\n lineHeight,\n baseline: a + Math.floor(Math.trunc(leading / 2) / 64),\n ascent: a,\n descent: d,\n };\n}\n\nconst graphemeSegmenter = new Intl.Segmenter(undefined, {\n granularity: \"grapheme\",\n});\n\n/**\n * The text as a paragraph's content, with every emoji grapheme an inline\n * placeholder for its image.\n */\ntype Content = {\n items: (string | ParagraphPlaceholder)[];\n /** The emoji, in the order of their placeholders. */\n emoji: string[];\n /**\n * Maps a UTF-16 index in the paragraph's text, where a placeholder counts\n * as one unit, to one in `text`; undefined when they're the same.\n */\n toTextIndex?: (index: number) => number;\n};\n\nfunction splitEmoji(\n text: string,\n fontSize: number,\n letterSpacing: number,\n): Content {\n const items: (string | ParagraphPlaceholder)[] = [];\n const emoji: string[] = [];\n // Paragraph index → text index, at the start of each emoji and after it.\n const marks: [number, number][] = [];\n let run = \"\";\n let paragraphIndex = 0;\n let textIndex = 0;\n for (const { segment } of graphemeSegmenter.segment(text)) {\n if (!isEmoji(segment)) {\n run += segment;\n paragraphIndex += segment.length;\n textIndex += segment.length;\n continue;\n }\n if (run) items.push(run);\n run = \"\";\n items.push({\n // Letter spacing follows every character, an emoji too, but a\n // paragraph doesn't add it to a placeholder.\n width: Math.max(0, fontSize + letterSpacing),\n height: fontSize,\n verticalAlign: \"baseline\",\n baselineOffset: fontSize * (1 - EMOJI_DROP),\n // Lines break around it as around an emoji, not an inline-block: it\n // stays with the punctuation next to it, so \"Hi 🎉! ok\" breaks as\n // \"Hi | 🎉! | ok\" and \"(🎉)\" stays whole, as in browsers.\n lineBreak: \"emoji\",\n });\n emoji.push(segment);\n marks.push([paragraphIndex, textIndex]);\n paragraphIndex += 1;\n textIndex += segment.length;\n marks.push([paragraphIndex, textIndex]);\n }\n if (run) items.push(run);\n if (emoji.length === 0) return { items: [text], emoji };\n return {\n items,\n emoji,\n toTextIndex: (index) => {\n // The last mark at or before `index`; text runs map one to one.\n let mark: [number, number] = [0, 0];\n for (const m of marks) {\n if (m[0] > index) break;\n mark = m;\n }\n return mark[1] + (index - mark[0]);\n },\n };\n}\n\n/**\n * Lay out already-transformed text natively: one segment per line, CSS\n * half-leading line boxes from the font's hhea metrics (Chrome's for\n * `line-height: normal`), an ellipsis for nowrap + text-overflow and for\n * line-clamp, and text-box-trim.\n *\n * @param lineHeight - Line box height in px, or undefined for `normal`\n * @param emojiEnabled - Whether emoji are drawn as images, each in an inline\n * box of its own\n */\nexport function layoutTextNative(\n text: string,\n style: ComputedStyle,\n maxWidth: number,\n lineHeight: number | undefined,\n emojiEnabled?: boolean,\n): TextLayoutResult {\n const styledFontSize = style.fontSize ?? 16;\n const fontSize = Number.isFinite(styledFontSize)\n ? Math.max(styledFontSize, MIN_FONT_SIZE)\n : 16;\n const fontFamily = style.fontFamily ?? DEFAULT_FONT_FAMILY;\n const fontWeight = style.fontWeight ?? 400;\n const fontStyle = style.fontStyle ?? \"normal\";\n const letterSpacing =\n typeof style.letterSpacing === \"number\" &&\n Number.isFinite(style.letterSpacing)\n ? style.letterSpacing\n : 0;\n const whiteSpace = style.whiteSpace ?? \"normal\";\n const noWrap = whiteSpace === \"nowrap\" || whiteSpace === \"pre\";\n const lineClamp =\n style.lineClamp && style.lineClamp >= 1\n ? Math.floor(style.lineClamp)\n : undefined;\n const ellipsis =\n lineClamp !== undefined || (noWrap && style.textOverflow === \"ellipsis\")\n ? \"…\"\n : undefined;\n const width = maxWidth > 0 ? maxWidth : MIN_WIDTH;\n\n const content = emojiEnabled\n ? splitEmoji(text, fontSize, letterSpacing)\n : { items: [text], emoji: [] };\n\n // Skia keeps its own cache of shaped text, so building a paragraph for text\n // it has seen (the next frame of a video, or Yoga measuring a node again)\n // only breaks the lines anew.\n const paragraph = new Paragraph(content.items, {\n fontFamily: quoteFontFamilies(fontFamily),\n fontSize,\n fontWeight: toWeight(fontWeight),\n fontStyle: toFontStyle(fontStyle),\n letterSpacing,\n // Undefined for `normal`, which the paragraph sizes as Chrome does.\n lineHeight,\n textAlign: toTextAlign(style.textAlign),\n noWrap,\n maxLines: lineClamp,\n ellipsis,\n // `pre` and `pre-wrap` keep the spaces before a line break in the line.\n keepTrailingWhitespace: whiteSpace === \"pre\" || whiteSpace === \"pre-wrap\",\n wordBreak: toWordBreak(style),\n overflowWrap: toOverflowWrap(style),\n });\n countParagraph();\n const layout = paragraph.layout(width);\n\n // The paragraph places each baseline by Chrome's half-leading in its line\n // box, a normal one too.\n const box = halfLeadingLineBox(\n layout.lineHeight,\n layout.ascent,\n layout.descent,\n );\n\n // An empty paragraph has no lines, where CSS keeps one empty line box.\n const lines: ParagraphLine[] =\n layout.lines.length > 0\n ? layout.lines\n : [\n {\n left: 0,\n width: 0,\n baseline: box.baseline,\n startIndex: 0,\n endIndex: 0,\n hardBreak: true,\n },\n ];\n const toTextIndex = content.toTextIndex ?? ((index: number) => index);\n const segments: TextSegment[] = lines.map((line, i) => ({\n text: text.slice(toTextIndex(line.startIndex), toTextIndex(line.endIndex)),\n x: line.left,\n y: line.baseline,\n width: line.width,\n height: layout.lineHeight,\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n color: style.color ?? \"black\",\n ascent: layout.ascent,\n textDecoration: style.textDecoration,\n letterSpacing,\n lineIndex: i,\n }));\n\n const emoji: PlacedEmoji[] = [];\n layout.placeholders.forEach((placed, i) => {\n // A placeholder that line-clamp or an ellipsis cut off has no box.\n if (!placed) return;\n emoji.push({\n grapheme: content.emoji[i]!,\n x: placed.x,\n y: placed.y,\n size: fontSize,\n baseline: lines[placed.line]!.baseline,\n });\n });\n\n // Normal line boxes are whole pixels tall; text of no font size, laid out\n // at MIN_FONT_SIZE, has them of no height, as in CSS.\n let height = lines.length * layout.lineHeight;\n\n let paragraphOffsetY = 0;\n const textBoxTrim = style.textBoxTrim;\n if (textBoxTrim && textBoxTrim !== \"none\") {\n const trim = measureTrimMetrics(\n fontSize,\n fontFamily,\n fontWeight,\n fontStyle,\n box,\n style.textBoxEdge ?? \"text\",\n );\n if (textBoxTrim === \"trim-start\" || textBoxTrim === \"trim-both\") {\n for (const seg of segments) seg.y -= trim.overTrim;\n for (const e of emoji) {\n e.y -= trim.overTrim;\n e.baseline -= trim.overTrim;\n }\n height -= trim.overTrim;\n paragraphOffsetY -= trim.overTrim;\n }\n if (textBoxTrim === \"trim-end\" || textBoxTrim === \"trim-both\") {\n height -= trim.underTrim;\n }\n }\n\n return {\n segments,\n width: segments.reduce((w, s) => Math.max(w, s.width), 0),\n height,\n maxContentWidth: layout.maxIntrinsicWidth,\n minContentWidth: layout.minIntrinsicWidth,\n paragraph,\n paragraphOffsetY,\n emoji,\n };\n}\n","// This file contains code adapted from Satori (https://github.com/vercel/satori)\n// Licensed under the Mozilla Public License 2.0 (MPL-2.0)\n// See NOTICE.md in the package root for details.\n\n/**\n * Detect the primary script/language of a text string.\n * Used for font selection and line-breaking behavior.\n */\nexport function detectLanguageCode(text: string): string | undefined {\n for (const char of text) {\n const cp = char.codePointAt(0);\n if (cp === undefined) continue;\n\n // CJK Unified Ideographs\n if (cp >= 0x4e00 && cp <= 0x9fff) return \"zh\";\n // CJK Extension A\n if (cp >= 0x3400 && cp <= 0x4dbf) return \"zh\";\n // Hiragana\n if (cp >= 0x3040 && cp <= 0x309f) return \"ja\";\n // Katakana\n if (cp >= 0x30a0 && cp <= 0x30ff) return \"ja\";\n // Hangul Syllables\n if (cp >= 0xac00 && cp <= 0xd7af) return \"ko\";\n // Hangul Jamo\n if (cp >= 0x1100 && cp <= 0x11ff) return \"ko\";\n // Thai\n if (cp >= 0x0e00 && cp <= 0x0e7f) return \"th\";\n // Arabic\n if (cp >= 0x0600 && cp <= 0x06ff) return \"ar\";\n // Hebrew\n if (cp >= 0x0590 && cp <= 0x05ff) return \"he\";\n // Devanagari\n if (cp >= 0x0900 && cp <= 0x097f) return \"hi\";\n // Bengali\n if (cp >= 0x0980 && cp <= 0x09ff) return \"bn\";\n // Tamil\n if (cp >= 0x0b80 && cp <= 0x0bff) return \"ta\";\n // Telugu\n if (cp >= 0x0c00 && cp <= 0x0c7f) return \"te\";\n // Kannada\n if (cp >= 0x0c80 && cp <= 0x0cff) return \"kn\";\n // Malayalam\n if (cp >= 0x0d00 && cp <= 0x0d7f) return \"ml\";\n }\n\n return undefined;\n}\n\n// Which graphemes are drawn as emoji images, following UTS #51: every emoji\n// character, with or without U+FE0F, except the few that are text by default\n// in every font (©, ®, ™, digits, # and *). Browsers draw the other\n// text-default emoji characters in the BMP, such as ❤ or ☎, as monochrome\n// text through system font fallback; canvas has no such fallback, so an\n// image beats tofu.\n\n/**\n * A code point reserved for emoji that this runtime's Unicode doesn't know\n * yet: every emoji added since Unicode 9 is presented as one by default.\n */\nexport const UNASSIGNED_PICTOGRAPHIC = String.raw`(?=\\p{Cn})\\p{Extended_Pictographic}`;\n\n/** A character with an emoji form, \\p{Emoji} or \\p{Extended_Pictographic}. */\nconst EMOJI_CHAR = String.raw`[\\p{Emoji}\\p{Extended_Pictographic}]`;\n\n/**\n * A keycap base: a digit, # or *. On its own, even before U+FE0F, it's text,\n * as in Chrome; only a keycap sequence makes it an emoji.\n */\nconst KEYCAP_BASE = \"[0-9#*]\";\n\n/**\n * An emoji character that stays text on its own: a keycap base (digits, # and\n * *), text unless a keycap follows it, and ©, ® and ™, text unless U+FE0F\n * follows them.\n */\nconst TEXT_EMOJI_CHAR = String.raw`[0-9#*\\u00A9\\u00AE\\u2122]`;\n\n/** A tag sequence's tags, as in a subdivision flag such as 🏴󠁧󠁢󠁥󠁮󠁧󠁿. */\nconst TAGS = String.raw`[\\u{E0020}-\\u{E007E}]+\\u{E007F}`;\n\n/** An emoji element drawn as an emoji, also when it stands alone. */\nconst PRESENTED_EMOJI = [\n // Keycap: 1️⃣, and the unqualified 1⃣.\n String.raw`${KEYCAP_BASE}\\uFE0F?\\u20E3`,\n // Flag: a pair of regional indicators.\n String.raw`\\p{Regional_Indicator}{2}`,\n // Emoji presentation sequence (©️), modifier sequence (👍🏽, ☝🏽) or tag\n // sequence (🏴󠁧󠁢󠁥󠁮󠁧󠁿).\n String.raw`(?!${KEYCAP_BASE})${EMOJI_CHAR}(?:\\uFE0F|\\p{Emoji_Modifier}|${TAGS})`,\n // An emoji character on its own, emoji presentation by default (🌍, ⭐) or\n // text (❤, ☎, 🕵), but not one that stays text.\n String.raw`(?!${TEXT_EMOJI_CHAR})\\p{Emoji}`,\n UNASSIGNED_PICTOGRAPHIC,\n].join(\"|\");\n\n/**\n * An element of a ZWJ sequence: any emoji element, or a character with an\n * emoji form that isn't one on its own (the © in ©‍®), but no bare keycap\n * base.\n */\nconst ZWJ_ELEMENT = `(?:${PRESENTED_EMOJI}|(?!${KEYCAP_BASE})${EMOJI_CHAR})`;\n\nconst EMOJI_RE = new RegExp(\n `^(?:${PRESENTED_EMOJI}|${ZWJ_ELEMENT}(?:\\\\u200D${ZWJ_ELEMENT})+)$`,\n \"u\",\n);\n\n/**\n * Whether a grapheme cluster is an emoji, to draw as an image: an emoji\n * character with or without U+FE0F (©, ®, ™ only with it, and digits, # and\n * * only in a keycap), a keycap, a flag, a modifier or tag sequence, or a ZWJ sequence of emoji\n * (UTS #51). U+FE0E keeps an emoji character text. A ZWJ between anything\n * else (the joiner in Arabic or Indic text, or a lone one) doesn't make an\n * emoji, and neither do symbols with no emoji form, such as ✓ or ●.\n *\n * @param grapheme - One grapheme cluster, as `Intl.Segmenter` splits text\n */\nexport function isEmoji(grapheme: string): boolean {\n return EMOJI_RE.test(grapheme);\n}\n","import { createCanvas } from \"@effing/skia\";\nimport type { SKRSContext2D } from \"@effing/skia\";\n\n// Scratch canvas for measuring glyphs\nlet scratchCtx: SKRSContext2D | null = null;\n\nfunction getScratchCtx(): SKRSContext2D {\n if (!scratchCtx) {\n scratchCtx = createCanvas(1, 1).getContext(\"2d\");\n }\n return scratchCtx;\n}\n\nconst GENERIC_FAMILIES = new Set([\n \"serif\",\n \"sans-serif\",\n \"monospace\",\n \"cursive\",\n \"fantasy\",\n \"system-ui\",\n \"ui-serif\",\n \"ui-sans-serif\",\n \"ui-monospace\",\n \"ui-rounded\",\n \"math\",\n \"emoji\",\n \"fangsong\",\n]);\n\nfunction quoteFontFamily(family: string): string {\n if (!family || GENERIC_FAMILIES.has(family)) return family;\n return `\"${family}\"`;\n}\n\n/** A font-family list with every non-generic family name quoted. */\nexport function quoteFontFamilies(fontFamily: string): string {\n return fontFamily\n .split(\",\")\n .map((f) => quoteFontFamily(f.trim()))\n .join(\", \");\n}\n\n/**\n * Set font properties on a canvas context.\n */\nexport function setFont(\n ctx: SKRSContext2D,\n fontSize: number,\n fontFamily: string,\n fontWeight: number | string = 400,\n fontStyle: string = \"normal\",\n): void {\n ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${quoteFontFamilies(fontFamily)}`;\n}\n\n/**\n * Measure how many pixels to trim from the top (overTrim) and bottom\n * (underTrim) of a line box based on `text-box-edge` keywords.\n *\n * The trim amount is the distance from the line box's edge to the target\n * metric for each edge, as the `text` edge the font's ascent and descent\n * rounded to whole pixels, as the line box's half-leading takes them (so the\n * `text` edge trims a set line height's half-leading exactly, as in Chrome).\n *\n * @param line - The line box, its baseline, and the font's ascent and\n * descent in px, rounded as the line box is built from them\n */\nexport function measureTrimMetrics(\n fontSize: number,\n fontFamily: string,\n fontWeight: number | string,\n fontStyle: string,\n line: {\n lineHeight: number;\n baseline: number;\n ascent: number;\n descent: number;\n },\n edge: string,\n): { overTrim: number; underTrim: number } {\n const c = getScratchCtx();\n // Unhinted, as text is laid out and drawn.\n const measure = (text: string) => {\n setFont(c, fontSize, fontFamily, fontWeight, fontStyle);\n const previous = c.textRendering;\n c.textRendering = \"geometricPrecision\";\n try {\n return c.measureText(text);\n } finally {\n c.textRendering = previous;\n }\n };\n\n // Parse edge into over-edge and under-edge keywords\n const parts = edge.trim().split(/\\s+/);\n const overEdge = parts[0] ?? \"text\";\n const underEdge = parts.length > 1 ? parts[1]! : overEdge;\n\n // Resolve over-edge keyword → target ascent\n let targetAscent: number;\n switch (overEdge) {\n case \"cap\": {\n const capMetrics = measure(\"H\");\n targetAscent = capMetrics.actualBoundingBoxAscent ?? fontSize * 0.7;\n break;\n }\n case \"ex\": {\n const exMetrics = measure(\"x\");\n targetAscent = exMetrics.actualBoundingBoxAscent ?? fontSize * 0.5;\n break;\n }\n case \"ideographic\":\n case \"ideographic-ink\":\n case \"text\":\n default:\n targetAscent = line.ascent;\n break;\n }\n\n // Resolve under-edge keyword → target descent\n let targetDescent: number;\n switch (underEdge) {\n case \"alphabetic\":\n targetDescent = 0;\n break;\n case \"ideographic\":\n case \"ideographic-ink\":\n case \"text\":\n default:\n targetDescent = line.descent;\n break;\n }\n\n const overTrim = line.baseline - targetAscent;\n const underTrim = line.lineHeight - line.baseline - targetDescent;\n\n return {\n overTrim: Math.max(0, overTrim),\n underTrim: Math.max(0, underTrim),\n };\n}\n","// White space processing, CSS Text 3 §4.1: the collapsing of phase I and the\n// removal of collapsible spaces at the start and end of a line of phase II,\n// for the `white-space` values that collapse spaces. Canvas lays out each run\n// of text and `<br>`s between other elements as a flex item of its own, as a\n// flex container has it, so the text of one text node is all there is to\n// collapse across.\n\nimport type { ComputedStyle } from \"../style/compute.ts\";\n\ntype WhiteSpace = NonNullable<ComputedStyle[\"whiteSpace\"]>;\n\n/**\n * The text of a text node: a string, or, for text with `<br>`s in it, the\n * pieces of text between them, each `<br>` a forced line break. The breaks\n * are kept apart from the text, as no character in it can stand for one: a\n * newline is a space under `normal` and `nowrap`, and a line separator\n * (U+2028) is a space with a break opportunity after it, as in Chrome.\n */\nexport type TextContent = string | readonly string[];\n\n/**\n * Whether `text` is nothing but white space: spaces, tabs, segment breaks,\n * form feeds and vertical tabs, the ASCII white space Chrome checks for. CSS\n * doesn't render a run of text in a flex container that is, under any\n * `white-space` (CSS Flexbox §4), as Chrome confirms.\n */\nexport function isWhiteSpaceOnly(text: string): boolean {\n return /^[ \\t\\n\\r\\f\\v]*$/.test(text);\n}\n\n/**\n * Process the white space of a text box's text as CSS does, before it's\n * transformed and laid out (CSS Text 3 §1.3). Each piece of text between two\n * `<br>`s is processed on its own, as the lines a `<br>` ends and starts, and\n * every `<br>` is a forced break (a newline) under every `white-space`, as in\n * Chrome; `nowrap` included. Under `normal`, `nowrap` and `pre-line`:\n *\n * - a CRLF is one segment break, and a lone CR a space, as Chrome has them;\n * - tabs are spaces;\n * - the spaces around a segment break are removed;\n * - under `normal` and `nowrap`, a run of segment breaks is one space, where\n * `pre-line` keeps each one as a forced break;\n * - a run of spaces is one space;\n * - the spaces at the start and end of the text, which start and end a line,\n * are removed, and so are those before and after a `<br>`.\n *\n * The paragraph hangs the space at a line's soft wrap, as CSS does, so the\n * spaces at the start and end of the other lines take care of themselves.\n * Only ASCII white space collapses: a no-break space, say, is kept.\n *\n * `pre` and `pre-wrap` keep the spaces and tabs, and a lone CR, which the\n * paragraph lays out as Chrome does: with no width, no glyph and no break\n * opportunity, but as a break in the shaping, so the letters either side of\n * it don't kern or join. Under every value, a CRLF is one segment break, as\n * in Chrome, made one newline so that removing a final break and joining at\n * a `<br>` deal in single-unit newlines, and:\n *\n * - A segment break or a `<br>` at the very end of the text ends the last\n * line, rather than starting an empty one, as in Chrome. This relies on\n * the paragraph (`@effing/skia`'s `Paragraph`) starting an empty line after\n * a hard break that ends its text: only one final break is removed, so\n * that \"a\\n\\n\" or \"a<br><br>\" keeps the one that gives it its second,\n * empty line, as in Chrome. A newline before a `<br>` is a break of its\n * own under `pre`, `pre-wrap` and `pre-line`: \"a\\n<br>b\" has an empty line\n * between \"a\" and \"b\", as in Chrome.\n * - The paragraph breaks the line at a line or paragraph separator (U+2028,\n * U+2029), a form feed or a vertical tab, where Chrome doesn't. Chrome sets\n * a separator as a space that neither collapses nor hangs, with a break\n * opportunity after it: a no-break space and a zero-width space are that\n * to the paragraph. A form feed or a vertical tab is removed. Chrome draws\n * a form feed as nothing under `pre` and `pre-wrap`; otherwise, and for a\n * vertical tab under any value, it draws a fallback font's glyph for the\n * control character, which this leaves out.\n */\nexport function collapseWhiteSpace(\n text: TextContent,\n whiteSpace: WhiteSpace | undefined,\n): string {\n const pieces = typeof text === \"string\" ? [text] : text;\n // Once collapsed, the only newlines left are forced breaks. A lone CR that\n // ends a piece, kept under `pre` and `pre-wrap`, makes a CRLF with the\n // break after it, which is one newline like any other.\n return pieces\n .map((piece) => collapsePiece(piece, whiteSpace))\n .join(\"\\n\")\n .replace(/\\r\\n/g, \"\\n\")\n .replace(FINAL_BREAK, \"\")\n .replace(SEPARATORS, SEPARATOR_SPACE);\n}\n\n/** Process the white space of text that a forced break or nothing ends. */\nfunction collapsePiece(\n text: string,\n whiteSpace: WhiteSpace | undefined,\n): string {\n let result = text.replace(/[\\v\\f]/g, \"\").replace(/\\r\\n/g, \"\\n\");\n if (\n whiteSpace !== \"pre\" &&\n whiteSpace !== \"pre-wrap\" &&\n /[\\t\\n\\r]| {2}|^ | $/.test(result)\n ) {\n // Most text has nothing to collapse: no tab, newline, CR, or space that\n // could be leading, trailing or doubled.\n result = result.replace(/[\\t\\r]/g, \" \").replace(/ *\\n */g, \"\\n\");\n if (whiteSpace !== \"pre-line\") result = result.replace(/\\n+/g, \" \");\n result = result.replace(/ {2,}/g, \" \").replace(/^ | $/g, \"\");\n }\n return result;\n}\n\nconst FINAL_BREAK = /\\n$/;\n\nconst SEPARATORS = /[\\u2028\\u2029]/g;\n\n/**\n * A space that neither collapses nor hangs (a no-break space), followed by a\n * break opportunity (a zero-width space).\n */\nconst SEPARATOR_SPACE = \"\\u00a0\\u200b\";\n","// This file contains code adapted from Satori (https://github.com/vercel/satori)\n// Licensed under the Mozilla Public License 2.0 (MPL-2.0)\n// See NOTICE.md in the package root for details.\n\nimport type { ComputedStyle } from \"../style/compute.ts\";\nimport { resolveUnit } from \"../style/compute.ts\";\nimport { layoutTextNative } from \"./native.ts\";\nimport type { NativeParagraph } from \"./native.ts\";\nimport { collapseWhiteSpace } from \"./white-space.ts\";\nimport type { TextContent } from \"./white-space.ts\";\n\nexport type TextSegment = {\n text: string;\n x: number;\n y: number;\n width: number;\n height: number;\n fontSize: number;\n fontFamily: string;\n fontWeight: number | string;\n fontStyle: string;\n color: string;\n ascent: number;\n textDecoration?: string;\n letterSpacing: number;\n lineIndex: number;\n textStrokeWidth?: number;\n textStrokeColor?: string;\n};\n\nexport type TextLayoutResult = {\n segments: TextSegment[];\n width: number;\n height: number;\n /**\n * The width of the widest line between forced breaks, were no line to wrap\n * (CSS max-content).\n */\n maxContentWidth: number;\n /**\n * The width of the widest run of text that can't break: a word, or a line\n * that doesn't wrap (CSS min-content). An `overflow-wrap: break-word` that\n * breaks a word doesn't count, as in CSS; `anywhere` does, but the\n * paragraph knows it as `break-word` (see `TextMeasure.minContentWidth`).\n */\n minContentWidth: number;\n /**\n * The paragraph to paint. The segments describe its lines, for\n * decorations.\n */\n paragraph: NativeParagraph;\n /** Vertical offset to paint `paragraph` at, relative to the text box. */\n paragraphOffsetY: number;\n /** Emoji to draw as images, in the inline boxes the paragraph left them. */\n emoji: PlacedEmoji[];\n};\n\n/** An emoji drawn as an image, at its inline box in the text box. */\nexport type PlacedEmoji = {\n /** The emoji's grapheme cluster. */\n grapheme: string;\n /** Top-left corner of its box. */\n x: number;\n y: number;\n /** The image's width and height. */\n size: number;\n /** Baseline of its line, to draw the emoji as text when there's no image. */\n baseline: number;\n};\n\n/**\n * Lay out text content into positioned lines, as one native paragraph that\n * Skia breaks, shapes and paints (see `./native.ts`). White space collapses\n * as `white-space` has it, before `text-transform` applies, as in CSS.\n *\n * @param text - The text to lay out, or the pieces of it between its `<br>`s\n * @param style - Computed style\n * @param maxWidth - Maximum width for wrapping\n * @param emojiEnabled - Whether emoji are drawn as images\n * @returns Text segments with positions and total dimensions, and the\n * paragraph to paint\n */\nexport function layoutText(\n text: TextContent,\n style: ComputedStyle,\n maxWidth: number,\n emojiEnabled?: boolean,\n): TextLayoutResult {\n const fontSize = style.fontSize ?? 16;\n const result = layoutTextNative(\n applyTextTransform(collapseWhiteSpace(text, style.whiteSpace), style),\n style,\n maxWidth,\n resolveLineHeight(style.lineHeight, fontSize),\n emojiEnabled,\n );\n const textStrokeWidth = resolveTextStrokeWidth(style, fontSize);\n for (const seg of result.segments) {\n seg.textStrokeWidth = textStrokeWidth;\n seg.textStrokeColor = style.WebkitTextStrokeColor;\n }\n return result;\n}\n\nfunction resolveTextStrokeWidth(\n style: ComputedStyle,\n fontSize: number,\n): number | undefined {\n const raw = style.WebkitTextStrokeWidth;\n if (raw === undefined) return undefined;\n if (typeof raw === \"number\") return raw;\n const resolved = resolveUnit(String(raw), 0, 0, fontSize, 16);\n return typeof resolved === \"number\" ? resolved : undefined;\n}\n\nfunction applyTextTransform(text: string, style: ComputedStyle): string {\n if (style.textTransform === \"uppercase\") return text.toUpperCase();\n if (style.textTransform === \"lowercase\") return text.toLowerCase();\n if (style.textTransform === \"capitalize\") {\n return text.replace(/\\b\\w/g, (c) => c.toUpperCase());\n }\n return text;\n}\n\n/**\n * The line box height in px, or undefined for `normal`, which the paragraph\n * takes from the font. A height of 0 collapses the line boxes, as in CSS.\n */\nfunction resolveLineHeight(\n lineHeight: number | string | undefined,\n fontSize: number,\n): number | undefined {\n if (lineHeight === undefined || lineHeight === \"normal\") return undefined;\n let px: number;\n if (typeof lineHeight === \"number\") {\n // Already resolved to px in compute.ts if > 5, else multiplier\n px = lineHeight > 5 ? lineHeight : lineHeight * fontSize;\n } else {\n px = parseFloat(lineHeight);\n }\n // A negative line height is invalid in CSS, as is anything unparsable:\n // `normal` it is.\n return Number.isFinite(px) && px >= 0 ? px : undefined;\n}\n\n/**\n * Round a text width for Yoga up to 1/64px, as Chrome does: it lays out in\n * units of 1/64px, and rounds the width of text up to them. That also keeps\n * Yoga's sums exact. It shrinks flex items in float32, and when every item\n * that shrinks in a line is held at its minimum width, the shrink factors it\n * sums and takes away again can leave a rounding error behind, which it then\n * divides by: the items grow to millions of pixels. Rounding up keeps the\n * text on the lines it was measured with.\n */\nfunction toLayoutGrid(width: number): number {\n return Math.ceil(width * 64) / 64;\n}\n\nconst graphemeSegmenter = new Intl.Segmenter(undefined, {\n granularity: \"grapheme\",\n});\n\n/**\n * Sizes a text node for Yoga, and lays its text out for drawing at the width\n * Yoga finally gives it.\n *\n * Yoga measures a node at whatever widths its algorithm needs, and may size\n * the node (or its ancestors) from a measurement at a width other than the\n * final one — a flex basis at the available width, say, before the node\n * shrinks. Laid out again at the final width, the text can then take more or\n * fewer lines than the box was sized for. `settle` catches that: it lays the\n * text out at the final width and, when Yoga saw a different height, pins\n * every later measurement to the height drawn, for the caller to compute the\n * layout again. The widths Yoga is given, which decide the line breaks, are\n * unchanged by the pin, so the next layout normally keeps the node's width.\n */\nexport class TextMeasure {\n /**\n * Yoga's measurements by width (Infinity for unbounded), and those at\n * exactly a width.\n */\n private readonly sizes = new Map<number, { width: number; height: number }>();\n private readonly exactSizes = new Map<\n number,\n { width: number; height: number }\n >();\n /**\n * The heights reported to Yoga since the node was last marked dirty (see\n * `settle`): Yoga may size the node, and its ancestors, from any of them,\n * cached, without measuring it again.\n */\n private readonly reported = new Set<number>();\n private pinnedHeight: number | undefined;\n private settled: { width: number; result: TextLayoutResult } | undefined;\n /**\n * The text's intrinsic widths, from whichever layout came first: its\n * max-content width, and a bound on its min-content width, which is the\n * min-content width but where finding it takes more (see `widestGrapheme`).\n */\n private intrinsic:\n { max: number; minBound: number; min: number | undefined } | undefined;\n\n constructor(\n private readonly text: TextContent,\n private readonly style: ComputedStyle,\n private readonly emojiEnabled?: boolean,\n ) {}\n\n /**\n * Measure the text for Yoga.\n *\n * @param maxWidth - The width available, Infinity for unbounded\n * @param exact - Whether the node is exactly `maxWidth` wide, whatever its\n * text: it's then measured for its height there\n */\n measure(maxWidth: number, exact = false): { width: number; height: number } {\n const sizes = exact ? this.exactSizes : this.sizes;\n let size = sizes.get(maxWidth);\n if (!size) {\n let result = this.layOut(maxWidth);\n // Text is as wide as CSS fit-content makes it. When it wraps, that's\n // the constraint width (like CSS block layout), so that the node is\n // drawn at the width its lines were broken at, unless a run that can't\n // break is wider: then it's as wide as that run (its min-content), and\n // laid out at that width, as it will be drawn. Text that only breaks\n // where it's forced to is as wide as its widest line (max-content),\n // without the ellipsis a line clamp adds: the clamped line is truncated\n // to fit that width when it's drawn, as in Chrome.\n let width: number;\n if (exact) {\n width = maxWidth;\n } else if (result.maxContentWidth > maxWidth) {\n width =\n this.minContentBound <= maxWidth\n ? maxWidth\n : Math.max(maxWidth, this.minContentWidth);\n if (width > maxWidth) result = this.layOut(width);\n } else {\n width = Math.min(\n toLayoutGrid(Math.min(result.width, result.maxContentWidth)),\n maxWidth,\n );\n }\n size = { width, height: result.height };\n sizes.set(maxWidth, size);\n }\n const height = this.pinnedHeight ?? size.height;\n this.reported.add(height);\n return { width: size.width, height };\n }\n\n /**\n * The height of the text's lines at exactly `width`, as drawn there,\n * whatever height later measurements are pinned to.\n */\n heightAt(width: number): number {\n if (this.settled?.width === width) return this.settled.result.height;\n let size = this.exactSizes.get(width);\n if (!size) {\n size = { width, height: this.layOut(width).height };\n this.exactSizes.set(width, size);\n }\n return size.height;\n }\n\n /**\n * The text's min-content width: as narrow as it gets, each run of it that\n * can't break on a line of its own. As CSS has it, that's the widest word,\n * or the widest line for text that doesn't wrap, and under\n * `overflow-wrap: anywhere` (or `word-break: break-word`) and\n * `word-break: break-all` the widest letter. Text truncated with an\n * ellipsis (`text-overflow: ellipsis` without wrapping, or a line clamp)\n * has none: it's drawn at whatever width it has, which CSS gives it in\n * the `overflow: hidden` box an ellipsis needs.\n *\n * Never wider than the text's widest line, and on the layout grid (see\n * `toLayoutGrid`), as the widths `measure` reports are.\n */\n get minContentWidth(): number {\n const intrinsic = this.intrinsic ?? this.measureIntrinsic();\n intrinsic.min ??= Math.min(\n toLayoutGrid(this.widestGrapheme()),\n intrinsic.minBound,\n );\n return intrinsic.min;\n }\n\n /** At least the text's min-content width, and found without more work. */\n get minContentBound(): number {\n return (this.intrinsic ?? this.measureIntrinsic()).minBound;\n }\n\n /**\n * The text's max-content width: its widest line, were no line to wrap, on\n * the layout grid.\n */\n get maxContentWidth(): number {\n return (this.intrinsic ?? this.measureIntrinsic()).max;\n }\n\n /** Whether the text can't be narrower than its widest line. */\n get unbreakable(): boolean {\n return this.minContentBound >= this.maxContentWidth;\n }\n\n private measureIntrinsic(): NonNullable<TextMeasure[\"intrinsic\"]> {\n this.layOut(Infinity);\n return this.intrinsic!;\n }\n\n private layOut(width: number): TextLayoutResult {\n const result = layoutText(this.text, this.style, width, this.emojiEnabled);\n this.intrinsic ??= this.intrinsicOf(result);\n return result;\n }\n\n /** The intrinsic widths of the text, from a layout of it at any width. */\n private intrinsicOf(\n result: TextLayoutResult,\n ): NonNullable<TextMeasure[\"intrinsic\"]> {\n const { style } = this;\n const max = toLayoutGrid(result.maxContentWidth);\n const noWrap = style.whiteSpace === \"nowrap\" || style.whiteSpace === \"pre\";\n if (\n (style.lineClamp !== undefined && style.lineClamp >= 1) ||\n (noWrap && style.textOverflow === \"ellipsis\")\n ) {\n return { max, minBound: 0, min: 0 };\n }\n // Every layout of text that doesn't wrap has the same lines. The\n // paragraph gives its min-content as its max-content, which it rounds\n // up: the widest line is what's drawn.\n const minBound = Math.min(\n toLayoutGrid(\n noWrap\n ? Math.min(result.minContentWidth, result.width)\n : result.minContentWidth,\n ),\n max,\n );\n // The paragraph breaks a word under `anywhere` as under `break-word`,\n // which a word's min-content doesn't count: its widest word is a bound.\n const anywhere =\n !noWrap &&\n (style.overflowWrap === \"anywhere\" || style.wordBreak === \"break-word\");\n return { max, minBound, min: anywhere ? undefined : minBound };\n }\n\n /**\n * The width of the text's widest grapheme cluster: its min-content where\n * a line may break between any two. Each one is laid out once, as a word\n * of its own.\n */\n private widestGrapheme(): number {\n const text = applyTextTransform(\n collapseWhiteSpace(this.text, this.style.whiteSpace),\n this.style,\n );\n // Latin text is a grapheme per character; other scripts and emoji may\n // join several.\n const graphemes = new Set<string>(\n /^[\\s!-\\u02ff]*$/.test(text)\n ? text\n : Array.from(graphemeSegmenter.segment(text), ({ segment }) => segment),\n );\n for (const grapheme of graphemes) {\n if (/^\\s+$/.test(grapheme)) graphemes.delete(grapheme);\n }\n if (graphemes.size === 0) return 0;\n return layoutText(\n [...graphemes].join(\" \"),\n {\n ...this.style,\n whiteSpace: \"normal\",\n wordBreak: \"normal\",\n overflowWrap: \"normal\",\n textTransform: \"none\",\n },\n Infinity,\n this.emojiEnabled,\n ).minContentWidth;\n }\n\n /**\n * Lay the text out for drawing at the node's final content width, and\n * check it against the heights Yoga was given since the node was last\n * marked dirty: Yoga reuses a node's measurements until then, also when\n * the node ends up at another width, so the heights of earlier layouts\n * count too, not just those of the last.\n *\n * @param pin - Whether to pin later measurements to the drawn height when\n * they disagree\n * @returns Whether Yoga sized the node from another height. If `pin`, the\n * node's measurements are now pinned to the drawn height, and the caller\n * must mark the node dirty and compute the layout again.\n */\n settle(width: number, pin: boolean): boolean {\n if (this.settled?.width !== width) {\n this.settled = {\n width,\n result: layoutText(this.text, this.style, width, this.emojiEnabled),\n };\n }\n const { height } = this.settled.result;\n const agrees =\n this.reported.size === 0 ||\n (this.reported.size === 1 && this.reported.has(height));\n if (agrees) return false;\n if (pin) {\n this.pinnedHeight = height;\n this.reported.clear();\n }\n return true;\n }\n\n /**\n * Drop the pinned height, so that Yoga sees the measured heights again.\n *\n * @returns Whether there was a pin, for the caller to mark the node dirty\n */\n unpin(): boolean {\n const pinned = this.pinnedHeight !== undefined;\n this.pinnedHeight = undefined;\n if (pinned) this.reported.clear();\n return pinned;\n }\n\n /** The text as laid out by the last `settle`. */\n get layout(): TextLayoutResult | undefined {\n return this.settled?.result;\n }\n}\n","import type { SKRSContext2D } from \"@effing/skia\";\n\n/**\n * Apply overflow:hidden clipping to a canvas context.\n * Creates a rectangular clip path with optional border-radius.\n */\nexport function applyClip(\n ctx: SKRSContext2D,\n x: number,\n y: number,\n width: number,\n height: number,\n borderRadius?: {\n topLeft: number;\n topRight: number;\n bottomRight: number;\n bottomLeft: number;\n },\n): void {\n ctx.beginPath();\n\n if (borderRadius && hasRadius(borderRadius)) {\n const { topLeft, topRight, bottomRight, bottomLeft } = borderRadius;\n roundedRect(\n ctx,\n x,\n y,\n width,\n height,\n topLeft,\n topRight,\n bottomRight,\n bottomLeft,\n );\n } else {\n ctx.rect(x, y, width, height);\n }\n\n ctx.clip();\n}\n\n/**\n * Draw a rounded rectangle path on the context.\n */\nexport function roundedRect(\n ctx: SKRSContext2D,\n x: number,\n y: number,\n w: number,\n h: number,\n tl: number,\n tr: number,\n br: number,\n bl: number,\n): void {\n const maxR = maxCornerRadius(w, h);\n tl = Math.min(tl, maxR);\n tr = Math.min(tr, maxR);\n br = Math.min(br, maxR);\n bl = Math.min(bl, maxR);\n\n ctx.moveTo(x + tl, y);\n ctx.lineTo(x + w - tr, y);\n if (tr > 0) ctx.arcTo(x + w, y, x + w, y + tr, tr);\n ctx.lineTo(x + w, y + h - br);\n if (br > 0) ctx.arcTo(x + w, y + h, x + w - br, y + h, br);\n ctx.lineTo(x + bl, y + h);\n if (bl > 0) ctx.arcTo(x, y + h, x, y + h - bl, bl);\n ctx.lineTo(x, y + tl);\n if (tl > 0) ctx.arcTo(x, y, x + tl, y, tl);\n ctx.closePath();\n}\n\n/**\n * The largest corner radius a `w` × `h` box is drawn with: every radius is\n * clamped to half the shorter side. Anything that needs to line up with the\n * element's painted corners (`clip-path` geometry boxes, overflow clips) must\n * apply the same clamp.\n */\nexport function maxCornerRadius(w: number, h: number): number {\n return Math.min(w, h) / 2;\n}\n\nexport function hasRadius(r: {\n topLeft: number;\n topRight: number;\n bottomRight: number;\n bottomLeft: number;\n}): boolean {\n return (\n r.topLeft > 0 || r.topRight > 0 || r.bottomRight > 0 || r.bottomLeft > 0\n );\n}\n","import { Path2D } from \"@effing/skia\";\nimport type { SKRSContext2D } from \"@effing/skia\";\n\nimport type { ComputedStyle } from \"../style/compute.ts\";\nimport { maxCornerRadius } from \"./clip.ts\";\nimport { getBorderRadiusFromStyle } from \"./rect.ts\";\nimport { parseCSSLength, resolveBoxValue } from \"./utils.ts\";\n\n/**\n * CSS `clip-path` support: basic shapes (`inset()`, `circle()`, `ellipse()`,\n * `polygon()`, `path()`, `rect()`, `xywh()`), the newer `shape()` function and\n * an optional geometry box (`border-box`, `padding-box`, `content-box`,\n * `margin-box`). Lengths other than `%` are already resolved to pixels by the\n * style pipeline; percentages resolve against the reference box here.\n *\n * `url(#id)` references and `calc()` are not supported — an unrecognised value\n * leaves the element unclipped, matching how a browser drops an invalid\n * declaration.\n */\n\nexport type FillRule = \"nonzero\" | \"evenodd\";\n\ntype Point = [number, number];\n\n/** Per-corner elliptical radii, in the order tl, tr, br, bl. */\nexport type CornerRadii = [Point, Point, Point, Point];\n\nexport type ReferenceBox = {\n x: number;\n y: number;\n width: number;\n height: number;\n};\n\n/**\n * A resolved clip shape in absolute canvas coordinates.\n */\nexport type ClipShape =\n | { kind: \"none\" }\n | {\n kind: \"rect\";\n x: number;\n y: number;\n width: number;\n height: number;\n radii: CornerRadii | null;\n }\n | { kind: \"circle\"; cx: number; cy: number; r: number }\n | { kind: \"ellipse\"; cx: number; cy: number; rx: number; ry: number }\n | { kind: \"polygon\"; points: Point[]; fillRule: FillRule }\n | { kind: \"path\"; d: string; dx: number; dy: number; fillRule: FillRule };\n\nconst GEOMETRY_BOXES = new Set([\n \"border-box\",\n \"padding-box\",\n \"content-box\",\n \"margin-box\",\n \"fill-box\",\n \"stroke-box\",\n \"view-box\",\n]);\n\nconst H_KEYWORDS = new Map<string, number>([\n [\"left\", 0],\n [\"x-start\", 0],\n [\"center\", 0.5],\n [\"right\", 1],\n [\"x-end\", 1],\n]);\n\nconst V_KEYWORDS = new Map<string, number>([\n [\"top\", 0],\n [\"y-start\", 0],\n [\"center\", 0.5],\n [\"bottom\", 1],\n [\"y-end\", 1],\n]);\n\nconst ARC_OPTIONS = new Set([\"of\", \"cw\", \"ccw\", \"large\", \"small\", \"rotate\"]);\n\n/**\n * Clip the context to the element's `clip-path`. Must be called after the\n * element's transform has been applied (clip-path lives in the element's own\n * coordinate space) and before anything of the element is painted — box-shadow\n * included, since clip-path clips the element's entire rendering.\n */\nexport function applyClipPath(\n ctx: SKRSContext2D,\n clipPath: string,\n style: ComputedStyle,\n x: number,\n y: number,\n width: number,\n height: number,\n): void {\n const shape = parseClipPath(clipPath, style, { x, y, width, height });\n if (!shape || shape.kind === \"none\") return;\n const path = clipShapeToPath(shape);\n if (path) ctx.clip(path, shapeFillRule(shape));\n}\n\nfunction shapeFillRule(shape: ClipShape): FillRule {\n return shape.kind === \"polygon\" || shape.kind === \"path\"\n ? shape.fillRule\n : \"nonzero\";\n}\n\n/**\n * Parse a `clip-path` value into a resolved shape in absolute coordinates.\n * `box` is the element's border box; `style` supplies the border, padding and\n * margin widths used for the other geometry boxes. Returns `null` for values\n * that can't be parsed.\n */\nexport function parseClipPath(\n value: string,\n style: ComputedStyle,\n box: ReferenceBox,\n): ClipShape | null {\n const trimmed = value.trim();\n if (trimmed === \"none\") return { kind: \"none\" };\n\n // Split into an optional shape function and an optional geometry box, in\n // either order: `circle(50%) padding-box` or `padding-box circle(50%)`.\n let fn: { name: string; args: string } | null = null;\n let geometryBox = \"border-box\";\n const fnMatch = trimmed.match(/^(.*?)([a-z]+)\\((.*)\\)(.*)$/s);\n let keywords: string[];\n if (fnMatch) {\n fn = { name: fnMatch[2]!, args: fnMatch[3]! };\n keywords = [fnMatch[1]!, fnMatch[4]!]\n .join(\" \")\n .split(/\\s+/)\n .filter(Boolean);\n } else {\n keywords = trimmed.split(/\\s+/).filter(Boolean);\n }\n for (const kw of keywords) {\n if (!GEOMETRY_BOXES.has(kw)) return null;\n geometryBox = kw;\n }\n if (!fn && keywords.length === 0) return null;\n\n const ref = resolveReferenceBox(geometryBox, style, box);\n const { width: w, height: h } = ref;\n\n if (!fn) {\n // A bare geometry box clips to that box, following the border radius\n // (reduced by the border/padding widths for the inner boxes).\n return {\n kind: \"rect\",\n x: ref.x,\n y: ref.y,\n width: w,\n height: h,\n radii: referenceBoxRadii(geometryBox, style, box, ref),\n };\n }\n\n switch (fn.name) {\n case \"inset\":\n return parseInset(fn.args, ref);\n case \"rect\":\n return parseRect(fn.args, ref);\n case \"xywh\":\n return parseXywh(fn.args, ref);\n case \"circle\":\n return parseCircle(fn.args, ref);\n case \"ellipse\":\n return parseEllipse(fn.args, ref);\n case \"polygon\":\n return parsePolygon(fn.args, ref);\n case \"path\":\n return parsePath(fn.args, ref);\n case \"shape\":\n return parseShape(fn.args, ref);\n default:\n return null;\n }\n}\n\n/**\n * Build a `Path2D` for a resolved clip shape. Returns `null` when the shape\n * is a `path()` whose data Skia cannot parse — treated like an invalid\n * declaration (the element is left unclipped) rather than a render failure.\n */\nexport function clipShapeToPath(shape: ClipShape): Path2D | null {\n const p = new Path2D();\n switch (shape.kind) {\n case \"none\":\n break;\n case \"rect\":\n if (shape.radii && shape.width > 0 && shape.height > 0) {\n roundedRectPath(\n p,\n shape.x,\n shape.y,\n shape.width,\n shape.height,\n shape.radii,\n );\n } else {\n p.rect(\n shape.x,\n shape.y,\n Math.max(0, shape.width),\n Math.max(0, shape.height),\n );\n }\n break;\n case \"circle\":\n if (shape.r > 0) p.arc(shape.cx, shape.cy, shape.r, 0, Math.PI * 2);\n break;\n case \"ellipse\":\n if (shape.rx > 0 && shape.ry > 0) {\n p.ellipse(shape.cx, shape.cy, shape.rx, shape.ry, 0, 0, Math.PI * 2);\n }\n break;\n case \"polygon\":\n if (shape.points.length >= 3) {\n const [first, ...rest] = shape.points;\n p.moveTo(first![0], first![1]);\n for (const [px, py] of rest) p.lineTo(px, py);\n p.closePath();\n }\n break;\n case \"path\": {\n let inner: Path2D;\n try {\n inner = new Path2D(shape.d);\n } catch {\n return null;\n }\n if (shape.dx === 0 && shape.dy === 0) return inner;\n p.addPath(inner, { a: 1, b: 0, c: 0, d: 1, e: shape.dx, f: shape.dy });\n break;\n }\n }\n return p;\n}\n\n// ---------------------------------------------------------------------------\n// Reference boxes\n// ---------------------------------------------------------------------------\n\nfunction resolveReferenceBox(\n geometryBox: string,\n style: ComputedStyle,\n box: ReferenceBox,\n): ReferenceBox {\n const { x, y, width, height } = box;\n switch (geometryBox) {\n case \"padding-box\": {\n const t = resolveBoxValue(style.borderTopWidth, width);\n const r = resolveBoxValue(style.borderRightWidth, width);\n const b = resolveBoxValue(style.borderBottomWidth, width);\n const l = resolveBoxValue(style.borderLeftWidth, width);\n return {\n x: x + l,\n y: y + t,\n width: width - l - r,\n height: height - t - b,\n };\n }\n case \"content-box\": {\n const t =\n resolveBoxValue(style.borderTopWidth, width) +\n resolveBoxValue(style.paddingTop, width);\n const r =\n resolveBoxValue(style.borderRightWidth, width) +\n resolveBoxValue(style.paddingRight, width);\n const b =\n resolveBoxValue(style.borderBottomWidth, width) +\n resolveBoxValue(style.paddingBottom, width);\n const l =\n resolveBoxValue(style.borderLeftWidth, width) +\n resolveBoxValue(style.paddingLeft, width);\n return {\n x: x + l,\n y: y + t,\n width: width - l - r,\n height: height - t - b,\n };\n }\n case \"margin-box\": {\n const t = marginValue(style.marginTop, width);\n const r = marginValue(style.marginRight, width);\n const b = marginValue(style.marginBottom, width);\n const l = marginValue(style.marginLeft, width);\n return {\n x: x - l,\n y: y - t,\n width: width + l + r,\n height: height + t + b,\n };\n }\n default:\n return box;\n }\n}\n\nfunction marginValue(v: unknown, referenceWidth: number): number {\n if (v === \"auto\") return 0;\n return resolveBoxValue(v, referenceWidth);\n}\n\n/**\n * Border radii of a geometry box: the element's border-radius for the border\n * box (and margin box, grown by the margin), reduced by the border and padding\n * widths for the inner boxes. Returns `null` when every corner is square.\n *\n * The base radii are clamped the way the element's own corners are painted\n * (see `maxCornerRadius`) so a bare `border-box` clip traces exactly the\n * painted rounded corner instead of a different arc.\n */\nfunction referenceBoxRadii(\n geometryBox: string,\n style: ComputedStyle,\n box: ReferenceBox,\n ref: ReferenceBox,\n): CornerRadii | null {\n const br = getBorderRadiusFromStyle(style, box.width, box.height);\n const maxR = maxCornerRadius(box.width, box.height);\n const base = [br.topLeft, br.topRight, br.bottomRight, br.bottomLeft].map(\n (r) => Math.min(Math.max(0, r), maxR),\n ) as [number, number, number, number];\n if (base.every((r) => r <= 0)) return null;\n\n // Horizontal / vertical insets from the border box to the reference box, per\n // corner: (left, top), (right, top), (right, bottom), (left, bottom).\n const left = ref.x - box.x;\n const top = ref.y - box.y;\n const right = box.x + box.width - (ref.x + ref.width);\n const bottom = box.y + box.height - (ref.y + ref.height);\n const insets: [Point, Point, Point, Point] = [\n [left, top],\n [right, top],\n [right, bottom],\n [left, bottom],\n ];\n\n const radii = base.map((r, i) => {\n const [ix, iy] = insets[i]!;\n return [adjustRadius(r, ix), adjustRadius(r, iy)] as Point;\n }) as CornerRadii;\n if (radii.every(([rx, ry]) => rx <= 0 || ry <= 0)) return null;\n return normalizeRadii(radii, ref.width, ref.height);\n}\n\n/**\n * Move a border radius inward by `inset` (CSS Backgrounds: the inner radius\n * is the outer one minus the border, floored at zero) or, for a negative\n * inset, outward (CSS Shapes `margin-box`: a square corner stays square, a\n * radius `r >= m` grows to `r + m`, and a smaller one is eased between the\n * two so the corner keeps its shape).\n */\nfunction adjustRadius(r: number, inset: number): number {\n if (inset >= 0) return Math.max(0, r - inset);\n if (r <= 0) return 0;\n const m = -inset;\n if (r >= m) return r + m;\n const ratio = r / m - 1;\n return r + m * (1 + ratio * ratio * ratio);\n}\n\n// ---------------------------------------------------------------------------\n// Basic shapes\n// ---------------------------------------------------------------------------\n\nfunction parseInset(args: string, ref: ReferenceBox): ClipShape | null {\n const [insetPart, roundPart] = splitRound(args);\n const values = tokenize(insetPart);\n if (values.length < 1 || values.length > 4) return null;\n const [t, r, b, l] = expandSides(values);\n const top = parseCSSLength(t, ref.height);\n const right = parseCSSLength(r, ref.width);\n const bottom = parseCSSLength(b, ref.height);\n const left = parseCSSLength(l, ref.width);\n if ([top, right, bottom, left].some(isNaN)) return null;\n return makeRect(\n ref.x + left,\n ref.y + top,\n ref.width - left - right,\n ref.height - top - bottom,\n roundPart,\n ref,\n );\n}\n\nfunction parseRect(args: string, ref: ReferenceBox): ClipShape | null {\n const [rectPart, roundPart] = splitRound(args);\n const values = tokenize(rectPart);\n if (values.length !== 4) return null;\n const [t, r, b, l] = values as [string, string, string, string];\n const top = t === \"auto\" ? 0 : parseCSSLength(t, ref.height);\n const right = r === \"auto\" ? ref.width : parseCSSLength(r, ref.width);\n const bottom = b === \"auto\" ? ref.height : parseCSSLength(b, ref.height);\n const left = l === \"auto\" ? 0 : parseCSSLength(l, ref.width);\n if ([top, right, bottom, left].some(isNaN)) return null;\n // Per spec, right/bottom are clamped so they never precede left/top.\n const x2 = Math.max(left, right);\n const y2 = Math.max(top, bottom);\n return makeRect(\n ref.x + left,\n ref.y + top,\n x2 - left,\n y2 - top,\n roundPart,\n ref,\n );\n}\n\nfunction parseXywh(args: string, ref: ReferenceBox): ClipShape | null {\n const [xywhPart, roundPart] = splitRound(args);\n const values = tokenize(xywhPart);\n if (values.length !== 4) return null;\n const [xs, ys, ws, hs] = values as [string, string, string, string];\n const x = parseCSSLength(xs, ref.width);\n const y = parseCSSLength(ys, ref.height);\n const w = parseCSSLength(ws, ref.width);\n const h = parseCSSLength(hs, ref.height);\n if ([x, y, w, h].some(isNaN)) return null;\n return makeRect(\n ref.x + x,\n ref.y + y,\n Math.max(0, w),\n Math.max(0, h),\n roundPart,\n ref,\n );\n}\n\n/**\n * Build a rect shape with optional `round` radii. Percentage radii resolve\n * against the reference box (CSS Shapes 1 §3), not the rectangle itself.\n */\nfunction makeRect(\n x: number,\n y: number,\n width: number,\n height: number,\n roundPart: string | undefined,\n ref: ReferenceBox,\n): ClipShape | null {\n const w = Math.max(0, width);\n const h = Math.max(0, height);\n let radii: CornerRadii | null = null;\n if (roundPart !== undefined) {\n const parsed = parseRadii(roundPart, ref.width, ref.height, w, h);\n if (parsed === undefined) return null;\n radii = parsed;\n }\n return { kind: \"rect\", x, y, width: w, height: h, radii };\n}\n\nfunction parseCircle(args: string, ref: ReferenceBox): ClipShape | null {\n const [radiusPart, posPart] = splitAt(args);\n const radiusTokens = tokenize(radiusPart);\n if (radiusTokens.length > 1) return null;\n const pos = resolvePosition(tokenize(posPart ?? \"\"), ref.width, ref.height);\n if (!pos) return null;\n const [cx, cy] = pos;\n const closest = Math.min(cx, cy, ref.width - cx, ref.height - cy);\n const farthest = Math.max(cx, cy, ref.width - cx, ref.height - cy);\n const percentBase = Math.hypot(ref.width, ref.height) / Math.SQRT2;\n const r = resolveRadius(radiusTokens[0], closest, farthest, percentBase);\n if (r === undefined) return null;\n return { kind: \"circle\", cx: ref.x + cx, cy: ref.y + cy, r: Math.max(0, r) };\n}\n\nfunction parseEllipse(args: string, ref: ReferenceBox): ClipShape | null {\n const [radiusPart, posPart] = splitAt(args);\n const radiusTokens = tokenize(radiusPart);\n if (radiusTokens.length !== 0 && radiusTokens.length !== 2) return null;\n const pos = resolvePosition(tokenize(posPart ?? \"\"), ref.width, ref.height);\n if (!pos) return null;\n const [cx, cy] = pos;\n const rx = resolveRadius(\n radiusTokens[0],\n Math.min(cx, ref.width - cx),\n Math.max(cx, ref.width - cx),\n ref.width,\n );\n const ry = resolveRadius(\n radiusTokens[1],\n Math.min(cy, ref.height - cy),\n Math.max(cy, ref.height - cy),\n ref.height,\n );\n if (rx === undefined || ry === undefined) return null;\n return {\n kind: \"ellipse\",\n cx: ref.x + cx,\n cy: ref.y + cy,\n rx: Math.max(0, rx),\n ry: Math.max(0, ry),\n };\n}\n\nfunction parsePolygon(args: string, ref: ReferenceBox): ClipShape | null {\n const parts = splitArgs(args);\n let fillRule: FillRule = \"nonzero\";\n const first = parts[0]?.trim();\n if (first === \"nonzero\" || first === \"evenodd\") {\n fillRule = first;\n parts.shift();\n }\n const points: Point[] = [];\n for (const part of parts) {\n const pair = tokenize(part);\n if (pair.length !== 2) return null;\n const px = parseCSSLength(pair[0]!, ref.width);\n const py = parseCSSLength(pair[1]!, ref.height);\n if (isNaN(px) || isNaN(py)) return null;\n points.push([ref.x + px, ref.y + py]);\n }\n if (points.length === 0) return null;\n return { kind: \"polygon\", points, fillRule };\n}\n\nfunction parsePath(args: string, ref: ReferenceBox): ClipShape | null {\n const parts = splitArgs(args);\n let fillRule: FillRule = \"nonzero\";\n const first = parts[0]?.trim();\n if (first === \"nonzero\" || first === \"evenodd\") {\n fillRule = first;\n parts.shift();\n }\n if (parts.length !== 1) return null;\n const d = unquote(parts[0]!.trim());\n if (!d) return null;\n return { kind: \"path\", d, dx: ref.x, dy: ref.y, fillRule };\n}\n\n// ---------------------------------------------------------------------------\n// shape()\n// ---------------------------------------------------------------------------\n\n/**\n * Parse the `shape()` function into SVG path data. Coordinates are resolved\n * against the reference box; the resulting path is positioned at the box\n * origin via `dx`/`dy`.\n *\n * Grammar (CSS Shapes 2): `shape([<fill-rule>]? from <x> <y>, <command>#)`\n * with commands `move`, `line`, `hline`, `vline`, `curve`, `smooth`, `arc`\n * and `close`, each using `to` (absolute) or `by` (relative to the current\n * point).\n */\nfunction parseShape(args: string, ref: ReferenceBox): ClipShape | null {\n const { width: w, height: h } = ref;\n const parts = splitArgs(args);\n const first = parts.shift()?.trim();\n if (!first) return null;\n\n const startMatch = first.match(/^(?:(nonzero|evenodd)\\s+)?from\\s+(.+)$/s);\n if (!startMatch) return null;\n const fillRule = (startMatch[1] ?? \"nonzero\") as FillRule;\n\n let current = resolvePoint(tokenize(startMatch[2]!), w, h);\n if (!current) return null;\n let subpathStart = current;\n let d = `M${fmtPoint(current)}`;\n\n for (const part of parts) {\n const tokens = tokenize(part);\n const command = tokens.shift();\n\n switch (command) {\n case \"close\": {\n if (tokens.length) return null;\n d += \" Z\";\n current = subpathStart;\n break;\n }\n case \"move\":\n case \"line\": {\n const end = resolveEndpoint(tokens, current, w, h);\n if (!end) return null;\n d += ` ${command === \"move\" ? \"M\" : \"L\"}${fmtPoint(end)}`;\n current = end;\n if (command === \"move\") subpathStart = end;\n break;\n }\n case \"hline\":\n case \"vline\": {\n const [mode, token, ...rest] = tokens;\n if ((mode !== \"to\" && mode !== \"by\") || !token || rest.length) {\n return null;\n }\n const axis = command === \"hline\" ? 0 : 1;\n const base = axis === 0 ? w : h;\n const keywords = axis === 0 ? H_KEYWORDS : V_KEYWORDS;\n const kw = keywords.get(token);\n const resolved =\n mode === \"to\" && kw !== undefined\n ? kw * base\n : parseCSSLength(token, base);\n if (isNaN(resolved)) return null;\n const next: Point = [current[0], current[1]];\n next[axis] = mode === \"by\" ? current[axis] + resolved : resolved;\n d += axis === 0 ? ` H${fmt(next[0])}` : ` V${fmt(next[1])}`;\n current = next;\n break;\n }\n case \"curve\":\n case \"smooth\": {\n const withIndex = tokens.indexOf(\"with\");\n const endTokens =\n withIndex === -1 ? tokens : tokens.slice(0, withIndex);\n const controlTokens =\n withIndex === -1 ? [] : tokens.slice(withIndex + 1);\n const mode = endTokens[0];\n const end = resolveEndpoint(endTokens, current, w, h);\n if (!end) return null;\n if (command === \"curve\" && withIndex === -1) return null;\n\n const controls: Point[] = [];\n for (const control of splitAtSlash(controlTokens)) {\n const point = resolveControlPoint(control, mode, current, end, w, h);\n if (!point) return null;\n controls.push(point);\n }\n\n if (command === \"curve\") {\n if (controls.length === 1) {\n d += ` Q${fmtPoint(controls[0]!)} ${fmtPoint(end)}`;\n } else if (controls.length === 2) {\n d += ` C${fmtPoint(controls[0]!)} ${fmtPoint(controls[1]!)} ${fmtPoint(end)}`;\n } else {\n return null;\n }\n } else if (controls.length === 0) {\n d += ` T${fmtPoint(end)}`;\n } else if (controls.length === 1) {\n d += ` S${fmtPoint(controls[0]!)} ${fmtPoint(end)}`;\n } else {\n return null;\n }\n current = end;\n break;\n }\n case \"arc\": {\n const optionIndex = tokens.findIndex((t) => ARC_OPTIONS.has(t));\n const endTokens =\n optionIndex === -1 ? tokens : tokens.slice(0, optionIndex);\n const options = optionIndex === -1 ? [] : tokens.slice(optionIndex);\n const end = resolveEndpoint(endTokens, current, w, h);\n if (!end) return null;\n\n let rx = 0;\n let ry = 0;\n let rotation = 0;\n let large = 0;\n let sweep = 0;\n for (let i = 0; i < options.length; i++) {\n const option = options[i]!;\n if (option === \"of\") {\n const r1 = options[++i];\n if (!r1) return null;\n const r2 = options[i + 1];\n const hasSecond = r2 !== undefined && !ARC_OPTIONS.has(r2);\n if (hasSecond) {\n i++;\n rx = parseCSSLength(r1, w);\n ry = parseCSSLength(r2!, h);\n } else {\n rx = ry = parseCSSLength(r1, Math.hypot(w, h) / Math.SQRT2);\n }\n if (isNaN(rx) || isNaN(ry)) return null;\n } else if (option === \"cw\" || option === \"ccw\") {\n sweep = option === \"cw\" ? 1 : 0;\n } else if (option === \"large\" || option === \"small\") {\n large = option === \"large\" ? 1 : 0;\n } else if (option === \"rotate\") {\n const angle = options[++i];\n if (!angle) return null;\n rotation = parseAngleDegrees(angle);\n if (isNaN(rotation)) return null;\n } else {\n return null;\n }\n }\n d += ` A${fmt(Math.abs(rx))} ${fmt(Math.abs(ry))} ${fmt(rotation)} ${large} ${sweep} ${fmtPoint(end)}`;\n current = end;\n break;\n }\n default:\n return null;\n }\n }\n\n return { kind: \"path\", d, dx: ref.x, dy: ref.y, fillRule };\n}\n\nfunction resolveEndpoint(\n tokens: string[],\n current: Point,\n w: number,\n h: number,\n): Point | null {\n const mode = tokens[0];\n if (mode !== \"to\" && mode !== \"by\") return null;\n const point = resolvePoint(tokens.slice(1), w, h);\n if (!point) return null;\n return mode === \"by\" ? [current[0] + point[0], current[1] + point[1]] : point;\n}\n\n/**\n * A control point: `<x> <y> [from start | end | origin]?`. Without `from`,\n * `by` commands measure from the segment start and `to` commands from the\n * reference box origin.\n */\nfunction resolveControlPoint(\n tokens: string[],\n mode: string | undefined,\n start: Point,\n end: Point,\n w: number,\n h: number,\n): Point | null {\n let origin: \"start\" | \"end\" | \"origin\" = mode === \"by\" ? \"start\" : \"origin\";\n let coords = tokens;\n const fromIndex = tokens.indexOf(\"from\");\n if (fromIndex !== -1) {\n const ref = tokens[fromIndex + 1];\n if (\n (ref !== \"start\" && ref !== \"end\" && ref !== \"origin\") ||\n tokens.length !== fromIndex + 2\n ) {\n return null;\n }\n origin = ref;\n coords = tokens.slice(0, fromIndex);\n }\n const point = resolvePoint(coords, w, h);\n if (!point) return null;\n const base: Point =\n origin === \"start\" ? start : origin === \"end\" ? end : [0, 0];\n return [base[0] + point[0], base[1] + point[1]];\n}\n\n/** Resolve a `<coordinate-pair>` (lengths, percentages or position keywords). */\nfunction resolvePoint(tokens: string[], w: number, h: number): Point | null {\n if (tokens.length !== 2) return null;\n const x = resolveAxis(tokens[0]!, w, H_KEYWORDS);\n const y = resolveAxis(tokens[1]!, h, V_KEYWORDS);\n if (isNaN(x) || isNaN(y)) return null;\n return [x, y];\n}\n\n// ---------------------------------------------------------------------------\n// Shared helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve a CSS `<position>` (as used after `at`) to a point relative to the\n * reference box. Defaults to the center.\n */\nfunction resolvePosition(tokens: string[], w: number, h: number): Point | null {\n if (tokens.length === 0) return [w / 2, h / 2];\n\n if (tokens.length === 1) {\n const t = tokens[0]!;\n if (V_KEYWORDS.has(t) && !H_KEYWORDS.has(t)) {\n return [w / 2, V_KEYWORDS.get(t)! * h];\n }\n const x = resolveAxis(t, w, H_KEYWORDS);\n return isNaN(x) ? null : [x, h / 2];\n }\n\n if (tokens.length === 2) {\n let [a, b] = tokens as [string, string];\n // Two keywords may come in either order (\"top left\" == \"left top\"); with\n // a length in the pair the order is fixed, so \"top 30px\" is invalid and\n // falls through to the NaN check below.\n const bothKeywords =\n (H_KEYWORDS.has(a) || V_KEYWORDS.has(a)) &&\n (H_KEYWORDS.has(b) || V_KEYWORDS.has(b));\n if (\n bothKeywords &&\n ((V_KEYWORDS.has(a) && !H_KEYWORDS.has(a)) ||\n (H_KEYWORDS.has(b) && !V_KEYWORDS.has(b)))\n ) {\n [a, b] = [b, a];\n }\n const x = resolveAxis(a, w, H_KEYWORDS);\n const y = resolveAxis(b, h, V_KEYWORDS);\n return isNaN(x) || isNaN(y) ? null : [x, y];\n }\n\n // 3–4 tokens: edge keywords with optional offsets, e.g. \"right 10px bottom 20px\".\n let x = w / 2;\n let y = h / 2;\n for (let i = 0; i < tokens.length; i++) {\n const t = tokens[i]!;\n const next = tokens[i + 1];\n const hasOffset =\n next !== undefined && !H_KEYWORDS.has(next) && !V_KEYWORDS.has(next);\n if (t === \"left\" || t === \"right\") {\n const off = hasOffset ? parseCSSLength(next!, w) : 0;\n if (isNaN(off)) return null;\n x = t === \"left\" ? off : w - off;\n } else if (t === \"top\" || t === \"bottom\") {\n const off = hasOffset ? parseCSSLength(next!, h) : 0;\n if (isNaN(off)) return null;\n y = t === \"top\" ? off : h - off;\n } else if (t !== \"center\") {\n return null;\n }\n if (hasOffset) i++;\n }\n return [x, y];\n}\n\nfunction resolveAxis(\n token: string,\n size: number,\n keywords: Map<string, number>,\n): number {\n const kw = keywords.get(token);\n if (kw !== undefined) return kw * size;\n return parseCSSLength(token, size);\n}\n\nfunction resolveRadius(\n token: string | undefined,\n closestSide: number,\n farthestSide: number,\n percentBase: number,\n): number | undefined {\n if (token === undefined || token === \"closest-side\") return closestSide;\n if (token === \"farthest-side\") return farthestSide;\n const r = parseCSSLength(token, percentBase);\n return isNaN(r) ? undefined : r;\n}\n\n/**\n * Parse `border-radius`-style radii (`r1 r2 r3 r4 / v1 v2 v3 v4`) into\n * per-corner elliptical radii. Percentages resolve against `refW` × `refH`;\n * the result is scaled down per the CSS overlap rule for a `w` × `h` box.\n * Returns `undefined` for unparsable input and `null` when all corners are\n * square.\n */\nfunction parseRadii(\n value: string,\n refW: number,\n refH: number,\n w: number,\n h: number,\n): CornerRadii | null | undefined {\n const [hPart, vPart] = value.split(\"/\");\n const hTokens = tokenize(hPart ?? \"\");\n const vTokens = vPart === undefined ? hTokens : tokenize(vPart);\n if (\n hTokens.length < 1 ||\n hTokens.length > 4 ||\n vTokens.length < 1 ||\n vTokens.length > 4\n ) {\n return undefined;\n }\n const hs = expandSides(hTokens).map((t) => parseCSSLength(t, refW));\n const vs = expandSides(vTokens).map((t) => parseCSSLength(t, refH));\n if ([...hs, ...vs].some(isNaN)) return undefined;\n const radii = hs.map((rx, i) => [\n Math.max(0, rx),\n Math.max(0, vs[i]!),\n ]) as CornerRadii;\n if (radii.every(([rx, ry]) => rx <= 0 || ry <= 0)) return null;\n return normalizeRadii(radii, w, h);\n}\n\n/**\n * CSS border-radius overlap rule: if adjacent radii along any side sum to more\n * than that side's length, scale every radius by the same factor.\n */\nfunction normalizeRadii(radii: CornerRadii, w: number, h: number): CornerRadii {\n const [tl, tr, br, bl] = radii;\n let f = 1;\n const consider = (sum: number, length: number) => {\n if (sum > 0 && length / sum < f) f = length / sum;\n };\n consider(tl[0] + tr[0], w);\n consider(bl[0] + br[0], w);\n consider(tl[1] + bl[1], h);\n consider(tr[1] + br[1], h);\n if (f >= 1) return radii;\n return radii.map(([rx, ry]) => [rx * f, ry * f]) as CornerRadii;\n}\n\n/**\n * Append a rounded rectangle with per-corner elliptical radii to a path.\n */\nfunction roundedRectPath(\n p: Path2D,\n x: number,\n y: number,\n w: number,\n h: number,\n radii: CornerRadii,\n): void {\n const [tl, tr, br, bl] = radii;\n const round = (r: Point) => r[0] > 0 && r[1] > 0;\n const HALF = Math.PI / 2;\n\n p.moveTo(x + (round(tl) ? tl[0] : 0), y);\n p.lineTo(x + w - (round(tr) ? tr[0] : 0), y);\n if (round(tr)) {\n p.ellipse(x + w - tr[0], y + tr[1], tr[0], tr[1], 0, -HALF, 0);\n }\n p.lineTo(x + w, y + h - (round(br) ? br[1] : 0));\n if (round(br)) {\n p.ellipse(x + w - br[0], y + h - br[1], br[0], br[1], 0, 0, HALF);\n }\n p.lineTo(x + (round(bl) ? bl[0] : 0), y + h);\n if (round(bl)) {\n p.ellipse(x + bl[0], y + h - bl[1], bl[0], bl[1], 0, HALF, Math.PI);\n }\n p.lineTo(x, y + (round(tl) ? tl[1] : 0));\n if (round(tl)) {\n p.ellipse(x + tl[0], y + tl[1], tl[0], tl[1], 0, Math.PI, 3 * HALF);\n }\n p.closePath();\n}\n\nfunction expandSides(values: string[]): [string, string, string, string] {\n const [a, b, c, d] = values;\n switch (values.length) {\n case 1:\n return [a!, a!, a!, a!];\n case 2:\n return [a!, b!, a!, b!];\n case 3:\n return [a!, b!, c!, b!];\n default:\n return [a!, b!, c!, d!];\n }\n}\n\n/** Split `... round <radii>` into the shape part and the optional radii part. */\nfunction splitRound(args: string): [string, string | undefined] {\n const m = args.match(/^(.*?)\\bround\\b(.*)$/s);\n if (!m) return [args, undefined];\n return [m[1]!, m[2]!];\n}\n\n/** Split `<radius> at <position>` into the radius part and the position part. */\nfunction splitAt(args: string): [string, string | undefined] {\n const m = args.match(/^(.*?)\\bat\\b(.*)$/s);\n if (!m) return [args, undefined];\n return [m[1]!, m[2]!];\n}\n\n/** Split on top-level commas, respecting parentheses and quoted strings. */\nfunction splitArgs(content: string): string[] {\n const parts: string[] = [];\n let current = \"\";\n let depth = 0;\n let quote: string | null = null;\n for (const char of content) {\n if (quote) {\n if (char === quote) quote = null;\n current += char;\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n current += char;\n continue;\n }\n if (char === \"(\") depth++;\n if (char === \")\") depth--;\n if (char === \",\" && depth === 0) {\n parts.push(current);\n current = \"\";\n } else {\n current += char;\n }\n }\n if (current.trim()) parts.push(current);\n return parts;\n}\n\nfunction splitAtSlash(tokens: string[]): string[][] {\n if (tokens.length === 0) return [];\n const slash = tokens.indexOf(\"/\");\n return slash === -1\n ? [tokens]\n : [tokens.slice(0, slash), tokens.slice(slash + 1)];\n}\n\nfunction tokenize(value: string): string[] {\n return value.trim().replace(/\\//g, \" / \").split(/\\s+/).filter(Boolean);\n}\n\nfunction unquote(s: string): string {\n if (\n s.length >= 2 &&\n ((s.startsWith('\"') && s.endsWith('\"')) ||\n (s.startsWith(\"'\") && s.endsWith(\"'\")))\n ) {\n return s.slice(1, -1);\n }\n return s;\n}\n\nfunction parseAngleDegrees(value: string): number {\n const n = parseFloat(value);\n if (isNaN(n)) return NaN;\n if (value.endsWith(\"deg\")) return n;\n if (value.endsWith(\"grad\")) return n * 0.9;\n if (value.endsWith(\"rad\")) return (n * 180) / Math.PI;\n if (value.endsWith(\"turn\")) return n * 360;\n return n;\n}\n\nfunction fmt(n: number): string {\n return String(Math.round(n * 1000) / 1000);\n}\n\nfunction fmtPoint(p: Point): string {\n return `${fmt(p[0])} ${fmt(p[1])}`;\n}\n","import type { SKRSContext2D } from \"@effing/skia\";\n\nimport type { ComputedStyle } from \"../style/compute.ts\";\nimport { hasRadius, maxCornerRadius, roundedRect } from \"./clip.ts\";\nimport type { Shadow } from \"./shadow.ts\";\nimport { parseCSSLength, toNumber, resolveBoxValue } from \"./utils.ts\";\n\n/**\n * Draw the background, borders, and box-shadow for a rectangular element.\n */\nexport function drawRect(\n ctx: SKRSContext2D,\n x: number,\n y: number,\n width: number,\n height: number,\n style: ComputedStyle,\n): void {\n const borderRadius = getBorderRadiusFromStyle(style, width, height);\n const hasRoundedCorners = hasRadius(borderRadius);\n\n // Background\n if (style.backgroundColor) {\n ctx.fillStyle = style.backgroundColor;\n\n if (hasRoundedCorners) {\n ctx.beginPath();\n roundedRect(\n ctx,\n x,\n y,\n width,\n height,\n borderRadius.topLeft,\n borderRadius.topRight,\n borderRadius.bottomRight,\n borderRadius.bottomLeft,\n );\n ctx.fill();\n } else {\n ctx.fillRect(x, y, width, height);\n }\n }\n\n // Borders\n drawBorders(ctx, x, y, width, height, style, borderRadius);\n}\n\nfunction resolveRadius(v: unknown, width: number, height: number): number {\n if (typeof v === \"string\") return parseCSSLength(v, Math.min(width, height));\n return toNumber(v);\n}\n\nexport function getBorderRadiusFromStyle(\n style: ComputedStyle,\n width: number,\n height: number,\n) {\n return {\n topLeft: resolveRadius(style.borderTopLeftRadius, width, height),\n topRight: resolveRadius(style.borderTopRightRadius, width, height),\n bottomRight: resolveRadius(style.borderBottomRightRadius, width, height),\n bottomLeft: resolveRadius(style.borderBottomLeftRadius, width, height),\n };\n}\n\nfunction drawBorders(\n ctx: SKRSContext2D,\n x: number,\n y: number,\n width: number,\n height: number,\n style: ComputedStyle,\n borderRadius: ReturnType<typeof getBorderRadiusFromStyle>,\n): void {\n const hasRoundedCorners = hasRadius(borderRadius);\n\n // If all borders are the same, draw as a single stroke\n const tw = resolveBoxValue(style.borderTopWidth, width);\n const rw = resolveBoxValue(style.borderRightWidth, width);\n const bw = resolveBoxValue(style.borderBottomWidth, width);\n const lw = resolveBoxValue(style.borderLeftWidth, width);\n\n if (tw === 0 && rw === 0 && bw === 0 && lw === 0) return;\n\n const allSameWidth = tw === rw && rw === bw && bw === lw && tw > 0;\n const tc = style.borderTopColor ?? \"black\";\n const rc = style.borderRightColor ?? \"black\";\n const bc = style.borderBottomColor ?? \"black\";\n const lc = style.borderLeftColor ?? \"black\";\n const allSameColor = tc === rc && rc === bc && bc === lc;\n\n if (allSameWidth && allSameColor) {\n ctx.strokeStyle = tc;\n ctx.lineWidth = tw;\n\n if (hasRoundedCorners) {\n ctx.beginPath();\n const half = tw / 2;\n roundedRect(\n ctx,\n x + half,\n y + half,\n width - tw,\n height - tw,\n Math.max(0, borderRadius.topLeft - half),\n Math.max(0, borderRadius.topRight - half),\n Math.max(0, borderRadius.bottomRight - half),\n Math.max(0, borderRadius.bottomLeft - half),\n );\n ctx.stroke();\n } else {\n ctx.strokeRect(x + tw / 2, y + tw / 2, width - tw, height - tw);\n }\n return;\n }\n\n // Draw individual borders\n if (hasRoundedCorners) {\n const maxR = Math.min(width, height) / 2;\n const tl = Math.min(borderRadius.topLeft, maxR);\n const tr = Math.min(borderRadius.topRight, maxR);\n const br = Math.min(borderRadius.bottomRight, maxR);\n const bl = Math.min(borderRadius.bottomLeft, maxR);\n\n const top = y + tw / 2;\n const right = x + width - rw / 2;\n const bottom = y + height - bw / 2;\n const left = x + lw / 2;\n\n const eTL = Math.max(0, tl - Math.max(tw, lw) / 2);\n const eTR = Math.max(0, tr - Math.max(tw, rw) / 2);\n const eBR = Math.max(0, br - Math.max(bw, rw) / 2);\n const eBL = Math.max(0, bl - Math.max(bw, lw) / 2);\n\n // Each side owns its end corner (in drawing direction) and only draws the\n // start corner arc when the adjacent owner side is not visible (width 0).\n // This prevents double-stroking of corner arcs which causes AA artifacts.\n\n // Top side (L → R): borrows TL, owns TR\n if (tw > 0) {\n ctx.strokeStyle = tc;\n ctx.lineWidth = tw;\n ctx.beginPath();\n if (eTL > 0 && lw === 0) {\n ctx.moveTo(left, top + eTL);\n ctx.arcTo(left, top, left + eTL, top, eTL);\n } else if (eTL > 0) {\n ctx.moveTo(left + eTL, top);\n } else {\n ctx.moveTo(x, top);\n }\n if (eTR > 0) {\n ctx.lineTo(right - eTR, top);\n ctx.arcTo(right, top, right, top + eTR, eTR);\n } else {\n ctx.lineTo(x + width, top);\n }\n ctx.stroke();\n }\n\n // Right side (T → B): borrows TR, owns BR\n if (rw > 0) {\n ctx.strokeStyle = rc;\n ctx.lineWidth = rw;\n ctx.beginPath();\n if (eTR > 0 && tw === 0) {\n ctx.moveTo(right - eTR, top);\n ctx.arcTo(right, top, right, top + eTR, eTR);\n } else if (eTR > 0) {\n ctx.moveTo(right, top + eTR);\n } else {\n ctx.moveTo(right, y);\n }\n if (eBR > 0) {\n ctx.lineTo(right, bottom - eBR);\n ctx.arcTo(right, bottom, right - eBR, bottom, eBR);\n } else {\n ctx.lineTo(right, y + height);\n }\n ctx.stroke();\n }\n\n // Bottom side (R → L): borrows BR, owns BL\n if (bw > 0) {\n ctx.strokeStyle = bc;\n ctx.lineWidth = bw;\n ctx.beginPath();\n if (eBR > 0 && rw === 0) {\n ctx.moveTo(right, bottom - eBR);\n ctx.arcTo(right, bottom, right - eBR, bottom, eBR);\n } else if (eBR > 0) {\n ctx.moveTo(right - eBR, bottom);\n } else {\n ctx.moveTo(x + width, bottom);\n }\n if (eBL > 0) {\n ctx.lineTo(left + eBL, bottom);\n ctx.arcTo(left, bottom, left, bottom - eBL, eBL);\n } else {\n ctx.lineTo(x, bottom);\n }\n ctx.stroke();\n }\n\n // Left side (B → T): borrows BL, owns TL\n if (lw > 0) {\n ctx.strokeStyle = lc;\n ctx.lineWidth = lw;\n ctx.beginPath();\n if (eBL > 0 && bw === 0) {\n ctx.moveTo(left + eBL, bottom);\n ctx.arcTo(left, bottom, left, bottom - eBL, eBL);\n } else if (eBL > 0) {\n ctx.moveTo(left, bottom - eBL);\n } else {\n ctx.moveTo(left, y + height);\n }\n if (eTL > 0) {\n ctx.lineTo(left, top + eTL);\n ctx.arcTo(left, top, left + eTL, top, eTL);\n } else {\n ctx.lineTo(left, y);\n }\n ctx.stroke();\n }\n } else {\n if (tw > 0) {\n ctx.strokeStyle = tc;\n ctx.lineWidth = tw;\n ctx.beginPath();\n ctx.moveTo(x, y + tw / 2);\n ctx.lineTo(x + width, y + tw / 2);\n ctx.stroke();\n }\n if (rw > 0) {\n ctx.strokeStyle = rc;\n ctx.lineWidth = rw;\n ctx.beginPath();\n ctx.moveTo(x + width - rw / 2, y);\n ctx.lineTo(x + width - rw / 2, y + height);\n ctx.stroke();\n }\n if (bw > 0) {\n ctx.strokeStyle = bc;\n ctx.lineWidth = bw;\n ctx.beginPath();\n ctx.moveTo(x, y + height - bw / 2);\n ctx.lineTo(x + width, y + height - bw / 2);\n ctx.stroke();\n }\n if (lw > 0) {\n ctx.strokeStyle = lc;\n ctx.lineWidth = lw;\n ctx.beginPath();\n ctx.moveTo(x + lw / 2, y);\n ctx.lineTo(x + lw / 2, y + height);\n ctx.stroke();\n }\n }\n}\n\ntype BorderRadius = ReturnType<typeof getBorderRadiusFromStyle>;\n\n/** A colour no shadow is cast in: what an invalid colour leaves the fill. */\nconst NO_COLOR = \"rgba(0, 0, 0, 0)\";\n\n/**\n * Draw an element's outer box shadows (those not `inset`), back to front:\n * the first listed is on top. Each is the border box grown by its spread\n * (shrunk, when negative), offset and blurred, and only shows outside the\n * border box.\n */\nexport function drawBoxShadow(\n ctx: SKRSContext2D,\n x: number,\n y: number,\n width: number,\n height: number,\n shadows: Shadow[],\n borderRadius: BorderRadius,\n): void {\n const outer = shadows.filter((s) => !s.inset);\n if (outer.length === 0) return;\n const radii = clampRadii(borderRadius, width, height);\n\n // Clip to the area outside the border box, far enough out for every shadow.\n let margin = 0;\n for (const s of outer) {\n margin = Math.max(margin, reach(s));\n }\n ctx.save();\n ctx.beginPath();\n ctx.rect(x - margin, y - margin, width + margin * 2, height + margin * 2);\n roundedRect(ctx, x, y, width, height, ...radii);\n ctx.clip(\"evenodd\");\n\n for (let i = outer.length - 1; i >= 0; i--) {\n const s = outer[i]!;\n const w = width + s.spread * 2;\n const h = height + s.spread * 2;\n if (w <= 0 || h <= 0) continue;\n ctx.save();\n setShadowPaint(ctx, s);\n ctx.beginPath();\n roundedRect(\n ctx,\n x - s.spread + s.offsetX,\n y - s.spread + s.offsetY,\n w,\n h,\n ...spreadRadii(radii, s.spread),\n );\n ctx.fill();\n ctx.restore();\n }\n ctx.restore();\n}\n\n/**\n * Draw an element's `inset` box shadows, back to front: inside the padding\n * box and clipped to it. Each is the shadow outside a hole, the padding box\n * shrunk by the spread and offset, blurred into the box.\n */\nexport function drawInsetBoxShadow(\n ctx: SKRSContext2D,\n x: number,\n y: number,\n width: number,\n height: number,\n shadows: Shadow[],\n borderRadius: BorderRadius,\n style: ComputedStyle,\n): void {\n const inset = shadows.filter((s) => s.inset);\n if (inset.length === 0) return;\n\n const bt = resolveBoxValue(style.borderTopWidth, width);\n const br = resolveBoxValue(style.borderRightWidth, width);\n const bb = resolveBoxValue(style.borderBottomWidth, width);\n const bl = resolveBoxValue(style.borderLeftWidth, width);\n const px = x + bl;\n const py = y + bt;\n const pw = width - bl - br;\n const ph = height - bt - bb;\n if (pw <= 0 || ph <= 0) return;\n\n // The padding box's corners: the border box's, less the borders' widths.\n const [tl, tr, brr, bll] = clampRadii(borderRadius, width, height);\n const inner: Radii = [\n Math.max(0, tl - Math.max(bt, bl)),\n Math.max(0, tr - Math.max(bt, br)),\n Math.max(0, brr - Math.max(bb, br)),\n Math.max(0, bll - Math.max(bb, bl)),\n ];\n\n ctx.save();\n ctx.beginPath();\n roundedRect(ctx, px, py, pw, ph, ...inner);\n ctx.clip();\n\n for (let i = inset.length - 1; i >= 0; i--) {\n const s = inset[i]!;\n // Far enough out that the shadow is solid where the blur reaches the box.\n const m = reach(s);\n ctx.save();\n setShadowPaint(ctx, s);\n ctx.beginPath();\n ctx.rect(px - m, py - m, pw + m * 2, ph + m * 2);\n const w = pw - s.spread * 2;\n const h = ph - s.spread * 2;\n if (w > 0 && h > 0) {\n roundedRect(\n ctx,\n px + s.spread + s.offsetX,\n py + s.spread + s.offsetY,\n w,\n h,\n ...spreadRadii(inner, -s.spread),\n );\n }\n ctx.fill(\"evenodd\");\n ctx.restore();\n }\n ctx.restore();\n}\n\n/** How far a shadow can paint from the box it is cast by. */\nfunction reach(s: Shadow): number {\n return (\n s.blur * 2 +\n Math.abs(s.offsetX) +\n Math.abs(s.offsetY) +\n Math.abs(s.spread) +\n 1\n );\n}\n\nfunction setShadowPaint(ctx: SKRSContext2D, s: Shadow): void {\n // An invalid colour leaves the fill as it was: make that no colour.\n ctx.fillStyle = NO_COLOR;\n ctx.fillStyle = s.color;\n // Use a CSS blur filter (σ = blur / 2), as CSS defines the shadow's blur,\n // rather than the canvas shadow API.\n if (s.blur > 0) ctx.filter = `blur(${s.blur / 2}px)`;\n}\n\n/** Corner radii: top left, top right, bottom right, bottom left. */\ntype Radii = [number, number, number, number];\n\n/** The radii as the box is drawn with them (see `roundedRect`). */\nfunction clampRadii(r: BorderRadius, width: number, height: number): Radii {\n const max = maxCornerRadius(width, height);\n return [\n Math.min(r.topLeft, max),\n Math.min(r.topRight, max),\n Math.min(r.bottomRight, max),\n Math.min(r.bottomLeft, max),\n ];\n}\n\n/**\n * The corner radii of a shape grown by `spread` (shrunk, when negative), as\n * CSS has them: a radius grows by the spread, but one smaller than the spread\n * by less (a square corner stays square), and shrinks to no less than 0.\n */\nexport function spreadRadii(radii: Radii, spread: number): Radii {\n return radii.map((r) => spreadRadius(r, spread)) as Radii;\n}\n\nfunction spreadRadius(r: number, spread: number): number {\n if (spread <= 0) return Math.max(0, r + spread);\n if (r >= spread) return r + spread;\n // CSS Backgrounds 3, \"Shadow shape, spread, and knockout\".\n const ratio = r / spread;\n return r + spread * (1 + (ratio - 1) ** 3);\n}\n","import type { SKRSContext2D } from \"@effing/skia\";\n\n/**\n * Parse and create a canvas gradient from a CSS gradient string.\n * Supports linear-gradient and radial-gradient.\n *\n * @returns A CanvasGradient or null if parsing fails\n */\nexport function createGradientFromCSS(\n ctx: SKRSContext2D,\n cssGradient: string,\n x: number,\n y: number,\n width: number,\n height: number,\n): CanvasGradient | null {\n const trimmed = cssGradient.trim();\n\n if (trimmed.startsWith(\"linear-gradient\")) {\n return parseLinearGradient(ctx, trimmed, x, y, width, height);\n }\n\n if (trimmed.startsWith(\"radial-gradient\")) {\n return parseRadialGradient(ctx, trimmed, x, y, width, height);\n }\n\n return null;\n}\n\nfunction parseLinearGradient(\n ctx: SKRSContext2D,\n css: string,\n x: number,\n y: number,\n width: number,\n height: number,\n): CanvasGradient | null {\n // Extract content between parentheses\n const match = css.match(/linear-gradient\\((.*)\\)/s);\n if (!match) return null;\n\n const content = match[1]!.trim();\n const parts = splitGradientArgs(content);\n\n let angle = 180; // default: to bottom\n let colorStartIdx = 0;\n\n // Parse direction\n const first = parts[0]?.trim();\n if (first) {\n if (first.startsWith(\"to \")) {\n angle = directionToAngle(first);\n colorStartIdx = 1;\n } else if (first.endsWith(\"deg\")) {\n angle = parseFloat(first);\n colorStartIdx = 1;\n } else if (first.endsWith(\"turn\")) {\n angle = parseFloat(first) * 360;\n colorStartIdx = 1;\n }\n }\n\n // Calculate gradient line endpoints\n const rad = ((angle - 90) * Math.PI) / 180;\n const cx = x + width / 2;\n const cy = y + height / 2;\n const halfDiag =\n Math.abs(width * Math.cos(rad)) / 2 + Math.abs(height * Math.sin(rad)) / 2;\n\n const x0 = cx - halfDiag * Math.cos(rad);\n const y0 = cy - halfDiag * Math.sin(rad);\n const x1 = cx + halfDiag * Math.cos(rad);\n const y1 = cy + halfDiag * Math.sin(rad);\n\n const gradient = ctx.createLinearGradient(x0, y0, x1, y1);\n\n // Parse color stops\n const stops = parts.slice(colorStartIdx);\n addColorStops(gradient, stops);\n\n return gradient;\n}\n\nfunction parseRadialGradient(\n ctx: SKRSContext2D,\n css: string,\n x: number,\n y: number,\n width: number,\n height: number,\n): CanvasGradient | null {\n const match = css.match(/radial-gradient\\((.*)\\)/s);\n if (!match) return null;\n\n const content = match[1]!.trim();\n const parts = splitGradientArgs(content);\n\n const cx = x + width / 2;\n const cy = y + height / 2;\n const radius = Math.max(width, height) / 2;\n\n const gradient = ctx.createRadialGradient(cx, cy, 0, cx, cy, radius);\n\n // Simple parsing: skip shape/size/position, just get color stops\n let colorStartIdx = 0;\n const first = parts[0]?.trim() ?? \"\";\n if (\n first.startsWith(\"circle\") ||\n first.startsWith(\"ellipse\") ||\n first.startsWith(\"closest\") ||\n first.startsWith(\"farthest\")\n ) {\n colorStartIdx = 1;\n }\n\n addColorStops(gradient, parts.slice(colorStartIdx));\n\n return gradient;\n}\n\nfunction addColorStops(gradient: CanvasGradient, stops: string[]): void {\n if (stops.length === 0) return;\n\n for (let i = 0; i < stops.length; i++) {\n const stop = stops[i]!.trim();\n const percentMatch = stop.match(/^(.+?)\\s+(\\d+(?:\\.\\d+)?%?)$/);\n\n if (percentMatch) {\n const color = percentMatch[1]!;\n const pos = percentMatch[2]!;\n const offset = pos.endsWith(\"%\")\n ? parseFloat(pos) / 100\n : parseFloat(pos);\n gradient.addColorStop(Math.max(0, Math.min(1, offset)), color);\n } else {\n // Auto-distribute\n const offset = stops.length === 1 ? 0.5 : i / (stops.length - 1);\n gradient.addColorStop(offset, stop);\n }\n }\n}\n\nfunction directionToAngle(dir: string): number {\n const map: Record<string, number> = {\n \"to top\": 0,\n \"to right\": 90,\n \"to bottom\": 180,\n \"to left\": 270,\n \"to top right\": 45,\n \"to top left\": 315,\n \"to bottom right\": 135,\n \"to bottom left\": 225,\n };\n return map[dir] ?? 180;\n}\n\nexport function splitGradientArgs(content: string): string[] {\n const parts: string[] = [];\n let current = \"\";\n let parenDepth = 0;\n\n for (const char of content) {\n if (char === \"(\") parenDepth++;\n if (char === \")\") parenDepth--;\n if (char === \",\" && parenDepth === 0) {\n parts.push(current);\n current = \"\";\n } else {\n current += char;\n }\n }\n if (current.trim()) parts.push(current);\n\n return parts;\n}\n","// Compositing groups through @effing/skia's `beginGroup` / `endGroup`:\n// everything drawn inside a group is composited as one when it ends, which is\n// what CSS `opacity`, `filter` and `backdrop-filter` mean on an element.\n// Per-draw `globalAlpha` and `ctx.filter` can't give that once draws overlap:\n// overlapping children would show through each other, and each would cast its\n// own shadow.\n//\n// A group is composited through an offscreen buffer, which @effing/skia sizes\n// to what the group draws, so a translucent element costs about as much as\n// its own area.\n\nimport type { SKRSContext2D } from \"@effing/skia\";\nimport { beginGroup, endGroup } from \"@effing/skia/extensions\";\n\nimport { applyClip } from \"./clip.ts\";\nimport type { getBorderRadiusFromStyle } from \"./rect.ts\";\n\ntype BorderRadius = ReturnType<typeof getBorderRadiusFromStyle>;\n\n/** A CSS filter value that filters nothing. */\nfunction isNoFilter(filter: string | undefined): boolean {\n if (!filter) return true;\n const normalized = filter.trim();\n return normalized === \"\" || normalized === \"none\";\n}\n\n/**\n * Start the group an element and its descendants paint into, when its\n * `opacity` or `filter` call for one. Returns whether a group was started,\n * to end with `endElementGroup`.\n */\nexport function beginElementGroup(\n ctx: SKRSContext2D,\n opacity: number,\n filter: string | undefined,\n): boolean {\n const hasFilter = !isNoFilter(filter);\n if (opacity >= 1 && !hasFilter) return false;\n beginGroup(ctx, { opacity, filter: hasFilter ? filter!.trim() : undefined });\n return true;\n}\n\nexport function endElementGroup(ctx: SKRSContext2D): void {\n endGroup(ctx);\n}\n\n/**\n * CSS `backdrop-filter`: filter whatever is already painted behind the\n * element's border box (with its radius) and composite the result back at the\n * element's opacity. Must run before the element's own painting — box-shadow\n * and background included — so nothing of the element ends up in its own\n * backdrop and its background composites on top of the filtered result.\n *\n * The filter runs in the element's own coordinate space, and the backdrop is\n * clamped at the canvas edge, as a browser does at the viewport edge, so a\n * blur near the edge doesn't fade into transparency. Skia reads the backdrop\n * from the enclosing group, so as in a browser, an ancestor with `opacity` or\n * a `filter` bounds what the element sees through: only what that ancestor\n * has painted so far.\n */\nexport function drawBackdropFilter(\n ctx: SKRSContext2D,\n filter: string,\n x: number,\n y: number,\n width: number,\n height: number,\n borderRadius: BorderRadius,\n opacity: number,\n): void {\n if (width <= 0 || height <= 0) return;\n if (isNoFilter(filter)) return;\n ctx.save();\n applyClip(ctx, x, y, width, height, borderRadius);\n beginGroup(ctx, { backdropFilter: filter.trim(), opacity });\n endGroup(ctx);\n ctx.restore();\n}\n","/**\n * Shared cover/contain sizing logic used by both `<img>` objectFit\n * and `backgroundImage` + `backgroundSize`.\n */\n\nexport interface FitRect {\n sx: number;\n sy: number;\n sw: number;\n sh: number;\n dx: number;\n dy: number;\n dw: number;\n dh: number;\n}\n\n/**\n * Compute source and destination rectangles for \"cover\" sizing.\n * The image fills the box completely, cropping the excess.\n */\nexport function computeCover(\n imgW: number,\n imgH: number,\n boxX: number,\n boxY: number,\n boxW: number,\n boxH: number,\n): FitRect {\n const imgRatio = imgW / imgH;\n const boxRatio = boxW / boxH;\n\n let sx: number, sy: number, sw: number, sh: number;\n\n if (imgRatio > boxRatio) {\n sh = imgH;\n sw = imgH * boxRatio;\n sx = (imgW - sw) / 2;\n sy = 0;\n } else {\n sw = imgW;\n sh = imgW / boxRatio;\n sx = 0;\n sy = (imgH - sh) / 2;\n }\n\n return { sx, sy, sw, sh, dx: boxX, dy: boxY, dw: boxW, dh: boxH };\n}\n\n/**\n * Compute destination rectangle for \"contain\" sizing.\n * The image fits entirely within the box, centered, with no cropping.\n */\nexport function computeContain(\n imgW: number,\n imgH: number,\n boxX: number,\n boxY: number,\n boxW: number,\n boxH: number,\n): FitRect {\n const imgRatio = imgW / imgH;\n const boxRatio = boxW / boxH;\n\n let dw: number, dh: number;\n\n if (imgRatio > boxRatio) {\n dw = boxW;\n dh = boxW / imgRatio;\n } else {\n dh = boxH;\n dw = boxH * imgRatio;\n }\n\n const dx = boxX + (boxW - dw) / 2;\n const dy = boxY + (boxH - dh) / 2;\n\n return { sx: 0, sy: 0, sw: imgW, sh: imgH, dx, dy, dw, dh };\n}\n","import type { SKRSContext2D } from \"@effing/skia\";\n\nimport { cachedLoadImage } from \"../../image.ts\";\nimport type { ComputedStyle } from \"../style/compute.ts\";\nimport type { RenderContext } from \"../context.ts\";\nimport { computeContain, computeCover } from \"./object-fit.ts\";\n\n/**\n * Draw an image element onto the canvas.\n *\n * @param ctx - Canvas rendering context\n * @param src - Image source (URL, file path, or Buffer)\n * @param x - X position\n * @param y - Y position\n * @param width - Target width\n * @param height - Target height\n * @param context - Per-render context (image cache + fetch config)\n * @param style - Computed style (for objectFit)\n */\nexport async function drawImage(\n ctx: SKRSContext2D,\n src: string | Buffer,\n x: number,\n y: number,\n width: number,\n height: number,\n context: RenderContext,\n style?: ComputedStyle,\n): Promise<void> {\n const image = await cachedLoadImage(\n context.imageCache,\n src,\n context.userAgent,\n );\n const objectFit = style?.objectFit ?? \"fill\";\n\n if (objectFit === \"fill\") {\n ctx.drawImage(image, x, y, width, height);\n return;\n }\n\n const imgW = image.width;\n const imgH = image.height;\n\n if (objectFit === \"contain\") {\n const r = computeContain(imgW, imgH, x, y, width, height);\n ctx.drawImage(image, r.dx, r.dy, r.dw, r.dh);\n } else if (objectFit === \"cover\") {\n const r = computeCover(imgW, imgH, x, y, width, height);\n ctx.drawImage(image, r.sx, r.sy, r.sw, r.sh, r.dx, r.dy, r.dw, r.dh);\n } else if (objectFit === \"none\") {\n const dx = x + (width - imgW) / 2;\n const dy = y + (height - imgH) / 2;\n ctx.drawImage(image, dx, dy);\n } else if (objectFit === \"scale-down\") {\n if (imgW <= width && imgH <= height) {\n const dx = x + (width - imgW) / 2;\n const dy = y + (height - imgH) / 2;\n ctx.drawImage(image, dx, dy);\n } else {\n const r = computeContain(imgW, imgH, x, y, width, height);\n ctx.drawImage(image, r.dx, r.dy, r.dw, r.dh);\n }\n }\n}\n","/**\n * Parsing of the CSS `box-shadow` and `text-shadow` properties.\n *\n * Their lengths arrive in px: `resolveUnits` resolves em, rem, vw and the\n * other units it knows before anything is drawn.\n */\n\n/** One shadow of a `box-shadow` or `text-shadow` list. */\nexport interface Shadow {\n offsetX: number;\n offsetY: number;\n /** The blur radius, 0 or more. CSS blurs by a Gaussian of σ = blur / 2. */\n blur: number;\n /** How far the shadow's shape grows (or, negative, shrinks): box-shadow only. */\n spread: number;\n /** Whether the shadow is cast inside the padding box: box-shadow only. */\n inset: boolean;\n color: string;\n}\n\n/** How a shadow list is parsed: what its property allows. */\ninterface ShadowSyntax {\n /** The most lengths a shadow takes: 4 for box-shadow, 3 for text-shadow. */\n maxLengths: number;\n /** Whether `inset` is allowed (box-shadow). */\n inset: boolean;\n}\n\nconst BOX_SHADOW: ShadowSyntax = { maxLengths: 4, inset: true };\nconst TEXT_SHADOW: ShadowSyntax = { maxLengths: 3, inset: false };\n\n/**\n * Parse a CSS `box-shadow`: a comma-separated list of\n * `inset? && <length>{2,4} && <color>?`, in the order they are listed\n * (the first is painted on top). A shadow without a colour casts it in\n * `currentColor`. An invalid value yields no shadows, as CSS ignores it.\n */\nexport function parseBoxShadow(value: string, currentColor: string): Shadow[] {\n return parseShadowList(value, currentColor, BOX_SHADOW);\n}\n\n/**\n * Parse a CSS `text-shadow`: a comma-separated list of\n * `<length>{2,3} && <color>?`, in the order they are listed (the first is\n * painted on top). A shadow without a colour casts it in `currentColor`. An\n * invalid value yields no shadows, as CSS ignores it.\n */\nexport function parseTextShadow(value: string, currentColor: string): Shadow[] {\n return parseShadowList(value, currentColor, TEXT_SHADOW);\n}\n\nfunction parseShadowList(\n value: string,\n currentColor: string,\n syntax: ShadowSyntax,\n): Shadow[] {\n const text = value.trim();\n if (text === \"\" || text.toLowerCase() === \"none\") return [];\n const shadows: Shadow[] = [];\n for (const item of splitTopLevel(text, \",\")) {\n const shadow = parseShadow(item, currentColor, syntax);\n // One invalid shadow invalidates the whole declaration.\n if (!shadow) return [];\n shadows.push(shadow);\n }\n return shadows;\n}\n\n/** A length: a number in px, or a unitless one (as React styles allow). */\nconst LENGTH = /^([+-]?(?:\\d+\\.?\\d*|\\.\\d+)(?:e[+-]?\\d+)?)(px)?$/i;\n\n/** A token that starts like a number: a length, or an invalid one. */\nconst NUMERIC = /^[+-]?\\.?\\d/;\n\nfunction parseShadow(\n item: string,\n currentColor: string,\n syntax: ShadowSyntax,\n): Shadow | null {\n const tokens = splitTopLevel(item, \" \");\n const lengths: number[] = [];\n let lengthsEnded = false;\n let inset = false;\n let color: string | undefined;\n\n for (const token of tokens) {\n if (NUMERIC.test(token)) {\n const match = LENGTH.exec(token);\n // The lengths are one run: nothing may come between them.\n if (!match || lengthsEnded) return null;\n lengths.push(parseFloat(match[1]!));\n continue;\n }\n if (lengths.length > 0) lengthsEnded = true;\n if (token.toLowerCase() === \"inset\") {\n if (!syntax.inset || inset) return null;\n inset = true;\n } else {\n if (color !== undefined) return null;\n color = token;\n }\n }\n\n if (lengths.length < 2 || lengths.length > syntax.maxLengths) return null;\n const [offsetX, offsetY, blur = 0, spread = 0] = lengths as [\n number,\n number,\n number?,\n number?,\n ];\n if (blur < 0) return null;\n if (color === undefined || color.toLowerCase() === \"currentcolor\") {\n color = currentColor;\n }\n return { offsetX, offsetY, blur, spread, inset, color };\n}\n\n/**\n * Split `text` at `separator` (a comma, or a space for any white space)\n * outside parentheses, dropping empty parts: `rgb(0, 0, 0)` stays whole.\n */\nexport function splitTopLevel(text: string, separator: \",\" | \" \"): string[] {\n const parts: string[] = [];\n let depth = 0;\n let current = \"\";\n for (const ch of text) {\n if (ch === \"(\") depth++;\n else if (ch === \")\") depth = Math.max(0, depth - 1);\n const splits =\n depth === 0 && (separator === \",\" ? ch === \",\" : /\\s/.test(ch));\n if (splits) {\n parts.push(current);\n current = \"\";\n } else {\n current += ch;\n }\n }\n parts.push(current);\n if (separator === \",\") {\n // An empty item (`a, , b` or a trailing comma) is invalid in CSS.\n return parts.map((p) => p.trim());\n }\n return parts.filter((p) => p !== \"\");\n}\n","import type { InheritedSvgStyle } from \"./types.ts\";\n\n/** Replace `\"currentColor\"` with the inherited CSS `color` value. */\nexport function resolveCurrentColor(\n value: string | undefined,\n color: string,\n): string | undefined {\n if (value?.toLowerCase() === \"currentcolor\") return color;\n return value;\n}\n\n/**\n * Merge SVG presentation properties from `props.style` into the props object.\n * Style values win over direct props, matching browser CSS specificity rules.\n */\nexport function mergeStyleIntoProps(\n props: Record<string, unknown>,\n): Record<string, unknown> {\n const style = props.style as Record<string, unknown> | undefined;\n if (!style) return props;\n return { ...props, ...style };\n}\n\n/**\n * Parse an SVG length value, resolving percentages against a reference dimension.\n * Unlike gradient-specific `parseFrac`, this returns absolute coordinates (not 0–1 fractions).\n */\nexport function svgLength(\n value: unknown,\n reference: number,\n fallback = 0,\n): number {\n if (value == null) return fallback;\n const s = String(value);\n if (s.endsWith(\"%\")) return (parseFloat(s) / 100) * reference;\n const n = Number(s);\n return isNaN(n) ? fallback : n;\n}\n\n/** Parse `url(#id)` references and return the id, or undefined. */\nexport function parseUrlRef(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined;\n const m = value.match(/^url\\(#(.+)\\)$/);\n return m?.[1];\n}\n\n/**\n * Build an `InheritedSvgStyle` from merged SVG props, falling back to `parent`\n * values when present (for nested groups) or sensible defaults (fill = \"black\").\n */\nexport function resolveInheritedStyle(\n merged: Record<string, unknown>,\n color: string,\n parent?: InheritedSvgStyle,\n): InheritedSvgStyle {\n return {\n fill:\n resolveCurrentColor(merged.fill as string | undefined, color) ??\n parent?.fill ??\n \"black\",\n stroke:\n resolveCurrentColor(merged.stroke as string | undefined, color) ??\n parent?.stroke,\n strokeWidth:\n ((merged.strokeWidth ?? merged[\"stroke-width\"]) as\n | string\n | number\n | undefined) ?? parent?.strokeWidth,\n strokeLinecap:\n ((merged.strokeLinecap ?? merged[\"stroke-linecap\"]) as\n | string\n | undefined) ?? parent?.strokeLinecap,\n strokeLinejoin:\n ((merged.strokeLinejoin ?? merged[\"stroke-linejoin\"]) as\n | string\n | undefined) ?? parent?.strokeLinejoin,\n strokeOpacity:\n ((merged.strokeOpacity ?? merged[\"stroke-opacity\"]) as\n | string\n | number\n | undefined) ?? parent?.strokeOpacity,\n };\n}\n","import type { SvgChild } from \"./types.ts\";\n\n/** Normalize children from either `.children` or `.props.children` into an array. */\nexport function normalizeChildren(node: SvgChild): SvgChild[] {\n const raw =\n node.children ?? (node.props.children as SvgChild | SvgChild[] | undefined);\n if (raw == null) return [];\n return (Array.isArray(raw) ? raw.flat(Infinity) : [raw]) as SvgChild[];\n}\n","import type { SvgChild, SvgDefs } from \"./types.ts\";\nimport { normalizeChildren } from \"./tree.ts\";\n\n/**\n * Collect `<clipPath>`, `<mask>`, `<filter>`, and gradient definitions from\n * `<defs>` elements as well as direct children of `<svg>` (both are valid per\n * the SVG spec).\n */\nexport function collectDefs(children: SvgChild[], vbW = 0, vbH = 0): SvgDefs {\n const clips = new Map<string, SvgChild[]>();\n const gradients = new Map<string, SvgChild>();\n const masks = new Map<string, SvgChild[]>();\n const filters = new Map<string, SvgChild>();\n\n function insertDef(def: SvgChild): void {\n if (!def || typeof def !== \"object\" || !(\"props\" in def) || !def.props)\n return;\n const id = def.props.id as string | undefined;\n if (!id) return;\n if (def.type === \"clipPath\") clips.set(id, normalizeChildren(def));\n else if (def.type === \"mask\") masks.set(id, normalizeChildren(def));\n else if (def.type === \"filter\") filters.set(id, def);\n else if (def.type === \"radialGradient\" || def.type === \"linearGradient\")\n gradients.set(id, def);\n }\n\n for (const child of children) {\n if (child.type === \"defs\") {\n for (const def of normalizeChildren(child)) insertDef(def);\n } else {\n // Definition elements can appear as direct children of <svg>.\n insertDef(child);\n }\n }\n return {\n clips,\n gradients,\n masks,\n filters,\n viewport: { width: vbW, height: vbH },\n };\n}\n\nexport const EMPTY_DEFS: SvgDefs = {\n clips: new Map(),\n gradients: new Map(),\n masks: new Map(),\n filters: new Map(),\n viewport: { width: 0, height: 0 },\n};\n","import type { SKRSContext2D } from \"@effing/skia\";\n\n/**\n * Save context state and apply transform + opacity if present.\n * Returns true if ctx.save() was called (caller must ctx.restore()).\n */\nexport function applyTransformAndOpacity(\n ctx: SKRSContext2D,\n transform: string | undefined,\n opacity: number,\n): boolean {\n if (!transform && opacity >= 1) return false;\n ctx.save();\n if (transform) applySvgTransform(ctx, transform);\n if (opacity < 1) ctx.globalAlpha *= opacity;\n return true;\n}\n\n/**\n * Parse an SVG `transform` attribute and apply it to the canvas context.\n *\n * Supports: translate, scale, rotate, skewX, skewY, matrix.\n * Multiple transforms are applied left-to-right (same order as SVG spec).\n */\nexport function applySvgTransform(ctx: SKRSContext2D, transform: string): void {\n const re = /\\b(translate|scale|rotate|skewX|skewY|matrix)\\s*\\(([^)]*)\\)/g;\n let match: RegExpExecArray | null;\n while ((match = re.exec(transform)) !== null) {\n const fn = match[1]!;\n const args = match[2]!\n .split(/[\\s,]+/)\n .filter(Boolean)\n .map(Number);\n\n switch (fn) {\n case \"translate\":\n ctx.translate(args[0] ?? 0, args[1] ?? 0);\n break;\n case \"scale\": {\n const sx = args[0] ?? 1;\n ctx.scale(sx, args[1] ?? sx);\n break;\n }\n case \"rotate\": {\n const angle = ((args[0] ?? 0) * Math.PI) / 180;\n if (args.length >= 3) {\n const cx = args[1]!;\n const cy = args[2]!;\n ctx.translate(cx, cy);\n ctx.rotate(angle);\n ctx.translate(-cx, -cy);\n } else {\n ctx.rotate(angle);\n }\n break;\n }\n case \"skewX\":\n ctx.transform(\n 1,\n 0,\n Math.tan(((args[0] ?? 0) * Math.PI) / 180),\n 1,\n 0,\n 0,\n );\n break;\n case \"skewY\":\n ctx.transform(\n 1,\n Math.tan(((args[0] ?? 0) * Math.PI) / 180),\n 0,\n 1,\n 0,\n 0,\n );\n break;\n case \"matrix\":\n ctx.transform(\n args[0] ?? 1,\n args[1] ?? 0,\n args[2] ?? 0,\n args[3] ?? 1,\n args[4] ?? 0,\n args[5] ?? 0,\n );\n break;\n }\n }\n}\n","import { Path2D } from \"@effing/skia\";\n\nimport type { BBox, SvgChild } from \"./types.ts\";\nimport { mergeStyleIntoProps } from \"./style.ts\";\nimport { svgLength } from \"./style.ts\";\n\n/** Compute a conservative bounding box from SVG path data. */\nexport function pathBBox(d: string): BBox {\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n let cx = 0;\n let cy = 0;\n\n const update = (x: number, y: number) => {\n if (x < minX) minX = x;\n if (x > maxX) maxX = x;\n if (y < minY) minY = y;\n if (y > maxY) maxY = y;\n };\n\n // Tokenize: commands and numbers (including negative)\n const tokens = d.match(/[a-zA-Z]|[-+]?(?:\\d+\\.?\\d*|\\.\\d+)(?:[eE][-+]?\\d+)?/g);\n if (!tokens) return { x: 0, y: 0, width: 0, height: 0 };\n\n let cmd = \"\";\n let i = 0;\n const num = () => Number(tokens[i++]);\n\n while (i < tokens.length) {\n const t = tokens[i]!;\n if (/[a-zA-Z]/.test(t)) {\n cmd = t;\n i++;\n }\n\n switch (cmd) {\n case \"M\":\n cx = num();\n cy = num();\n update(cx, cy);\n cmd = \"L\"; // implicit lineTo after moveTo\n break;\n case \"m\":\n cx += num();\n cy += num();\n update(cx, cy);\n cmd = \"l\";\n break;\n case \"L\":\n cx = num();\n cy = num();\n update(cx, cy);\n break;\n case \"l\":\n cx += num();\n cy += num();\n update(cx, cy);\n break;\n case \"H\":\n cx = num();\n update(cx, cy);\n break;\n case \"h\":\n cx += num();\n update(cx, cy);\n break;\n case \"V\":\n cy = num();\n update(cx, cy);\n break;\n case \"v\":\n cy += num();\n update(cx, cy);\n break;\n case \"C\": {\n // Cubic bezier: use control points as conservative bounds\n for (let j = 0; j < 3; j++) {\n const px = num();\n const py = num();\n update(px, py);\n }\n cx = Number(tokens[i - 2]);\n cy = Number(tokens[i - 1]);\n break;\n }\n case \"c\": {\n for (let j = 0; j < 3; j++) {\n const dx = num();\n const dy = num();\n update(cx + dx, cy + dy);\n if (j === 2) {\n cx += dx;\n cy += dy;\n }\n }\n break;\n }\n case \"Q\": {\n for (let j = 0; j < 2; j++) {\n const px = num();\n const py = num();\n update(px, py);\n }\n cx = Number(tokens[i - 2]);\n cy = Number(tokens[i - 1]);\n break;\n }\n case \"q\": {\n for (let j = 0; j < 2; j++) {\n const dx = num();\n const dy = num();\n update(cx + dx, cy + dy);\n if (j === 1) {\n cx += dx;\n cy += dy;\n }\n }\n break;\n }\n case \"A\": {\n // Arc: skip rx, ry, rotation, flags; endpoint is the bound\n num();\n num();\n num();\n num();\n num(); // rx ry rot largeArc sweep\n cx = num();\n cy = num();\n update(cx, cy);\n break;\n }\n case \"a\": {\n num();\n num();\n num();\n num();\n num();\n cx += num();\n cy += num();\n update(cx, cy);\n break;\n }\n case \"Z\":\n case \"z\":\n break;\n default:\n // Unknown command — skip token to avoid infinite loop\n i++;\n break;\n }\n }\n\n if (!isFinite(minX)) return { x: 0, y: 0, width: 0, height: 0 };\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n}\n\n/** Compute bounding box from a points attribute (polygon/polyline). */\nexport function pointsBBox(points: [number, number][]): BBox {\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const [x, y] of points) {\n if (x < minX) minX = x;\n if (x > maxX) maxX = x;\n if (y < minY) minY = y;\n if (y > maxY) maxY = y;\n }\n if (!isFinite(minX)) return { x: 0, y: 0, width: 0, height: 0 };\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n}\n\n/**\n * Build a `Path2D` from an SVG shape element (without drawing it).\n * Returns `undefined` for unsupported element types.\n */\nexport function buildPath(\n child: SvgChild,\n vbW: number,\n vbH: number,\n): Path2D | undefined {\n const props = mergeStyleIntoProps(child.props);\n switch (child.type) {\n case \"path\": {\n const d = props.d as string | undefined;\n if (!d) return undefined;\n return new Path2D(d);\n }\n case \"circle\": {\n const cx = svgLength(props.cx, vbW);\n const cy = svgLength(props.cy, vbH);\n const r = svgLength(props.r, Math.min(vbW, vbH));\n if (r <= 0) return undefined;\n const p = new Path2D();\n p.arc(cx, cy, r, 0, Math.PI * 2);\n return p;\n }\n case \"rect\": {\n const x = svgLength(props.x, vbW);\n const y = svgLength(props.y, vbH);\n const w = svgLength(props.width, vbW);\n const h = svgLength(props.height, vbH);\n if (w <= 0 || h <= 0) return undefined;\n const rxRaw = svgLength(props.rx, vbW, -1);\n const ryRaw = svgLength(props.ry, vbH, -1);\n let rx = rxRaw >= 0 ? rxRaw : ryRaw >= 0 ? ryRaw : 0;\n let ry = ryRaw >= 0 ? ryRaw : rx;\n rx = Math.min(rx, w / 2);\n ry = Math.min(ry, h / 2);\n const p = new Path2D();\n if (rx > 0 || ry > 0) {\n p.roundRect(x, y, w, h, [rx]);\n } else {\n p.rect(x, y, w, h);\n }\n return p;\n }\n case \"ellipse\": {\n const cx = svgLength(props.cx, vbW);\n const cy = svgLength(props.cy, vbH);\n const rx = svgLength(props.rx, vbW);\n const ry = svgLength(props.ry, vbH);\n if (rx <= 0 || ry <= 0) return undefined;\n const p = new Path2D();\n p.ellipse(cx, cy, rx, ry, 0, 0, Math.PI * 2);\n return p;\n }\n case \"polygon\": {\n const points = parsePoints(props.points as string | undefined);\n if (points.length < 2) return undefined;\n const p = new Path2D();\n p.moveTo(points[0]![0], points[0]![1]);\n for (let i = 1; i < points.length; i++) {\n p.lineTo(points[i]![0], points[i]![1]);\n }\n p.closePath();\n return p;\n }\n default:\n return undefined;\n }\n}\n\n/**\n * Build a combined `Path2D` from all children of a `<clipPath>` definition.\n */\nexport function buildClipPath(\n shapes: SvgChild[],\n vbW: number,\n vbH: number,\n): Path2D | undefined {\n let combined: Path2D | undefined;\n for (const shape of shapes) {\n const p = buildPath(shape, vbW, vbH);\n if (!p) continue;\n if (!combined) {\n combined = p;\n } else {\n combined.addPath(p);\n }\n }\n return combined;\n}\n\nexport function parsePoints(value: string | undefined): [number, number][] {\n if (!value) return [];\n const nums = value\n .trim()\n .split(/[\\s,]+/)\n .map(Number);\n const result: [number, number][] = [];\n for (let i = 0; i + 1 < nums.length; i += 2) {\n result.push([nums[i]!, nums[i + 1]!]);\n }\n return result;\n}\n","import type { Canvas, SKRSContext2D } from \"@effing/skia\";\nimport { createCanvas } from \"@effing/skia\";\n\nconst canvasPool = new Map<string, WeakRef<Canvas>[]>();\n\nexport function acquireOffscreen(\n w: number,\n h: number,\n): [Canvas, SKRSContext2D] {\n const key = `${w}x${h}`;\n const stack = canvasPool.get(key);\n if (stack) {\n while (stack.length > 0) {\n const ref = stack.pop()!;\n const canvas = ref.deref();\n if (canvas) {\n const ctx = canvas.getContext(\"2d\");\n ctx.reset();\n return [canvas, ctx];\n }\n }\n }\n const canvas = createCanvas(w, h);\n return [canvas, canvas.getContext(\"2d\")];\n}\n\nexport function releaseOffscreen(canvas: Canvas): void {\n const key = `${canvas.width}x${canvas.height}`;\n let stack = canvasPool.get(key);\n if (!stack) {\n stack = [];\n canvasPool.set(key, stack);\n }\n stack.push(new WeakRef(canvas));\n}\n","import type { Canvas } from \"@effing/skia\";\n\nimport type { SvgChild } from \"./types.ts\";\nimport { normalizeChildren } from \"./tree.ts\";\nimport { acquireOffscreen } from \"../offscreen.ts\";\n\nfunction applyFeOffset(\n input: Canvas,\n dx: number,\n dy: number,\n w: number,\n h: number,\n): Canvas {\n const [canvas, ctx] = acquireOffscreen(w, h);\n ctx.drawImage(input, dx, dy);\n return canvas;\n}\n\nfunction applyFeGaussianBlur(\n input: Canvas,\n stdDeviation: number,\n w: number,\n h: number,\n): Canvas {\n const [canvas, ctx] = acquireOffscreen(w, h);\n ctx.filter = `blur(${stdDeviation}px)`;\n ctx.drawImage(input, 0, 0);\n ctx.filter = \"none\";\n return canvas;\n}\n\nfunction applyFeColorMatrix(\n input: Canvas,\n type: string,\n values: string | undefined,\n w: number,\n h: number,\n): Canvas {\n const [canvas, ctx] = acquireOffscreen(w, h);\n ctx.drawImage(input, 0, 0);\n\n if (type === \"matrix\" && values) {\n const m = values\n .trim()\n .split(/[\\s,]+/)\n .map(Number);\n if (m.length >= 20) {\n const imageData = ctx.getImageData(0, 0, w, h);\n const d = imageData.data;\n for (let i = 0; i < d.length; i += 4) {\n const r = d[i]!;\n const g = d[i + 1]!;\n const b = d[i + 2]!;\n const a = d[i + 3]!;\n d[i] = Math.min(\n 255,\n Math.max(\n 0,\n m[0]! * r + m[1]! * g + m[2]! * b + m[3]! * a + m[4]! * 255,\n ),\n );\n d[i + 1] = Math.min(\n 255,\n Math.max(\n 0,\n m[5]! * r + m[6]! * g + m[7]! * b + m[8]! * a + m[9]! * 255,\n ),\n );\n d[i + 2] = Math.min(\n 255,\n Math.max(\n 0,\n m[10]! * r + m[11]! * g + m[12]! * b + m[13]! * a + m[14]! * 255,\n ),\n );\n d[i + 3] = Math.min(\n 255,\n Math.max(\n 0,\n m[15]! * r + m[16]! * g + m[17]! * b + m[18]! * a + m[19]! * 255,\n ),\n );\n }\n ctx.putImageData(imageData, 0, 0);\n }\n }\n\n return canvas;\n}\n\nconst BLEND_MODE_MAP: Record<string, GlobalCompositeOperation> = {\n normal: \"source-over\",\n multiply: \"multiply\",\n screen: \"screen\",\n darken: \"darken\",\n lighten: \"lighten\",\n overlay: \"overlay\",\n};\n\nfunction applyFeBlend(\n in1: Canvas,\n in2: Canvas,\n mode: string,\n w: number,\n h: number,\n): Canvas {\n const [canvas, ctx] = acquireOffscreen(w, h);\n ctx.drawImage(in2, 0, 0);\n ctx.globalCompositeOperation = BLEND_MODE_MAP[mode] ?? \"source-over\";\n ctx.drawImage(in1, 0, 0);\n ctx.globalCompositeOperation = \"source-over\";\n return canvas;\n}\n\n/**\n * Extract the alpha channel of a canvas as a new greyscale canvas.\n * The result is a canvas where each pixel's RGBA channels equal the\n * source alpha (i.e. white where opaque, black where transparent).\n */\nfunction extractSourceAlpha(input: Canvas, w: number, h: number): Canvas {\n const [canvas, ctx] = acquireOffscreen(w, h);\n ctx.fillStyle = \"black\";\n ctx.fillRect(0, 0, w, h);\n ctx.globalCompositeOperation = \"destination-in\";\n ctx.drawImage(input, 0, 0);\n ctx.globalCompositeOperation = \"source-over\";\n return canvas;\n}\n\n/**\n * Execute an SVG `<filter>` pipeline on the element canvas.\n * Returns a new canvas with the filtered result; the caller is responsible\n * for releasing all canvases.\n */\nexport function applyFilter(\n filterDef: SvgChild,\n sourceGraphic: Canvas,\n w: number,\n h: number,\n): Canvas {\n const buffers = new Map<string, Canvas>();\n buffers.set(\"SourceGraphic\", sourceGraphic);\n\n let sourceAlpha: Canvas | undefined;\n const getSourceAlpha = () => {\n if (!sourceAlpha) {\n sourceAlpha = extractSourceAlpha(sourceGraphic, w, h);\n buffers.set(\"SourceAlpha\", sourceAlpha);\n }\n return sourceAlpha;\n };\n\n const children = normalizeChildren(filterDef);\n let lastResult: Canvas = sourceGraphic;\n\n for (const prim of children) {\n const p = prim.props;\n const inName = (p.in as string | undefined) ?? \"\";\n const resolve = (name: string): Canvas => {\n if (name === \"SourceAlpha\") return getSourceAlpha();\n return buffers.get(name) ?? lastResult;\n };\n const input = inName ? resolve(inName) : lastResult;\n let output: Canvas;\n\n switch (prim.type) {\n case \"feOffset\":\n output = applyFeOffset(\n input,\n Number(p.dx ?? 0),\n Number(p.dy ?? 0),\n w,\n h,\n );\n break;\n case \"feGaussianBlur\": {\n const std = Number(p.stdDeviation ?? 0);\n output = std > 0 ? applyFeGaussianBlur(input, std, w, h) : input;\n break;\n }\n case \"feColorMatrix\":\n output = applyFeColorMatrix(\n input,\n (p.type as string) ?? \"matrix\",\n p.values as string | undefined,\n w,\n h,\n );\n break;\n case \"feBlend\": {\n const in2Name = (p.in2 as string | undefined) ?? \"\";\n const in2 = in2Name ? resolve(in2Name) : lastResult;\n output = applyFeBlend(input, in2, (p.mode as string) ?? \"normal\", w, h);\n break;\n }\n default:\n output = input;\n break;\n }\n\n const resultName = p.result as string | undefined;\n if (resultName) buffers.set(resultName, output);\n lastResult = output;\n }\n\n return lastResult;\n}\n","import { Path2D } from \"@effing/skia\";\nimport type { SKRSContext2D } from \"@effing/skia\";\n\nimport type { BBox, InheritedSvgStyle, SvgDefs } from \"./types.ts\";\nimport { applyFillAndStroke, applyStroke } from \"./paint.ts\";\nimport { pathBBox, pointsBBox, parsePoints } from \"./path.ts\";\nimport { svgLength } from \"./style.ts\";\n\nexport function drawPath(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n inherited: InheritedSvgStyle,\n color: string,\n defs: SvgDefs,\n): void {\n const d = props.d as string | undefined;\n if (!d) return;\n\n const path = new Path2D(d);\n const bbox = pathBBox(d);\n applyFillAndStroke(ctx, props, path, inherited, color, defs, bbox);\n}\n\nexport function drawCircle(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n inherited: InheritedSvgStyle,\n color: string,\n defs: SvgDefs,\n vbW = 0,\n vbH = 0,\n): void {\n const cx = svgLength(props.cx, vbW);\n const cy = svgLength(props.cy, vbH);\n const r = svgLength(props.r, Math.min(vbW, vbH));\n if (r <= 0) return;\n\n const path = new Path2D();\n path.arc(cx, cy, r, 0, Math.PI * 2);\n const bbox: BBox = { x: cx - r, y: cy - r, width: 2 * r, height: 2 * r };\n applyFillAndStroke(ctx, props, path, inherited, color, defs, bbox);\n}\n\nexport function drawSvgRect(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n inherited: InheritedSvgStyle,\n color: string,\n defs: SvgDefs,\n vbW = 0,\n vbH = 0,\n): void {\n const x = svgLength(props.x, vbW);\n const y = svgLength(props.y, vbH);\n const w = svgLength(props.width, vbW);\n const h = svgLength(props.height, vbH);\n if (w <= 0 || h <= 0) return;\n\n const rxRaw = svgLength(props.rx, vbW, -1);\n const ryRaw = svgLength(props.ry, vbH, -1);\n let rx = rxRaw >= 0 ? rxRaw : ryRaw >= 0 ? ryRaw : 0;\n let ry = ryRaw >= 0 ? ryRaw : rx;\n rx = Math.min(rx, w / 2);\n ry = Math.min(ry, h / 2);\n\n const path = new Path2D();\n if (rx > 0 || ry > 0) {\n path.roundRect(x, y, w, h, [rx]);\n } else {\n path.rect(x, y, w, h);\n }\n const bbox: BBox = { x, y, width: w, height: h };\n applyFillAndStroke(ctx, props, path, inherited, color, defs, bbox);\n}\n\nexport function drawLine(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n inherited: InheritedSvgStyle,\n color: string,\n defs: SvgDefs,\n vbW = 0,\n vbH = 0,\n): void {\n const x1 = svgLength(props.x1, vbW);\n const y1 = svgLength(props.y1, vbH);\n const x2 = svgLength(props.x2, vbW);\n const y2 = svgLength(props.y2, vbH);\n\n const path = new Path2D();\n path.moveTo(x1, y1);\n path.lineTo(x2, y2);\n // Lines are stroke-only\n const bbox: BBox = {\n x: Math.min(x1, x2),\n y: Math.min(y1, y2),\n width: Math.abs(x2 - x1),\n height: Math.abs(y2 - y1),\n };\n applyStroke(ctx, props, path, inherited, color, defs, bbox);\n}\n\nexport function drawEllipse(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n inherited: InheritedSvgStyle,\n color: string,\n defs: SvgDefs,\n vbW = 0,\n vbH = 0,\n): void {\n const cx = svgLength(props.cx, vbW);\n const cy = svgLength(props.cy, vbH);\n const rx = svgLength(props.rx, vbW);\n const ry = svgLength(props.ry, vbH);\n if (rx <= 0 || ry <= 0) return;\n\n const path = new Path2D();\n path.ellipse(cx, cy, rx, ry, 0, 0, Math.PI * 2);\n const bbox: BBox = {\n x: cx - rx,\n y: cy - ry,\n width: 2 * rx,\n height: 2 * ry,\n };\n applyFillAndStroke(ctx, props, path, inherited, color, defs, bbox);\n}\n\nexport function drawPolygon(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n inherited: InheritedSvgStyle,\n color: string,\n defs: SvgDefs,\n): void {\n const points = parsePoints(props.points as string | undefined);\n if (points.length < 2) return;\n\n const path = new Path2D();\n path.moveTo(points[0]![0], points[0]![1]);\n for (let i = 1; i < points.length; i++) {\n path.lineTo(points[i]![0], points[i]![1]);\n }\n path.closePath();\n const bbox = pointsBBox(points);\n applyFillAndStroke(ctx, props, path, inherited, color, defs, bbox);\n}\n\nexport function drawPolyline(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n inherited: InheritedSvgStyle,\n color: string,\n defs: SvgDefs,\n): void {\n const points = parsePoints(props.points as string | undefined);\n if (points.length < 2) return;\n\n const path = new Path2D();\n path.moveTo(points[0]![0], points[0]![1]);\n for (let i = 1; i < points.length; i++) {\n path.lineTo(points[i]![0], points[i]![1]);\n }\n const bbox = pointsBBox(points);\n applyFillAndStroke(ctx, props, path, inherited, color, defs, bbox);\n}\n","import { Path2D } from \"@effing/skia\";\nimport type {\n CanvasGradient,\n DOMMatrix2DInit,\n SKRSContext2D,\n} from \"@effing/skia\";\n\nimport parseCssColor from \"parse-css-color\";\n\nimport type { BBox, SvgChild, SvgDefs } from \"./types.ts\";\nimport { normalizeChildren } from \"./tree.ts\";\n\ntype Viewport = SvgDefs[\"viewport\"];\n\n/** Parse a gradient coordinate percentage/fraction to a 0–1 value. */\nfunction parseFrac(value: unknown, fallback: number): number {\n if (value == null) return fallback;\n const s = String(value);\n if (s.endsWith(\"%\")) return parseFloat(s) / 100;\n return Number(s);\n}\n\n/** True when the gradient declares `gradientUnits=\"userSpaceOnUse\"`. */\nfunction isUserSpaceOnUse(props: Record<string, unknown>): boolean {\n return props.gradientUnits === \"userSpaceOnUse\";\n}\n\n/**\n * Parse a user-space gradient coordinate. Percentages resolve against\n * `reference` (the relevant viewport dimension, per the SVG spec).\n */\nfunction parseUserLength(\n value: unknown,\n fallback: number,\n reference: number,\n): number {\n if (value == null) return fallback;\n const s = String(value);\n if (s.endsWith(\"%\")) return (parseFloat(s) / 100) * reference;\n return Number(s);\n}\n\n/** Apply opacity to a CSS color string. */\nexport function applyOpacity(color: string, opacity: number): string {\n if (opacity >= 1) return color;\n const parsed = parseCssColor(color);\n if (!parsed) return color;\n const [r, g, b] = parsed.values;\n return `rgba(${r}, ${g}, ${b}, ${parsed.alpha * opacity})`;\n}\n\n/** Add color stops from SVG `<stop>` children to a canvas gradient. */\nfunction addGradientStops(gradient: CanvasGradient, def: SvgChild): void {\n for (const stop of normalizeChildren(def)) {\n if (stop.type !== \"stop\") continue;\n const sp = stop.props;\n const offsetRaw = (sp.offset as string | number) ?? 0;\n const offset =\n typeof offsetRaw === \"string\" && offsetRaw.endsWith(\"%\")\n ? parseFloat(offsetRaw) / 100\n : Number(offsetRaw);\n const stopColor =\n ((sp.stopColor ?? sp[\"stop-color\"]) as string | undefined) ?? \"black\";\n const stopOpacity = Number(sp.stopOpacity ?? sp[\"stop-opacity\"] ?? 1);\n gradient.addColorStop(offset, applyOpacity(stopColor, stopOpacity));\n }\n}\n\n/** Create a linear gradient from bbox-relative coordinates with stops applied. */\nfunction createLinearGradientFromBBox(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n bbox: BBox,\n def: SvgChild,\n): CanvasGradient {\n const x1 = bbox.x + parseFrac(props.x1, 0) * bbox.width;\n const y1 = bbox.y + parseFrac(props.y1, 0) * bbox.height;\n const x2 = bbox.x + parseFrac(props.x2, 1) * bbox.width;\n const y2 = bbox.y + parseFrac(props.y2, 0) * bbox.height;\n const gradient = ctx.createLinearGradient(x1, y1, x2, y2);\n addGradientStops(gradient, def);\n return gradient;\n}\n\n/**\n * Create a linear gradient from `userSpaceOnUse` coordinates with stops\n * applied. The coordinates are in the SVG user coordinate system, which is\n * the context's current coordinate system (the viewBox transform is active),\n * so they map to canvas gradient coordinates directly.\n */\nfunction createLinearGradientUserSpace(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n viewport: Viewport,\n def: SvgChild,\n): CanvasGradient {\n const x1 = parseUserLength(props.x1, 0, viewport.width);\n const y1 = parseUserLength(props.y1, 0, viewport.height);\n const x2 = parseUserLength(props.x2, viewport.width, viewport.width);\n const y2 = parseUserLength(props.y2, 0, viewport.height);\n const gradient = ctx.createLinearGradient(x1, y1, x2, y2);\n addGradientStops(gradient, def);\n return gradient;\n}\n\n/**\n * Create a radial gradient from `userSpaceOnUse` coordinates with stops\n * applied. In user space the gradient is a true circle, so no elliptical\n * bbox transform is needed. Percentage radii resolve against the\n * viewport's normalized diagonal, per the SVG spec.\n */\nfunction createRadialGradientUserSpace(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n viewport: Viewport,\n def: SvgChild,\n): CanvasGradient {\n const diagonal = Math.hypot(viewport.width, viewport.height) / Math.SQRT2;\n const cx = parseUserLength(props.cx, viewport.width / 2, viewport.width);\n const cy = parseUserLength(props.cy, viewport.height / 2, viewport.height);\n const r = parseUserLength(props.r, diagonal / 2, diagonal);\n const fx = parseUserLength(props.fx, cx, viewport.width);\n const fy = parseUserLength(props.fy, cy, viewport.height);\n const gradient = ctx.createRadialGradient(fx, fy, 0, cx, cy, r);\n addGradientStops(gradient, def);\n return gradient;\n}\n\n/**\n * Fill `path` with a gradient defined by `def` in the coordinate space of `bbox`.\n *\n * With `gradientUnits=\"userSpaceOnUse\"` the gradient coordinates are already\n * in the SVG user coordinate system and are used as-is.\n *\n * With the default `objectBoundingBox` units, coordinates are fractions of\n * `bbox`. For `<linearGradient>` the bbox-to-canvas mapping is\n * straightforward. For `<radialGradient>` a non-square bbox produces an\n * *elliptical* gradient. Canvas only supports circular radial gradients, so\n * we apply a non-uniform scale transform to the context and fill an\n * inverse-transformed copy of the path.\n */\nexport function fillWithSvgGradient(\n ctx: SKRSContext2D,\n def: SvgChild,\n bbox: BBox,\n path: Path2D,\n fillRule: CanvasFillRule,\n viewport: Viewport,\n): boolean {\n const props = def.props;\n\n if (def.type === \"linearGradient\") {\n ctx.fillStyle = isUserSpaceOnUse(props)\n ? createLinearGradientUserSpace(ctx, props, viewport, def)\n : createLinearGradientFromBBox(ctx, props, bbox, def);\n ctx.fill(path, fillRule);\n return true;\n }\n\n if (def.type === \"radialGradient\" && isUserSpaceOnUse(props)) {\n ctx.fillStyle = createRadialGradientUserSpace(ctx, props, viewport, def);\n ctx.fill(path, fillRule);\n return true;\n }\n\n if (def.type === \"radialGradient\") {\n const cxF = parseFrac(props.cx, 0.5);\n const cyF = parseFrac(props.cy, 0.5);\n const rF = parseFrac(props.r, 0.5);\n const fxF = parseFrac(props.fx, cxF);\n const fyF = parseFrac(props.fy, cyF);\n\n // Render in a transformed space where the bbox maps to a unit square.\n // This turns canvas's circular radial gradient into the correct ellipse.\n ctx.save();\n ctx.translate(bbox.x, bbox.y);\n ctx.scale(bbox.width, bbox.height);\n\n const gradient = ctx.createRadialGradient(fxF, fyF, 0, cxF, cyF, rF);\n addGradientStops(gradient, def);\n ctx.fillStyle = gradient;\n\n // The path is in original (absolute) coordinates. Inverse-transform it\n // into the unit-square space so the fill aligns with the shape.\n // inverse of translate(bx,by) · scale(bw,bh) = scale(1/bw,1/bh) · translate(-bx,-by)\n const unitPath = new Path2D();\n const invTransform: DOMMatrix2DInit = {\n a: 1 / bbox.width,\n b: 0,\n c: 0,\n d: 1 / bbox.height,\n e: -bbox.x / bbox.width,\n f: -bbox.y / bbox.height,\n };\n unitPath.addPath(path, invTransform);\n\n ctx.fill(unitPath, fillRule);\n ctx.restore();\n return true;\n }\n\n return false;\n}\n\n/**\n * Stroke `path` with a gradient defined by `def` in the coordinate space of `bbox`.\n */\nexport function strokeWithSvgGradient(\n ctx: SKRSContext2D,\n def: SvgChild,\n bbox: BBox,\n path: Path2D,\n viewport: Viewport,\n): boolean {\n const props = def.props;\n\n if (def.type === \"linearGradient\") {\n ctx.strokeStyle = isUserSpaceOnUse(props)\n ? createLinearGradientUserSpace(ctx, props, viewport, def)\n : createLinearGradientFromBBox(ctx, props, bbox, def);\n ctx.stroke(path);\n return true;\n }\n\n if (def.type === \"radialGradient\" && isUserSpaceOnUse(props)) {\n ctx.strokeStyle = createRadialGradientUserSpace(ctx, props, viewport, def);\n ctx.stroke(path);\n return true;\n }\n\n if (def.type === \"radialGradient\") {\n // For stroke, use a simple circular approximation (geometric mean radius)\n const cxAbs = bbox.x + parseFrac(props.cx, 0.5) * bbox.width;\n const cyAbs = bbox.y + parseFrac(props.cy, 0.5) * bbox.height;\n const rAbs = parseFrac(props.r, 0.5) * Math.sqrt(bbox.width * bbox.height);\n const fxAbs = bbox.x + parseFrac(props.fx, 0.5) * bbox.width;\n const fyAbs = bbox.y + parseFrac(props.fy, 0.5) * bbox.height;\n const gradient = ctx.createRadialGradient(\n fxAbs,\n fyAbs,\n 0,\n cxAbs,\n cyAbs,\n rAbs,\n );\n addGradientStops(gradient, def);\n ctx.strokeStyle = gradient;\n ctx.stroke(path);\n return true;\n }\n\n return false;\n}\n","import type { Path2D, SKRSContext2D } from \"@effing/skia\";\n\nimport type { BBox, InheritedSvgStyle, SvgDefs } from \"./types.ts\";\nimport { resolveCurrentColor } from \"./style.ts\";\nimport { parseUrlRef } from \"./style.ts\";\nimport {\n applyOpacity,\n fillWithSvgGradient,\n strokeWithSvgGradient,\n} from \"./gradients.ts\";\n\nexport function applyFillAndStroke(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n path: Path2D,\n inherited: InheritedSvgStyle,\n color: string,\n defs: SvgDefs,\n bbox: BBox,\n): void {\n // Use element's own fill if set, otherwise inherit from parent\n const fill =\n resolveCurrentColor(props.fill as string | undefined, color) ??\n inherited.fill;\n const fillRule = (props.fillRule ?? props[\"fill-rule\"]) as\n CanvasFillRule | undefined;\n const fillOpacity = Number(props.fillOpacity ?? props[\"fill-opacity\"] ?? 1);\n\n // Resolve url(#id) gradient reference\n const fillRef = parseUrlRef(fill);\n if (fillRef) {\n const gradientDef = defs.gradients.get(fillRef);\n if (gradientDef) {\n if (fillOpacity < 1) {\n ctx.save();\n ctx.globalAlpha *= fillOpacity;\n fillWithSvgGradient(\n ctx,\n gradientDef,\n bbox,\n path,\n fillRule ?? \"nonzero\",\n defs.viewport,\n );\n ctx.restore();\n } else {\n fillWithSvgGradient(\n ctx,\n gradientDef,\n bbox,\n path,\n fillRule ?? \"nonzero\",\n defs.viewport,\n );\n }\n }\n } else if (fill !== \"none\") {\n ctx.fillStyle = applyOpacity(fill, fillOpacity);\n ctx.fill(path, fillRule ?? \"nonzero\");\n }\n\n applyStroke(ctx, props, path, inherited, color, defs, bbox);\n}\n\nexport function applyStroke(\n ctx: SKRSContext2D,\n props: Record<string, unknown>,\n path: Path2D,\n inherited: InheritedSvgStyle,\n color: string,\n defs: SvgDefs,\n bbox: BBox,\n): void {\n const stroke =\n resolveCurrentColor(props.stroke as string | undefined, color) ??\n inherited.stroke;\n if (!stroke || stroke === \"none\") return;\n\n const strokeOpacity = Number(\n props.strokeOpacity ??\n props[\"stroke-opacity\"] ??\n inherited.strokeOpacity ??\n 1,\n );\n\n ctx.lineWidth = Number(\n props.strokeWidth ?? props[\"stroke-width\"] ?? inherited.strokeWidth ?? 1,\n );\n ctx.lineCap = (((props.strokeLinecap ??\n props[\"stroke-linecap\"]) as CanvasLineCap) ??\n inherited.strokeLinecap ??\n \"butt\") as CanvasLineCap;\n ctx.lineJoin = (((props.strokeLinejoin ??\n props[\"stroke-linejoin\"]) as CanvasLineJoin) ??\n inherited.strokeLinejoin ??\n \"miter\") as CanvasLineJoin;\n\n // Resolve url(#id) gradient reference for stroke\n const strokeRef = parseUrlRef(stroke);\n if (strokeRef) {\n const gradientDef = defs.gradients.get(strokeRef);\n if (gradientDef) {\n if (strokeOpacity < 1) {\n ctx.save();\n ctx.globalAlpha *= strokeOpacity;\n strokeWithSvgGradient(ctx, gradientDef, bbox, path, defs.viewport);\n ctx.restore();\n } else {\n strokeWithSvgGradient(ctx, gradientDef, bbox, path, defs.viewport);\n }\n return;\n }\n }\n\n ctx.strokeStyle = applyOpacity(stroke, strokeOpacity);\n ctx.stroke(path);\n}\n","import type { Canvas, SKRSContext2D } from \"@effing/skia\";\n\nimport type { InheritedSvgStyle, SvgChild, SvgDefs } from \"./types.ts\";\nimport { EMPTY_DEFS } from \"./defs.ts\";\nimport { normalizeChildren } from \"./tree.ts\";\nimport {\n mergeStyleIntoProps,\n parseUrlRef,\n resolveInheritedStyle,\n} from \"./style.ts\";\nimport { applyTransformAndOpacity } from \"./transform.ts\";\nimport { buildClipPath } from \"./path.ts\";\nimport { applyFilter } from \"./filters.ts\";\nimport { acquireOffscreen, releaseOffscreen } from \"../offscreen.ts\";\nimport {\n drawPath,\n drawCircle,\n drawSvgRect,\n drawLine,\n drawEllipse,\n drawPolygon,\n drawPolyline,\n} from \"./shapes.ts\";\n\nexport function drawSvgChild(\n ctx: SKRSContext2D,\n child: SvgChild,\n inherited: InheritedSvgStyle,\n color: string,\n defs: SvgDefs = EMPTY_DEFS,\n vbW = 0,\n vbH = 0,\n): void {\n const { type } = child;\n const props = mergeStyleIntoProps(child.props);\n\n // Skip non-drawable definition elements\n if (\n type === \"defs\" ||\n type === \"clipPath\" ||\n type === \"mask\" ||\n type === \"filter\"\n )\n return;\n\n // Apply transform and opacity on shape elements (drawGroup handles its own)\n const transform =\n type !== \"g\" ? (props.transform as string | undefined) : undefined;\n const opacity = type !== \"g\" ? Number(props.opacity ?? 1) : 1;\n const savedTransform = applyTransformAndOpacity(ctx, transform, opacity);\n\n // Check for clip-path=\"url(#id)\" reference\n const clipRef = parseUrlRef(props.clipPath ?? props[\"clip-path\"]);\n const clipShapes = clipRef ? defs.clips.get(clipRef) : undefined;\n const clipPath = clipShapes ? buildClipPath(clipShapes, vbW, vbH) : undefined;\n\n // Check for mask=\"url(#id)\" reference\n const maskRef = parseUrlRef(props.mask as string | undefined);\n const maskShapes = maskRef ? defs.masks.get(maskRef) : undefined;\n\n // Check for filter=\"url(#id)\" reference\n const filterRef = parseUrlRef(props.filter as string | undefined);\n const filterDef = filterRef ? defs.filters.get(filterRef) : undefined;\n\n if (clipPath) {\n ctx.save();\n ctx.clip(clipPath);\n }\n\n // When a mask or filter is present, render the element to an offscreen\n // canvas so we can post-process it before drawing to the main context.\n const needsOffscreen = maskShapes || filterDef;\n let elemCanvas: Canvas | undefined;\n let targetCtx: SKRSContext2D;\n if (needsOffscreen) {\n const [c, cCtx] = acquireOffscreen(Math.ceil(vbW), Math.ceil(vbH));\n elemCanvas = c;\n targetCtx = cCtx;\n } else {\n targetCtx = ctx;\n }\n\n switch (type) {\n case \"path\":\n drawPath(targetCtx, props, inherited, color, defs);\n break;\n case \"circle\":\n drawCircle(targetCtx, props, inherited, color, defs, vbW, vbH);\n break;\n case \"rect\":\n drawSvgRect(targetCtx, props, inherited, color, defs, vbW, vbH);\n break;\n case \"line\":\n drawLine(targetCtx, props, inherited, color, defs, vbW, vbH);\n break;\n case \"ellipse\":\n drawEllipse(targetCtx, props, inherited, color, defs, vbW, vbH);\n break;\n case \"polygon\":\n drawPolygon(targetCtx, props, inherited, color, defs);\n break;\n case \"polyline\":\n drawPolyline(targetCtx, props, inherited, color, defs);\n break;\n case \"g\":\n drawGroup(targetCtx, child, props, inherited, color, defs, vbW, vbH);\n break;\n }\n\n if (needsOffscreen && elemCanvas) {\n applyOffscreenEffects(\n ctx,\n elemCanvas,\n targetCtx,\n maskShapes,\n filterDef,\n color,\n defs,\n vbW,\n vbH,\n );\n }\n\n if (clipPath) ctx.restore();\n if (savedTransform) ctx.restore();\n}\n\nfunction drawGroup(\n ctx: SKRSContext2D,\n node: SvgChild,\n mergedProps: Record<string, unknown>,\n inherited: InheritedSvgStyle,\n color: string,\n defs: SvgDefs = EMPTY_DEFS,\n vbW = 0,\n vbH = 0,\n): void {\n const children = normalizeChildren(node);\n if (children.length === 0) return;\n const groupInherited = resolveInheritedStyle(mergedProps, color, inherited);\n\n const opacity = Number(mergedProps.opacity ?? 1);\n const transform = mergedProps.transform as string | undefined;\n const saved = applyTransformAndOpacity(ctx, transform, opacity);\n\n for (const child of children) {\n if (child != null && typeof child === \"object\") {\n drawSvgChild(ctx, child, groupInherited, color, defs, vbW, vbH);\n }\n }\n\n if (saved) ctx.restore();\n}\n\n/** Composite mask and/or filter effects from offscreen canvas onto main context. */\nfunction applyOffscreenEffects(\n ctx: SKRSContext2D,\n elemCanvas: Canvas,\n targetCtx: SKRSContext2D,\n maskShapes: SvgChild[] | undefined,\n filterDef: SvgChild | undefined,\n color: string,\n defs: SvgDefs,\n vbW: number,\n vbH: number,\n): void {\n // Apply mask if present\n if (maskShapes) {\n const [maskCanvas, maskCtx] = acquireOffscreen(\n Math.ceil(vbW),\n Math.ceil(vbH),\n );\n for (const shape of maskShapes) {\n drawSvgChild(maskCtx, shape, { fill: \"white\" }, \"white\", defs, vbW, vbH);\n }\n targetCtx.globalCompositeOperation = \"destination-in\";\n targetCtx.drawImage(maskCanvas, 0, 0);\n targetCtx.globalCompositeOperation = \"source-over\";\n releaseOffscreen(maskCanvas);\n }\n\n // Apply filter if present\n if (filterDef) {\n const filteredCanvas = applyFilter(\n filterDef,\n elemCanvas,\n Math.ceil(vbW),\n Math.ceil(vbH),\n );\n ctx.drawImage(filteredCanvas, 0, 0);\n // Release intermediates (filteredCanvas may be elemCanvas if no-op)\n if (filteredCanvas !== elemCanvas) releaseOffscreen(filteredCanvas);\n } else {\n ctx.drawImage(elemCanvas, 0, 0);\n }\n releaseOffscreen(elemCanvas);\n}\n","import type { SKRSContext2D } from \"@effing/skia\";\n\nimport type { LayoutNode } from \"../../layout.ts\";\nimport type { SvgChild } from \"./types.ts\";\nimport { mergeStyleIntoProps, resolveInheritedStyle } from \"./style.ts\";\nimport { collectDefs } from \"./defs.ts\";\nimport { drawSvgChild } from \"./traverse.ts\";\n\n/**\n * Draw an `<svg>` container and its SVG children (path, circle, rect, etc.).\n *\n * Parses the `viewBox` prop to compute scale factors, then recurses into\n * the React children stored in `node.props.children`.\n */\nexport function drawSvgContainer(\n ctx: SKRSContext2D,\n node: LayoutNode,\n x: number,\n y: number,\n width: number,\n height: number,\n): void {\n ctx.save();\n ctx.translate(x, y);\n\n // Parse viewBox for coordinate mapping; default to rendered size when absent\n const viewBox = node.props.viewBox as string | undefined;\n let vbW = width;\n let vbH = height;\n if (viewBox) {\n const parts = viewBox.split(/[\\s,]+/).map(Number);\n if (parts.length === 4) {\n const [vbX, vbY, parsedW, parsedH] = parts as [\n number,\n number,\n number,\n number,\n ];\n vbW = parsedW;\n vbH = parsedH;\n const scaleX = width / vbW;\n const scaleY = height / vbH;\n ctx.scale(scaleX, scaleY);\n ctx.translate(-vbX, -vbY);\n }\n }\n\n // Resolve the CSS `color` property for `currentColor` references\n const color = (node.style.color as string | undefined) ?? \"black\";\n\n // Build inherited SVG style from the <svg> element\n const merged = mergeStyleIntoProps(node.props);\n const inherited = resolveInheritedStyle(merged, color);\n\n // Traverse React children\n const children = node.props.children;\n if (children != null) {\n // Deep-flatten so helpers returning arrays don't slip nested arrays through\n // to the defs collector or shape switch (both expect element-shaped nodes).\n const childArray = (\n Array.isArray(children) ? children.flat(Infinity) : [children]\n ) as unknown[];\n const svgChildren = childArray.filter(\n (c): c is SvgChild =>\n c != null && typeof c === \"object\" && !Array.isArray(c),\n );\n\n // First pass: collect definitions from <defs>\n const defs = collectDefs(svgChildren, vbW, vbH);\n\n // Second pass: draw children\n for (const child of svgChildren) {\n drawSvgChild(ctx, child, inherited, color, defs, vbW, vbH);\n }\n }\n\n ctx.restore();\n}\n","import { loadImage } from \"@effing/skia\";\nimport type { SKRSContext2D, Image } from \"@effing/skia\";\nimport { fillParagraph, strokeParagraph } from \"@effing/skia/extensions\";\n\nimport parseCssColor from \"parse-css-color\";\n\nimport type { EmojiStyle } from \"../emoji.ts\";\nimport { emojiUrl, loadEmoji } from \"../emoji.ts\";\nimport type {\n PlacedEmoji,\n TextLayoutResult,\n TextSegment,\n} from \"../text/index.ts\";\nimport { setFont } from \"../text/measure.ts\";\nimport type { Shadow } from \"./shadow.ts\";\nimport { parseTextShadow } from \"./shadow.ts\";\n\nconst emojiImageCache = new Map<string, Promise<Image | null>>();\n\nfunction loadEmojiImage(\n style: EmojiStyle,\n emoji: string,\n): Promise<Image | null> {\n const key = emojiUrl(style, emoji);\n let cached = emojiImageCache.get(key);\n if (!cached) {\n cached = loadEmoji(style, emoji)\n .then((svgText) => {\n if (!svgText || !svgText.includes(\"<svg\")) return null;\n const dataUri =\n \"data:image/svg+xml;base64,\" +\n Buffer.from(svgText).toString(\"base64\");\n return loadImage(dataUri);\n })\n .catch(() => null);\n emojiImageCache.set(key, cached);\n }\n return cached;\n}\n\n/**\n * Draw laid-out text onto the canvas context: the paragraph, unhinted and\n * unsnapped, with its shadow, stroke and decorations, and the emoji drawn as\n * images in the inline boxes it left them.\n *\n * @param ctx - Canvas 2D rendering context\n * @param layout - The text as laid out by `layoutText`\n * @param offsetX - X offset for the text block\n * @param offsetY - Y offset for the text block\n * @param textShadow - Optional text-shadow CSS value\n * @param emojiStyle - The emoji style the text was laid out for, if any\n */\nexport async function drawText(\n ctx: SKRSContext2D,\n layout: TextLayoutResult,\n offsetX: number,\n offsetY: number,\n textShadow?: string,\n emojiStyle?: EmojiStyle,\n): Promise<void> {\n const { paragraph, segments, emoji } = layout;\n const first = segments[0];\n if (!first) return;\n const x = offsetX;\n const y = offsetY + layout.paragraphOffsetY;\n const shadows = textShadow ? parseTextShadow(textShadow, first.color) : [];\n ctx.fillStyle = first.color;\n\n // Each pass is a single native call for the whole paragraph. The shadows\n // paint back to front: the first listed is on top.\n for (let i = shadows.length - 1; i >= 0; i--) {\n drawShadowPass(ctx, shadows[i]!, getColorAlpha(first.color), () =>\n fillParagraph(ctx, paragraph, x, y),\n );\n }\n if (first.textStrokeWidth !== undefined && first.textStrokeWidth > 0) {\n ctx.save();\n ctx.lineWidth = first.textStrokeWidth;\n ctx.strokeStyle = first.textStrokeColor ?? first.color;\n ctx.lineJoin = \"round\";\n strokeParagraph(ctx, paragraph, x, y);\n ctx.restore();\n }\n fillParagraph(ctx, paragraph, x, y);\n\n if (emojiStyle && emoji.length > 0) {\n await drawEmoji(ctx, emoji, first, offsetX, offsetY, emojiStyle);\n }\n\n for (const seg of segments) {\n if (seg.textDecoration) {\n drawTextDecoration(ctx, seg, offsetX, offsetY);\n }\n }\n}\n\nasync function drawEmoji(\n ctx: SKRSContext2D,\n emoji: PlacedEmoji[],\n font: TextSegment,\n offsetX: number,\n offsetY: number,\n emojiStyle: EmojiStyle,\n): Promise<void> {\n const images = await Promise.all(\n emoji.map((e) => loadEmojiImage(emojiStyle, e.grapheme)),\n );\n emoji.forEach((e, i) => {\n const img = images[i];\n if (img) {\n ctx.drawImage(img, offsetX + e.x, offsetY + e.y, e.size, e.size);\n return;\n }\n // Emoji image unavailable: draw it as text, in its box on the baseline.\n setFont(\n ctx,\n font.fontSize,\n font.fontFamily,\n font.fontWeight,\n font.fontStyle,\n );\n const textRendering = ctx.textRendering;\n ctx.textRendering = \"geometricPrecision\";\n ctx.fillText(e.grapheme, offsetX + e.x, offsetY + e.baseline);\n ctx.textRendering = textRendering;\n });\n}\n\n/** Extract the alpha component from a CSS color string. */\nfunction getColorAlpha(color: string): number {\n const parsed = parseCssColor(color);\n return parsed ? parsed.alpha : 1;\n}\n\n/**\n * Draw the text shadow manually instead of using the canvas shadow API.\n *\n * CSS text-shadow renders the shadow as if derived from the text's painted\n * appearance, so when the text color has alpha < 1 the shadow is also\n * attenuated. The canvas shadow API does NOT do this — it always renders\n * the shadow at the full specified opacity. We match CSS behavior by\n * drawing the shadow as a separate fillParagraph at the offset, with\n * globalAlpha scaled by the text color's alpha.\n */\nfunction drawShadowPass(\n ctx: SKRSContext2D,\n shadow: Shadow,\n textAlpha: number,\n drawFn: () => void,\n): void {\n ctx.save();\n // An invalid colour leaves the fill as it was: make that no colour.\n ctx.fillStyle = \"rgba(0, 0, 0, 0)\";\n ctx.fillStyle = shadow.color;\n if (textAlpha < 1) ctx.globalAlpha *= textAlpha;\n if (shadow.blur > 0) ctx.filter = `blur(${shadow.blur / 2}px)`;\n ctx.translate(shadow.offsetX, shadow.offsetY);\n drawFn();\n ctx.restore();\n}\n\nfunction drawTextDecoration(\n ctx: SKRSContext2D,\n seg: TextSegment,\n offsetX: number,\n offsetY: number,\n): void {\n const decoration = seg.textDecoration;\n if (!decoration || decoration === \"none\") return;\n\n ctx.strokeStyle = seg.color;\n ctx.lineWidth = Math.max(1, seg.fontSize * 0.1);\n\n const x = offsetX + seg.x;\n const baseY = offsetY + seg.y;\n\n if (decoration.includes(\"underline\")) {\n const y = baseY + seg.ascent * 0.1;\n ctx.beginPath();\n ctx.moveTo(x, y);\n ctx.lineTo(x + seg.width, y);\n ctx.stroke();\n }\n\n if (decoration.includes(\"line-through\")) {\n const y = baseY - seg.fontSize * 0.3;\n ctx.beginPath();\n ctx.moveTo(x, y);\n ctx.lineTo(x + seg.width, y);\n ctx.stroke();\n }\n\n if (decoration.includes(\"overline\")) {\n const y = baseY - seg.fontSize * 0.85;\n ctx.beginPath();\n ctx.moveTo(x, y);\n ctx.lineTo(x + seg.width, y);\n ctx.stroke();\n }\n}\n","// This file contains code adapted from Satori (https://github.com/vercel/satori)\n// Licensed under the Mozilla Public License 2.0 (MPL-2.0)\n// See NOTICE.md in the package root for details.\n\nimport { UNASSIGNED_PICTOGRAPHIC } from \"./language.ts\";\n\n/**\n * Emoji style options for rendering\n */\nexport type EmojiStyle =\n \"twemoji\" | \"openmoji\" | \"blobmoji\" | \"noto\" | \"fluent\" | \"fluentFlat\";\n\nconst FE0F = 0xfe0f;\nconst ZWJ = 0x200d;\nconst KEYCAP = 0x20e3;\n\nconst EMOJI_CHAR = /[\\p{Emoji}\\p{Extended_Pictographic}]/u;\n// Presented as an emoji without U+FE0F: by default, or (unassigned in this\n// runtime's Unicode) as every emoji added since Unicode 9 is.\nconst EMOJI_PRESENTATION = new RegExp(\n String.raw`\\p{Emoji_Presentation}|${UNASSIGNED_PICTOGRAPHIC}`,\n \"u\",\n);\nconst EMOJI_MODIFIER = /\\p{Emoji_Modifier}/u;\n\n/**\n * An emoji's code points in its fully-qualified form (UTS #51), which names\n * its image in every style: U+FE0F after each element that is text by default\n * (©️, the ♂️ in 🏃‍♂️, the 🏳️ in 🏳️‍🌈, the 1️ in 1️⃣), unless an emoji modifier\n * follows it (☝🏽).\n */\nfunction qualifiedCodePoints(emoji: string): number[] {\n const chars = [...emoji].filter((c) => c.codePointAt(0) !== FE0F);\n const codePoints: number[] = [];\n chars.forEach((char, i) => {\n codePoints.push(char.codePointAt(0)!);\n const startsElement = i === 0 || chars[i - 1] === \"\\u200D\";\n if (\n startsElement &&\n EMOJI_CHAR.test(char) &&\n !EMOJI_PRESENTATION.test(char) &&\n !EMOJI_MODIFIER.test(chars[i + 1] ?? \"\")\n ) {\n codePoints.push(FE0F);\n }\n });\n return codePoints;\n}\n\nfunction hex(codePoints: number[], pad = 0): string {\n return codePoints.map((cp) => cp.toString(16).padStart(pad, \"0\")).join(\"-\");\n}\n\n/**\n * Twemoji's file name: lowercase hex code points, with U+FE0F dropped unless\n * the emoji is a ZWJ sequence (its own `grabTheRightIcon` rule), and from\n * 👁️‍🗨️, the one ZWJ sequence it names without them.\n */\nfunction twemojiCode(codePoints: number[]): string {\n const code = hex(\n codePoints.includes(ZWJ)\n ? codePoints\n : codePoints.filter((cp) => cp !== FE0F),\n );\n return code === \"1f441-fe0f-200d-1f5e8-fe0f\" ? \"1f441-200d-1f5e8\" : code;\n}\n\n/**\n * Svgmoji's file name (OpenMoji, Blobmoji and Noto): Emojibase hexcodes,\n * uppercase and padded to four digits, with U+FE0F kept only in ZWJ and\n * keycap sequences.\n */\nfunction svgmojiCode(codePoints: number[]): string {\n const keepFE0F = codePoints.includes(ZWJ) || codePoints.includes(KEYCAP);\n return hex(\n keepFE0F ? codePoints : codePoints.filter((cp) => cp !== FE0F),\n 4,\n ).toUpperCase();\n}\n\n/**\n * Fluent's file name: the fully-qualified emoji itself. Its hex names are\n * inconsistent about U+FE0F (`1f590-fe0f`, but `2764-200d-1f525`), so they\n * miss emoji that the glyph names cover.\n */\nfunction fluentCode(codePoints: number[]): string {\n return encodeURIComponent(String.fromCodePoint(...codePoints));\n}\n\nconst emojiUrls: Record<EmojiStyle, (codePoints: number[]) => string> = {\n twemoji: (cps) =>\n `https://cdnjs.cloudflare.com/ajax/libs/twemoji/16.0.1/svg/${twemojiCode(cps)}.svg`,\n openmoji: (cps) =>\n `https://cdn.jsdelivr.net/npm/@svgmoji/openmoji@2.0.0/svg/${svgmojiCode(cps)}.svg`,\n blobmoji: (cps) =>\n `https://cdn.jsdelivr.net/npm/@svgmoji/blob@2.0.0/svg/${svgmojiCode(cps)}.svg`,\n noto: (cps) =>\n `https://cdn.jsdelivr.net/gh/svgmoji/svgmoji/packages/svgmoji__noto/svg/${svgmojiCode(cps)}.svg`,\n fluent: (cps) =>\n `https://cdn.jsdelivr.net/gh/shuding/fluentui-emoji-unicode/assets/${fluentCode(cps)}_color.svg`,\n fluentFlat: (cps) =>\n `https://cdn.jsdelivr.net/gh/shuding/fluentui-emoji-unicode/assets/${fluentCode(cps)}_flat.svg`,\n};\n\n/**\n * The URL of an emoji's SVG image in a style. The emoji may be fully,\n * minimally or not qualified (🏳️‍🌈, or the unqualified 🏳‍🌈): each style names its images\n * after the fully-qualified form, in its own way.\n *\n * @param style - The emoji style\n * @param emoji - One emoji grapheme cluster\n */\nexport function emojiUrl(style: EmojiStyle, emoji: string): string {\n return emojiUrls[style](qualifiedCodePoints(emoji));\n}\n\nconst emojiCache: Record<string, Promise<string>> = {};\n\n/**\n * Fetch an emoji's SVG image in a style, once per URL.\n *\n * @param style - The emoji style\n * @param emoji - One emoji grapheme cluster\n */\nexport async function loadEmoji(\n style: EmojiStyle,\n emoji: string,\n): Promise<string> {\n const url = emojiUrl(style, emoji);\n return (emojiCache[url] ??= fetch(url).then((r) => r.text()));\n}\n","import type { SKRSContext2D } from \"@effing/skia\";\n\nimport type { EmojiStyle } from \"../emoji.ts\";\nimport { cachedLoadImage } from \"../../image.ts\";\nimport type { LayoutNode } from \"../layout.ts\";\nimport type { RenderContext } from \"../context.ts\";\nimport { layoutText } from \"../text/index.ts\";\nimport { applyClip, hasRadius, roundedRect } from \"./clip.ts\";\nimport { applyClipPath } from \"./clip-path.ts\";\nimport { createGradientFromCSS, splitGradientArgs } from \"./gradient.ts\";\nimport {\n beginElementGroup,\n drawBackdropFilter,\n endElementGroup,\n} from \"./group.ts\";\nimport { drawImage } from \"./image.ts\";\nimport { computeContain, computeCover } from \"./object-fit.ts\";\nimport {\n drawBoxShadow,\n drawInsetBoxShadow,\n drawRect,\n getBorderRadiusFromStyle,\n} from \"./rect.ts\";\nimport { parseBoxShadow } from \"./shadow.ts\";\nimport { drawSvgContainer } from \"./svg/index.ts\";\nimport { drawText } from \"./text.ts\";\nimport { parseCSSLength, resolveBoxValue } from \"./utils.ts\";\n\n/**\n * Main draw dispatcher: recursively draws the layout tree onto the canvas.\n *\n * Every node, scaled or not, is drawn straight through its transform. Text is\n * drawn unhinted and unsnapped (see `drawText`), so it lands in the same place\n * at any scale and a scaled subtree needs no supersampled offscreen buffer.\n */\nexport async function drawNode(\n ctx: SKRSContext2D,\n node: LayoutNode,\n parentX: number,\n parentY: number,\n context?: RenderContext,\n emojiStyle?: EmojiStyle,\n): Promise<void> {\n const x = parentX + node.x;\n const y = parentY + node.y;\n const { style } = node;\n\n // Resolve a context once so the whole subtree shares one image cache.\n const renderContext: RenderContext = context ?? {\n imageCache: new Map(),\n debug: false,\n };\n\n if (style.display === \"none\") return;\n\n // A numeric string counts, as it does in CSS; anything that isn't a\n // number leaves the element opaque.\n const rawOpacity = Number(style.opacity ?? 1);\n const opacity = Number.isFinite(rawOpacity) ? rawOpacity : 1;\n if (opacity <= 0) return;\n\n // Painting awaits image loads, which can fail. The group and the save are\n // closed either way, so a caller that catches the error and draws the next\n // frame on this context doesn't paint into a layer left open.\n const group = { open: false };\n ctx.save();\n try {\n await paintNode(ctx, node, x, y, opacity, renderContext, emojiStyle, group);\n } finally {\n if (group.open) endElementGroup(ctx);\n ctx.restore();\n }\n}\n\n/** Paints a node inside the save that `drawNode` opened for it. */\nasync function paintNode(\n ctx: SKRSContext2D,\n node: LayoutNode,\n x: number,\n y: number,\n opacity: number,\n renderContext: RenderContext,\n emojiStyle: EmojiStyle | undefined,\n group: { open: boolean },\n): Promise<void> {\n const { width, height, style } = node;\n\n if (style.transform) {\n applyTransform(\n ctx,\n style.transform,\n x,\n y,\n width,\n height,\n style.transformOrigin,\n );\n }\n\n // Apply clip-path — in the element's own (transformed) coordinate space, and\n // before anything is painted, since it clips the element's entire rendering\n // including its box-shadow.\n if (style.clipPath) {\n applyClipPath(ctx, style.clipPath, style, x, y, width, height);\n }\n\n const borderRadius = getBorderRadiusFromStyle(style, width, height);\n\n // Filter the backdrop behind the border box before anything of the element\n // itself is painted: its box-shadow must not end up in the backdrop, and its\n // background composites on top of the filtered result.\n if (style.backdropFilter) {\n drawBackdropFilter(\n ctx,\n style.backdropFilter,\n x,\n y,\n width,\n height,\n borderRadius,\n opacity,\n );\n }\n\n // The element's own painting and its descendants form one group, composited\n // with its opacity and filter. CSS applies clip-path after the filter, so the\n // clip above also clips the filtered result. The backdrop above stays outside\n // the group: a group's backdrop is read from the enclosing one.\n group.open = beginElementGroup(ctx, opacity, style.filter);\n\n // Draw outer box shadows BEFORE overflow clip — CSS overflow:hidden clips children,\n // not the element's own box-shadow.\n const boxShadows = style.boxShadow\n ? parseBoxShadow(style.boxShadow, style.color ?? \"black\")\n : [];\n drawBoxShadow(ctx, x, y, width, height, boxShadows, borderRadius);\n\n // Apply clipping for overflow: hidden\n const isClipped =\n style.overflow === \"hidden\" ||\n style.overflowX === \"hidden\" ||\n style.overflowY === \"hidden\";\n\n if (isClipped) {\n applyClip(ctx, x, y, width, height, borderRadius);\n }\n\n // Draw background and borders\n if (\n style.backgroundColor ||\n style.borderTopWidth ||\n style.borderRightWidth ||\n style.borderBottomWidth ||\n style.borderLeftWidth\n ) {\n drawRect(ctx, x, y, width, height, style);\n }\n\n // Draw background-image (gradient or url) — supports multiple comma-separated layers\n if (style.backgroundImage) {\n const layers = splitGradientArgs(style.backgroundImage);\n // CSS paints last layer first (bottommost)\n for (let i = layers.length - 1; i >= 0; i--) {\n const layer = layers[i]!.trim();\n const gradient = createGradientFromCSS(ctx, layer, x, y, width, height);\n if (gradient) {\n ctx.fillStyle = gradient;\n if (hasRadius(borderRadius)) {\n ctx.beginPath();\n roundedRect(\n ctx,\n x,\n y,\n width,\n height,\n borderRadius.topLeft,\n borderRadius.topRight,\n borderRadius.bottomRight,\n borderRadius.bottomLeft,\n );\n ctx.fill();\n } else {\n ctx.fillRect(x, y, width, height);\n }\n } else {\n // Try url(...) background image\n const urlMatch = layer.match(/url\\([\"']?(.*?)[\"']?\\)/);\n if (urlMatch) {\n // Load the image first, so that nothing awaits inside the save.\n const image = await cachedLoadImage(\n renderContext.imageCache,\n urlMatch[1]!,\n renderContext.userAgent,\n );\n const bgSize = style.backgroundSize;\n\n // Clipped to the border box (rounded or not), as CSS's default\n // `background-clip: border-box` does, so that an image or tile\n // larger than the box doesn't paint past it. The clip is the\n // background's alone: restored after it, so that it doesn't clip\n // the text, image and children painted next.\n ctx.save();\n applyClip(ctx, x, y, width, height, borderRadius);\n\n if (bgSize === \"cover\") {\n // Cover fills the box completely — no tiling needed\n const r = computeCover(\n image.width,\n image.height,\n x,\n y,\n width,\n height,\n );\n ctx.drawImage(\n image,\n r.sx,\n r.sy,\n r.sw,\n r.sh,\n r.dx,\n r.dy,\n r.dw,\n r.dh,\n );\n } else {\n // Compute tile dimensions based on backgroundSize\n let tileW: number, tileH: number;\n if (bgSize === \"contain\") {\n const r = computeContain(\n image.width,\n image.height,\n 0,\n 0,\n width,\n height,\n );\n tileW = r.dw;\n tileH = r.dh;\n } else if (bgSize === \"100% 100%\") {\n tileW = width;\n tileH = height;\n } else {\n // CSS default (auto): natural image size\n tileW = image.width;\n tileH = image.height;\n }\n // A zero-size image (or a tile size that isn't finite) paints\n // nothing, and would step the tiling loops by 0 forever.\n const drawable =\n tileW > 0 &&\n tileH > 0 &&\n Number.isFinite(tileW) &&\n Number.isFinite(tileH);\n const repeat = style.backgroundRepeat ?? \"repeat\";\n const stepX =\n repeat === \"repeat\" || repeat === \"repeat-x\" ? tileW : width;\n const stepY =\n repeat === \"repeat\" || repeat === \"repeat-y\" ? tileH : height;\n if (drawable) {\n for (let ty = y; ty < y + height; ty += stepY) {\n for (let tx = x; tx < x + width; tx += stepX) {\n ctx.drawImage(image, tx, ty, tileW, tileH);\n }\n }\n }\n }\n ctx.restore();\n }\n }\n }\n }\n\n // Inset box shadows paint over the background, inside the padding box.\n drawInsetBoxShadow(ctx, x, y, width, height, boxShadows, borderRadius, style);\n\n // Debug: draw bounding boxes\n if (renderContext.debug) {\n ctx.strokeStyle = \"rgba(255, 0, 0, 0.5)\";\n ctx.lineWidth = 1;\n ctx.strokeRect(x, y, width, height);\n }\n\n // Draw text content\n if (node.textContent !== undefined && node.textContent !== \"\") {\n const paddingTop = resolveBoxValue(style.paddingTop, width);\n const paddingLeft = resolveBoxValue(style.paddingLeft, width);\n const paddingRight = resolveBoxValue(style.paddingRight, width);\n\n const borderTopW = resolveBoxValue(style.borderTopWidth, width);\n const borderLeftW = resolveBoxValue(style.borderLeftWidth, width);\n const borderRightW = resolveBoxValue(style.borderRightWidth, width);\n\n const contentX = x + paddingLeft + borderLeftW;\n const contentY = y + paddingTop + borderTopW;\n const contentWidth =\n width - paddingLeft - paddingRight - borderLeftW - borderRightW;\n\n // Text nodes come laid out at their width from the layout phase.\n const textLayout =\n node.textLayout && contentWidth === node.width\n ? node.textLayout\n : layoutText(node.textContent, style, contentWidth, !!emojiStyle);\n await drawText(\n ctx,\n textLayout,\n contentX,\n contentY,\n style.textShadow,\n emojiStyle,\n );\n }\n\n // Draw <img> elements\n if (node.type === \"img\" && node.props.src) {\n const paddingTop = resolveBoxValue(style.paddingTop, width);\n const paddingLeft = resolveBoxValue(style.paddingLeft, width);\n const paddingRight = resolveBoxValue(style.paddingRight, width);\n const paddingBottom = resolveBoxValue(style.paddingBottom, width);\n\n const borderTopW = resolveBoxValue(style.borderTopWidth, width);\n const borderLeftW = resolveBoxValue(style.borderLeftWidth, width);\n const borderRightW = resolveBoxValue(style.borderRightWidth, width);\n const borderBottomW = resolveBoxValue(style.borderBottomWidth, width);\n\n const imgX = x + paddingLeft + borderLeftW;\n const imgY = y + paddingTop + borderTopW;\n const imgW =\n width - paddingLeft - paddingRight - borderLeftW - borderRightW;\n const imgH =\n height - paddingTop - paddingBottom - borderTopW - borderBottomW;\n\n // Images are replaced content — borderRadius clips them directly\n // (unlike child content which requires overflow:hidden)\n if (!isClipped) {\n if (hasRadius(borderRadius)) {\n applyClip(ctx, imgX, imgY, imgW, imgH, borderRadius);\n }\n }\n\n await drawImage(\n ctx,\n node.props.src as string | Buffer,\n imgX,\n imgY,\n imgW,\n imgH,\n renderContext,\n style,\n );\n }\n\n // Draw <svg> containers (handle their own child traversal in SVG coordinate space)\n if (node.type === \"svg\") {\n drawSvgContainer(ctx, node, x, y, width, height);\n } else {\n for (const child of node.children) {\n await drawNode(ctx, child, x, y, renderContext, emojiStyle);\n }\n }\n}\n\nfunction applyTransform(\n ctx: SKRSContext2D,\n transform: string,\n x: number,\n y: number,\n width: number,\n height: number,\n transformOrigin?: string,\n): void {\n // Resolve transform-origin (default: center)\n let ox = x + width / 2;\n let oy = y + height / 2;\n\n if (transformOrigin) {\n const parts = transformOrigin.split(/\\s+/);\n ox = resolveOrigin(parts[0], x, width);\n oy = resolveOrigin(parts[1], y, height);\n }\n\n ctx.translate(ox, oy);\n\n // Parse and apply transform functions\n const funcs = transform.matchAll(/(\\w+)\\(([^)]+)\\)/g);\n\n for (const [, name, args] of funcs) {\n const values = args!.split(\",\").map((s) => s.trim());\n\n switch (name) {\n case \"translate\":\n case \"translateX\":\n case \"translateY\": {\n const tx =\n name === \"translateY\" ? 0 : parseCSSLength(values[0]!, width);\n const ty =\n name === \"translateX\"\n ? 0\n : parseCSSLength(\n values[name === \"translate\" ? 1 : 0] ?? \"0\",\n height,\n );\n ctx.translate(tx, ty);\n break;\n }\n case \"scale\":\n case \"scaleX\":\n case \"scaleY\": {\n const sx = name === \"scaleY\" ? 1 : parseFloat(values[0]!);\n const sy =\n name === \"scaleX\"\n ? 1\n : parseFloat(values[name === \"scale\" ? 1 : 0] ?? String(sx));\n ctx.scale(sx, sy);\n break;\n }\n case \"rotate\": {\n const angle = parseAngle(values[0]!);\n ctx.rotate(angle);\n break;\n }\n case \"skewX\": {\n const angle = parseAngle(values[0]!);\n ctx.transform(1, 0, Math.tan(angle), 1, 0, 0);\n break;\n }\n case \"skewY\": {\n const angle = parseAngle(values[0]!);\n ctx.transform(1, Math.tan(angle), 0, 1, 0, 0);\n break;\n }\n }\n }\n\n ctx.translate(-ox, -oy);\n}\n\nfunction resolveOrigin(\n value: string | undefined,\n base: number,\n size: number,\n): number {\n if (!value) return base + size / 2;\n if (value === \"left\" || value === \"top\") return base;\n if (value === \"right\" || value === \"bottom\") return base + size;\n if (value === \"center\") return base + size / 2;\n return base + parseCSSLength(value, size);\n}\n\nfunction parseAngle(value: string): number {\n if (value.endsWith(\"deg\")) return (parseFloat(value) * Math.PI) / 180;\n if (value.endsWith(\"rad\")) return parseFloat(value);\n if (value.endsWith(\"turn\")) return parseFloat(value) * 2 * Math.PI;\n return parseFloat(value);\n}\n","import { GlobalFonts } from \"@effing/skia\";\n\nimport type { FontData } from \"../types.ts\";\n\nconst registeredFonts = new Set<string>();\n\n/**\n * Register a font from a FontData buffer.\n * Registration is idempotent — re-registering the same font name is a no-op.\n *\n * @param font - Font data to register\n */\nexport function registerFont(font: FontData): void {\n const key = `${font.name}:${font.weight}:${font.style}`;\n if (registeredFonts.has(key)) return;\n\n const buffer = Buffer.isBuffer(font.data)\n ? font.data\n : Buffer.from(font.data);\n\n GlobalFonts.register(buffer, font.name);\n\n registeredFonts.add(key);\n}\n\n/**\n * Register a font from a file path.\n *\n * @param path - Path to the font file\n * @param nameAlias - Optional font family name override\n */\nexport function registerFontFromPath(path: string, nameAlias?: string): void {\n GlobalFonts.registerFromPath(path, nameAlias ?? \"\");\n}\n\n/**\n * Get the list of registered font family names.\n *\n * @returns Array of font family names\n */\nexport function registeredFamilies(): string[] {\n return GlobalFonts.families.map((f: { family: string }) => f.family);\n}\n\n/**\n * Ensure all fonts from the given array are registered.\n * Called internally by `renderReactElement()`.\n */\nexport function ensureFontsRegistered(fonts: FontData[]): void {\n for (const font of fonts) {\n registerFont(font);\n }\n}\n","// This file contains code adapted from Satori (https://github.com/vercel/satori)\n// Licensed under the Mozilla Public License 2.0 (MPL-2.0)\n// See NOTICE.md in the package root for details.\n\nimport { splitGradientArgs } from \"../draw/gradient.ts\";\nimport type { ExpandedStyle } from \"./compute.ts\";\n\ntype RawStyle = Record<string, unknown>;\n\nconst SIDES = [\"Top\", \"Right\", \"Bottom\", \"Left\"] as const;\n\n/**\n * Parse a CSS shorthand value like \"10px 20px\" into 1-4 parts.\n */\nfunction parseSides(value: string): string[] {\n const parts = value.toString().split(/\\s+/).filter(Boolean);\n switch (parts.length) {\n case 1:\n return [parts[0]!, parts[0]!, parts[0]!, parts[0]!];\n case 2:\n return [parts[0]!, parts[1]!, parts[0]!, parts[1]!];\n case 3:\n return [parts[0]!, parts[1]!, parts[2]!, parts[1]!];\n default:\n return [parts[0]!, parts[1]!, parts[2]!, parts[3]!];\n }\n}\n\nfunction parseValue(v: unknown): number | string | undefined {\n if (v === undefined || v === null) return undefined;\n const s = String(v);\n if (s === \"auto\") return \"auto\";\n const n = Number(s);\n if (s !== \"\" && !isNaN(n)) return n;\n return s;\n}\n\n/**\n * Expand CSS shorthand properties into their longhand equivalents.\n * Mutates and returns the style object.\n */\nexport function expandStyle(\n raw: RawStyle,\n fontFamilies?: string[],\n): ExpandedStyle {\n const style = { ...raw } as Record<string, unknown>;\n\n // margin shorthand\n if (style.margin !== undefined) {\n const sides = parseSides(String(style.margin));\n for (let i = 0; i < 4; i++) {\n const key = `margin${SIDES[i]}`;\n if (style[key] === undefined) style[key] = parseValue(sides[i]);\n }\n delete style.margin;\n }\n\n // padding shorthand\n if (style.padding !== undefined) {\n const sides = parseSides(String(style.padding));\n for (let i = 0; i < 4; i++) {\n const key = `padding${SIDES[i]}`;\n if (style[key] === undefined) style[key] = parseValue(sides[i]);\n }\n delete style.padding;\n }\n\n // borderRadius shorthand\n if (style.borderRadius !== undefined) {\n const sides = parseSides(String(style.borderRadius));\n const corners = [\n \"borderTopLeftRadius\",\n \"borderTopRightRadius\",\n \"borderBottomRightRadius\",\n \"borderBottomLeftRadius\",\n ];\n for (let i = 0; i < 4; i++) {\n if (style[corners[i]!] === undefined)\n style[corners[i]!] = parseValue(sides[i]);\n }\n delete style.borderRadius;\n }\n\n // borderWidth shorthand\n if (style.borderWidth !== undefined) {\n const sides = parseSides(String(style.borderWidth));\n for (let i = 0; i < 4; i++) {\n const key = `border${SIDES[i]}Width`;\n if (style[key] === undefined) style[key] = parseValue(sides[i]);\n }\n delete style.borderWidth;\n }\n\n // borderColor shorthand\n if (style.borderColor !== undefined) {\n const val = style.borderColor;\n for (const side of SIDES) {\n const key = `border${side}Color`;\n if (style[key] === undefined) style[key] = val;\n }\n delete style.borderColor;\n }\n\n // borderStyle shorthand\n if (style.borderStyle !== undefined) {\n const val = style.borderStyle;\n for (const side of SIDES) {\n const key = `border${side}Style`;\n if (style[key] === undefined) style[key] = val;\n }\n delete style.borderStyle;\n }\n\n // border shorthand (e.g. \"1px solid black\")\n if (style.border !== undefined) {\n const parts = String(style.border).split(/\\s+/);\n const width = parseValue(parts[0]);\n const borderStyle = parts[1] ?? \"solid\";\n const color = parts[2] ?? \"black\";\n for (const side of SIDES) {\n if (style[`border${side}Width`] === undefined)\n style[`border${side}Width`] = width;\n if (style[`border${side}Style`] === undefined)\n style[`border${side}Style`] = borderStyle;\n if (style[`border${side}Color`] === undefined)\n style[`border${side}Color`] = color;\n }\n delete style.border;\n }\n\n // Per-side border shorthands (e.g. borderLeft: \"3px solid white\")\n for (const side of SIDES) {\n const key = `border${side}`;\n if (style[key] !== undefined) {\n const parts = String(style[key]).split(/\\s+/);\n const width = parseValue(parts[0]);\n const borderStyle = parts[1] ?? \"solid\";\n const color = parts[2] ?? \"black\";\n if (style[`${key}Width`] === undefined) style[`${key}Width`] = width;\n if (style[`${key}Style`] === undefined)\n style[`${key}Style`] = borderStyle;\n if (style[`${key}Color`] === undefined) style[`${key}Color`] = color;\n delete style[key];\n }\n }\n\n // flex shorthand\n if (style.flex !== undefined) {\n const val = String(style.flex);\n if (val === \"none\") {\n if (style.flexGrow === undefined) style.flexGrow = 0;\n if (style.flexShrink === undefined) style.flexShrink = 0;\n if (style.flexBasis === undefined) style.flexBasis = \"auto\";\n } else {\n const parts = val.split(/\\s+/);\n if (parts.length === 1) {\n const n = parseFloat(parts[0]!);\n if (!isNaN(n)) {\n if (style.flexGrow === undefined) style.flexGrow = n;\n if (style.flexShrink === undefined) style.flexShrink = 1;\n if (style.flexBasis === undefined) style.flexBasis = 0;\n }\n } else if (parts.length === 2) {\n if (style.flexGrow === undefined)\n style.flexGrow = parseFloat(parts[0]!);\n if (style.flexShrink === undefined)\n style.flexShrink = parseFloat(parts[1]!);\n } else if (parts.length >= 3) {\n if (style.flexGrow === undefined)\n style.flexGrow = parseFloat(parts[0]!);\n if (style.flexShrink === undefined)\n style.flexShrink = parseFloat(parts[1]!);\n if (style.flexBasis === undefined)\n style.flexBasis = parseValue(parts[2]);\n }\n }\n delete style.flex;\n }\n\n // gap shorthand\n if (style.gap !== undefined) {\n const sides = parseSides(String(style.gap));\n if (style.rowGap === undefined) style.rowGap = parseValue(sides[0]);\n if (style.columnGap === undefined) style.columnGap = parseValue(sides[1]);\n delete style.gap;\n }\n\n // background shorthand\n if (style.background !== undefined) {\n const parts = parseBackgroundShorthand(String(style.background));\n if (parts.image !== undefined && style.backgroundImage === undefined)\n style.backgroundImage = parts.image;\n if (parts.repeat !== undefined && style.backgroundRepeat === undefined)\n style.backgroundRepeat = parts.repeat;\n if (parts.size !== undefined && style.backgroundSize === undefined)\n style.backgroundSize = parts.size;\n if (parts.color !== undefined && style.backgroundColor === undefined)\n style.backgroundColor = parts.color;\n delete style.background;\n }\n\n // overflow shorthand\n if (style.overflow !== undefined) {\n if (style.overflowX === undefined) style.overflowX = style.overflow;\n if (style.overflowY === undefined) style.overflowY = style.overflow;\n }\n\n // textBox shorthand (e.g. \"trim-both cap alphabetic\")\n if (style.textBox !== undefined) {\n const val = String(style.textBox);\n if (val === \"normal\" || val === \"none\") {\n style.textBoxTrim ??= \"none\";\n } else {\n const parts = val.split(/\\s+/);\n style.textBoxTrim ??= parts[0];\n if (parts.length > 1) {\n style.textBoxEdge ??= parts.slice(1).join(\" \");\n }\n }\n delete style.textBox;\n }\n\n // WebkitTextStroke shorthand (e.g. \"2px red\")\n if (style.WebkitTextStroke !== undefined) {\n const val = String(style.WebkitTextStroke).trim();\n const match = val.match(/^(\\S+)\\s+(.+)$/);\n if (match) {\n if (style.WebkitTextStrokeWidth === undefined)\n style.WebkitTextStrokeWidth = parseValue(match[1]);\n if (style.WebkitTextStrokeColor === undefined)\n style.WebkitTextStrokeColor = match[2];\n } else {\n // Single value — treat as width\n if (style.WebkitTextStrokeWidth === undefined)\n style.WebkitTextStrokeWidth = parseValue(val);\n }\n delete style.WebkitTextStroke;\n }\n\n // Vendor-prefixed aliases\n if (style.WebkitBackdropFilter !== undefined) {\n if (style.backdropFilter === undefined)\n style.backdropFilter = style.WebkitBackdropFilter;\n delete style.WebkitBackdropFilter;\n }\n // `word-wrap` is the legacy name of `overflow-wrap`.\n if (style.wordWrap !== undefined) {\n if (style.overflowWrap === undefined) style.overflowWrap = style.wordWrap;\n delete style.wordWrap;\n }\n if (style.WebkitClipPath !== undefined) {\n if (style.clipPath === undefined) style.clipPath = style.WebkitClipPath;\n delete style.WebkitClipPath;\n }\n\n // fontFamily normalization\n if (typeof style.fontFamily === \"string\") {\n const families = style.fontFamily\n .split(\",\")\n .map((s) => s.trim().replace(/^['\"]|['\"]$/g, \"\"))\n .filter(Boolean);\n if (fontFamilies) {\n const present = new Set(families);\n for (const name of fontFamilies) {\n if (!present.has(name)) families.push(name);\n }\n }\n style.fontFamily = families.join(\", \");\n }\n\n return style as unknown as ExpandedStyle;\n}\n\nconst BG_REPEAT_KEYWORDS = new Set([\n \"repeat\",\n \"no-repeat\",\n \"repeat-x\",\n \"repeat-y\",\n \"space\",\n \"round\",\n]);\nconst BG_POSITION_KEYWORDS = new Set([\n \"left\",\n \"right\",\n \"top\",\n \"bottom\",\n \"center\",\n]);\nconst BG_ATTACHMENT_KEYWORDS = new Set([\"scroll\", \"fixed\", \"local\"]);\nconst BG_BOX_KEYWORDS = new Set([\"border-box\", \"padding-box\", \"content-box\"]);\nconst BG_IMAGE_FN =\n /^(?:url|image-set|(?:repeating-)?(?:linear|radial|conic)-gradient)\\(/;\n\n// Whitespace-tokenize a CSS value, keeping balanced-paren blocks intact and\n// emitting `/` as its own token (the position/size separator).\nfunction tokenizeBackground(value: string): string[] {\n const tokens: string[] = [];\n let buf = \"\";\n for (let i = 0; i < value.length; i++) {\n const c = value[i]!;\n if (c === \"(\") {\n let depth = 1;\n buf += c;\n i++;\n while (i < value.length && depth > 0) {\n const ch = value[i]!;\n if (ch === \"(\") depth++;\n else if (ch === \")\") depth--;\n buf += ch;\n i++;\n }\n i--;\n } else if (/\\s/.test(c)) {\n if (buf) {\n tokens.push(buf);\n buf = \"\";\n }\n } else if (c === \"/\") {\n if (buf) {\n tokens.push(buf);\n buf = \"\";\n }\n tokens.push(\"/\");\n } else {\n buf += c;\n }\n }\n if (buf) tokens.push(buf);\n return tokens;\n}\n\ninterface BackgroundParts {\n image?: string;\n repeat?: string;\n size?: string;\n color?: string;\n}\n\nfunction parseLayer(value: string): BackgroundParts {\n const out: BackgroundParts = {};\n const sizeTokens: string[] = [];\n let afterSlash = false;\n for (const tok of tokenizeBackground(value)) {\n if (tok === \"/\") {\n afterSlash = true;\n continue;\n }\n if (afterSlash) {\n sizeTokens.push(tok);\n continue;\n }\n if (BG_IMAGE_FN.test(tok)) {\n out.image = tok;\n continue;\n }\n if (tok === \"none\") continue;\n if (BG_REPEAT_KEYWORDS.has(tok)) {\n out.repeat = tok;\n continue;\n }\n // Position/attachment/box/length tokens are recognized so they don't fall\n // through and get treated as colors; the renderer doesn't honor them yet.\n if (\n BG_POSITION_KEYWORDS.has(tok) ||\n BG_ATTACHMENT_KEYWORDS.has(tok) ||\n BG_BOX_KEYWORDS.has(tok) ||\n /^-?\\d/.test(tok)\n ) {\n continue;\n }\n out.color = tok;\n }\n if (sizeTokens.length > 0) out.size = sizeTokens.join(\" \");\n return out;\n}\n\n/**\n * Parse the CSS `background` shorthand into image/repeat/size/color longhands.\n * For multi-layer values, image is comma-joined and color is taken only from\n * the final layer (the only layer permitted a color per the CSS spec).\n */\nexport function parseBackgroundShorthand(value: string): BackgroundParts {\n const layers = splitGradientArgs(value).map((l) => l.trim());\n if (layers.length <= 1) return parseLayer(layers[0] ?? \"\");\n\n const parsed = layers.map(parseLayer);\n const out: BackgroundParts = {};\n const images = parsed.map((p) => p.image ?? \"none\");\n if (images.some((i) => i !== \"none\")) out.image = images.join(\", \");\n for (const p of parsed) {\n if (p.repeat !== undefined && out.repeat === undefined)\n out.repeat = p.repeat;\n if (p.size !== undefined && out.size === undefined) out.size = p.size;\n }\n const finalColor = parsed[parsed.length - 1]?.color;\n if (finalColor !== undefined) out.color = finalColor;\n return out;\n}\n","import Yoga, {\n Align,\n Display,\n Edge,\n FlexDirection,\n Gutter,\n Justify,\n MeasureMode,\n Overflow,\n PositionType,\n Unit,\n Wrap,\n} from \"yoga-layout\";\nimport type { Node as YogaNode } from \"yoga-layout\";\n\nexport type { YogaNode };\n\nexport {\n Yoga,\n Align,\n Display,\n Edge,\n FlexDirection,\n Gutter,\n Justify,\n MeasureMode,\n Overflow,\n PositionType,\n Unit,\n Wrap,\n};\n\nexport function createYogaNode(): YogaNode {\n return Yoga.Node.create();\n}\n\nlet textConfig: ReturnType<typeof Yoga.Config.create> | undefined;\n\n/**\n * A node for text, whose layout Yoga leaves unrounded (its parents are still\n * rounded to whole pixels). Its width is then the width the text was measured\n * at, which it's drawn at too, so a line that just fits stays on one line,\n * and a line that doesn't wraps, as in a browser.\n */\nexport function createTextYogaNode(): YogaNode {\n if (!textConfig) {\n textConfig = Yoga.Config.create();\n textConfig.setPointScaleFactor(0);\n }\n return Yoga.Node.create(textConfig);\n}\n\nexport function freeYogaNode(node: YogaNode): void {\n node.freeRecursive();\n}\n","import {\n Align,\n Display,\n Edge,\n FlexDirection,\n Gutter,\n Justify,\n Overflow,\n PositionType,\n Wrap,\n} from \"../yoga.ts\";\nimport type { YogaNode } from \"../yoga.ts\";\nimport type { ComputedStyle } from \"./compute.ts\";\n\n/**\n * A length in px, truncated to 1/64px, as Chrome lays lengths out (in\n * units of 1/64px). It also keeps the sums Yoga shrinks flex items with\n * exact (see `TextMeasure`).\n */\nexport function toLayoutUnit(px: number): number {\n if (!Number.isFinite(px)) return px;\n // Rounded first, so that 2.3 * 64 = 147.19999… still counts as 147.2.\n return Math.trunc(Math.round(px * 64 * 1e6) / 1e6) / 64;\n}\n\n/**\n * Apply computed CSS styles to a Yoga node.\n */\nexport function applyStylesToYoga(node: YogaNode, style: ComputedStyle): void {\n // Display\n if (style.display === \"none\") {\n node.setDisplay(Display.None);\n } else {\n node.setDisplay(Display.Flex);\n }\n\n // Flex direction (CSS default is \"row\", Yoga defaults to \"column\")\n {\n const map: Record<string, FlexDirection> = {\n row: FlexDirection.Row,\n \"row-reverse\": FlexDirection.RowReverse,\n column: FlexDirection.Column,\n \"column-reverse\": FlexDirection.ColumnReverse,\n };\n node.setFlexDirection(\n map[style.flexDirection ?? \"row\"] ?? FlexDirection.Row,\n );\n }\n\n // Justify content\n if (style.justifyContent) {\n const map: Record<string, Justify> = {\n \"flex-start\": Justify.FlexStart,\n \"flex-end\": Justify.FlexEnd,\n center: Justify.Center,\n \"space-between\": Justify.SpaceBetween,\n \"space-around\": Justify.SpaceAround,\n \"space-evenly\": Justify.SpaceEvenly,\n };\n const jc = map[style.justifyContent];\n if (jc !== undefined) node.setJustifyContent(jc);\n }\n\n // Align items.\n // NOTE: `baseline` does NOT produce typographic baseline alignment. The\n // bundled yoga-layout JS binding exposes no baseline function, so Yoga falls\n // back to a node's height as its baseline — which aligns box bottoms (the\n // same result as `flex-end`), correct only when all children share a font\n // size. The README documents this limitation; don't re-advertise it as full\n // baseline support without a real fix, since the engine can't express it.\n if (style.alignItems) {\n const map: Record<string, Align> = {\n \"flex-start\": Align.FlexStart,\n \"flex-end\": Align.FlexEnd,\n center: Align.Center,\n stretch: Align.Stretch,\n baseline: Align.Baseline,\n };\n const ai = map[style.alignItems];\n if (ai !== undefined) node.setAlignItems(ai);\n }\n\n // Align self (`baseline` carries the same box-bottom caveat as alignItems)\n if (style.alignSelf) {\n const map: Record<string, Align> = {\n auto: Align.Auto,\n \"flex-start\": Align.FlexStart,\n \"flex-end\": Align.FlexEnd,\n center: Align.Center,\n stretch: Align.Stretch,\n baseline: Align.Baseline,\n };\n const as_ = map[style.alignSelf];\n if (as_ !== undefined) node.setAlignSelf(as_);\n }\n\n // Align content\n if (style.alignContent) {\n const map: Record<string, Align> = {\n \"flex-start\": Align.FlexStart,\n \"flex-end\": Align.FlexEnd,\n center: Align.Center,\n stretch: Align.Stretch,\n \"space-between\": Align.SpaceBetween,\n \"space-around\": Align.SpaceAround,\n };\n const ac = map[style.alignContent];\n if (ac !== undefined) node.setAlignContent(ac);\n }\n\n // Flex wrap\n if (style.flexWrap) {\n const map: Record<string, Wrap> = {\n nowrap: Wrap.NoWrap,\n wrap: Wrap.Wrap,\n \"wrap-reverse\": Wrap.WrapReverse,\n };\n const fw = map[style.flexWrap];\n if (fw !== undefined) node.setFlexWrap(fw);\n }\n\n // Flex grow / shrink / basis\n if (style.flexGrow !== undefined) node.setFlexGrow(style.flexGrow);\n // Satori defaults flexShrink to 0 (React Native convention); match it for compatibility\n node.setFlexShrink(style.flexShrink ?? 0);\n if (style.flexBasis !== undefined) {\n if (typeof style.flexBasis === \"number\") {\n node.setFlexBasis(toLayoutUnit(style.flexBasis));\n } else if (String(style.flexBasis).endsWith(\"%\")) {\n node.setFlexBasis(String(style.flexBasis) as `${number}%`);\n } else if (style.flexBasis === \"auto\") {\n node.setFlexBasis(\"auto\");\n } else {\n const n = parseFloat(String(style.flexBasis));\n if (!isNaN(n)) node.setFlexBasis(toLayoutUnit(n));\n }\n }\n\n // Dimensions\n applyDimension(node, \"setWidth\", style.width);\n applyDimension(node, \"setHeight\", style.height);\n applyDimension(node, \"setMinWidth\", style.minWidth);\n applyDimension(node, \"setMinHeight\", style.minHeight);\n applyDimension(node, \"setMaxWidth\", style.maxWidth);\n applyDimension(node, \"setMaxHeight\", style.maxHeight);\n\n // Position\n if (style.position === \"absolute\") {\n node.setPositionType(PositionType.Absolute);\n } else {\n node.setPositionType(PositionType.Relative);\n }\n\n // Position edges\n applyEdgeValue(node, \"setPosition\", Edge.Top, style.top);\n applyEdgeValue(node, \"setPosition\", Edge.Right, style.right);\n applyEdgeValue(node, \"setPosition\", Edge.Bottom, style.bottom);\n applyEdgeValue(node, \"setPosition\", Edge.Left, style.left);\n\n // Margin\n applyEdgeValue(node, \"setMargin\", Edge.Top, style.marginTop);\n applyEdgeValue(node, \"setMargin\", Edge.Right, style.marginRight);\n applyEdgeValue(node, \"setMargin\", Edge.Bottom, style.marginBottom);\n applyEdgeValue(node, \"setMargin\", Edge.Left, style.marginLeft);\n\n // Padding\n applyEdgeValue(node, \"setPadding\", Edge.Top, style.paddingTop);\n applyEdgeValue(node, \"setPadding\", Edge.Right, style.paddingRight);\n applyEdgeValue(node, \"setPadding\", Edge.Bottom, style.paddingBottom);\n applyEdgeValue(node, \"setPadding\", Edge.Left, style.paddingLeft);\n\n // Border width (resolved to numbers by resolveUnits before this point)\n if (style.borderTopWidth !== undefined)\n node.setBorder(Edge.Top, toLayoutUnit(style.borderTopWidth as number));\n if (style.borderRightWidth !== undefined)\n node.setBorder(Edge.Right, toLayoutUnit(style.borderRightWidth as number));\n if (style.borderBottomWidth !== undefined)\n node.setBorder(\n Edge.Bottom,\n toLayoutUnit(style.borderBottomWidth as number),\n );\n if (style.borderLeftWidth !== undefined)\n node.setBorder(Edge.Left, toLayoutUnit(style.borderLeftWidth as number));\n\n // Gap\n if (style.rowGap !== undefined)\n node.setGap(Gutter.Row, toLayoutUnit(style.rowGap));\n if (style.columnGap !== undefined)\n node.setGap(Gutter.Column, toLayoutUnit(style.columnGap));\n\n // Overflow\n if (\n style.overflow === \"hidden\" ||\n style.overflowX === \"hidden\" ||\n style.overflowY === \"hidden\"\n ) {\n node.setOverflow(Overflow.Hidden);\n } else {\n node.setOverflow(Overflow.Visible);\n }\n}\n\nfunction applyDimension(\n node: YogaNode,\n setter:\n | \"setWidth\"\n | \"setHeight\"\n | \"setMinWidth\"\n | \"setMinHeight\"\n | \"setMaxWidth\"\n | \"setMaxHeight\",\n value: number | string | undefined,\n): void {\n if (value === undefined) return;\n if (value === \"auto\") {\n if (setter === \"setWidth\" || setter === \"setHeight\") {\n node[setter](\"auto\");\n }\n return;\n }\n if (typeof value === \"number\") {\n node[setter](toLayoutUnit(value));\n return;\n }\n const s = String(value);\n if (s.endsWith(\"%\")) {\n node[setter](s as `${number}%`);\n } else {\n const n = parseFloat(s);\n if (!isNaN(n)) node[setter](toLayoutUnit(n));\n }\n}\n\nfunction applyEdgeValue(\n node: YogaNode,\n setter: \"setMargin\" | \"setPadding\" | \"setPosition\",\n edge: Edge,\n value: number | string | undefined,\n): void {\n if (value === undefined) return;\n if (value === \"auto\" && setter === \"setMargin\") {\n node.setMargin(edge, \"auto\");\n return;\n }\n if (typeof value === \"number\") {\n node[setter](edge, toLayoutUnit(value));\n return;\n }\n const s = String(value);\n if (s.endsWith(\"%\")) {\n node[setter](edge, s as `${number}%`);\n } else {\n const n = parseFloat(s);\n if (!isNaN(n)) node[setter](edge, toLayoutUnit(n));\n }\n}\n","// This file contains code adapted from Satori (https://github.com/vercel/satori)\n// Licensed under the Mozilla Public License 2.0 (MPL-2.0)\n// See NOTICE.md in the package root for details.\n\nimport type { ReactElement, ReactNode } from \"react\";\n\nimport type { ImageCache } from \"../image.ts\";\nimport { cachedLoadImage } from \"../image.ts\";\nimport type { RenderContext } from \"./context.ts\";\nimport { expandStyle } from \"./style/expand.ts\";\nimport {\n resolveStyle,\n resolveUnit,\n resolveUnits,\n DEFAULT_STYLE,\n} from \"./style/compute.ts\";\nimport type { ComputedStyle } from \"./style/compute.ts\";\nimport { applyStylesToYoga, toLayoutUnit } from \"./style/properties.ts\";\nimport { TextMeasure } from \"./text/index.ts\";\nimport { isWhiteSpaceOnly } from \"./text/white-space.ts\";\nimport type { TextContent } from \"./text/white-space.ts\";\nimport type { TextLayoutResult } from \"./text/index.ts\";\nimport {\n createTextYogaNode,\n createYogaNode,\n freeYogaNode,\n Edge,\n FlexDirection,\n MeasureMode,\n Unit,\n Wrap,\n} from \"./yoga.ts\";\nimport type { YogaNode } from \"./yoga.ts\";\n\n/**\n * A node in the computed layout tree, ready for drawing.\n */\nexport type LayoutNode = {\n type: string;\n style: ComputedStyle;\n children: LayoutNode[];\n textContent?: TextContent;\n /** The text laid out at the node's width, for drawing. */\n textLayout?: TextLayoutResult;\n props: Record<string, unknown>;\n x: number;\n y: number;\n width: number;\n height: number;\n};\n\n/**\n * Build a layout tree from a React element tree.\n * Creates Yoga nodes, calculates layout, and returns the positioned tree.\n *\n * @param element - React element tree to lay out\n * @param containerWidth - Width of the container (from canvas)\n * @param containerHeight - Height of the container (from canvas)\n * @returns Root layout node with computed positions and dimensions\n */\nexport async function buildLayoutTree(\n element: ReactNode,\n containerWidth: number,\n containerHeight: number,\n emojiEnabled?: boolean,\n fontFamilies?: string[],\n context?: RenderContext,\n): Promise<{ tree: LayoutNode; imageCache: ImageCache }> {\n const renderContext: RenderContext = context ?? {\n imageCache: new Map(),\n debug: false,\n };\n const rootElement = renderComponents(element);\n const elementYogaNode = isText(rootElement)\n ? createTextYogaNode()\n : createYogaNode();\n\n // Set font families as default on root style so all nodes inherit them\n const rootStyle = fontFamilies?.length\n ? { ...DEFAULT_STYLE, fontFamily: fontFamilies.join(\", \") }\n : DEFAULT_STYLE;\n\n // Build the tree\n const elementNode = await buildNode(\n rootElement,\n rootStyle,\n elementYogaNode,\n containerWidth,\n containerHeight,\n emojiEnabled,\n fontFamilies,\n renderContext,\n );\n\n // Wrap the user element in a canvas-sized container (like Satori) so that\n // absolute positioning, percentage sizes, etc. resolve against the canvas.\n const rootYogaNode = createYogaNode();\n rootYogaNode.setWidth(containerWidth);\n rootYogaNode.setHeight(containerHeight);\n rootYogaNode.setFlexDirection(FlexDirection.Row);\n rootYogaNode.insertChild(elementYogaNode, 0);\n\n // The layout is computed once, and normally once more for text items it\n // squeezed below their minimums. At worst, `layOut` computes it\n // 1 + MAX_AUTO_MINIMUM_RELAYOUTS = 5 times, and `settleText` calls it\n // MAX_TEXT_RELAYOUTS + 1 = 3 times more: 20 layouts a round, for the first\n // round, MAX_RUNAWAY_RELAYOUTS = 2 rounds of pinned runaway items and one\n // with minimums lifted, 80 in all.\n let layouts = 0;\n const compute = () => {\n layouts++;\n rootYogaNode.calculateLayout(containerWidth, containerHeight);\n };\n\n // Text items get their automatic minimum widths (in a column, heights)\n // where the layout squeezes them below their text, which takes another\n // layout, and their text is laid out at the widths they end up with.\n const autoMinimums = collectAutoMinimums(elementNode);\n const layOut = () => {\n compute();\n for (const node of autoMinimums) node.autoMinimum!.refreshed = false;\n for (\n let pass = 0;\n pass < MAX_AUTO_MINIMUM_RELAYOUTS && enforceAutoMinimums(autoMinimums);\n pass++\n ) {\n compute();\n }\n };\n layOut();\n settleText(elementNode, layOut, renderContext.debug);\n\n // Yoga can lose its sums and size flex items out of all proportion (see\n // `findRunawayItems`): pin them at their minimums, as CSS sizes them, or\n // failing that, lay the text in their lines out without its automatic\n // minimums.\n const limit = RUNAWAY_SIZE * Math.max(containerWidth, containerHeight);\n for (let pass = 0; pass < MAX_RUNAWAY_RELAYOUTS; pass++) {\n const runaway = findRunawayItems(elementNode, limit);\n if (runaway.length === 0) break;\n for (const item of runaway) pinAtMinimum(item);\n layOut();\n settleText(elementNode, layOut, renderContext.debug);\n }\n const runaway = findRunawayItems(elementNode, limit);\n if (runaway.length > 0) {\n const lines = new Set(runaway.map((item) => item.parent));\n const lifted = [...lines]\n .flatMap((line) => line.children)\n .filter((node) => node.autoMinimum && liftAutoMinimum(node));\n if (lifted.length > 0) {\n layOut();\n settleText(elementNode, layOut, renderContext.debug);\n }\n if (renderContext.debug) {\n console.warn(\n \"[@effing/canvas] Yoga sized flex items out of all proportion\" +\n (lifted.length > 0 ? \": laid their text out without minimums\" : \"\"),\n );\n }\n }\n if (renderContext.debug && layouts > 5) {\n console.warn(`[@effing/canvas] computed the layout ${layouts} times`);\n }\n\n const elementLayout = extractLayout(elementNode, elementYogaNode);\n freeYogaNode(rootYogaNode);\n\n const tree: LayoutNode = {\n type: \"div\",\n style: rootStyle,\n children: [elementLayout],\n props: {},\n x: 0,\n y: 0,\n width: containerWidth,\n height: containerHeight,\n };\n return { tree, imageCache: renderContext.imageCache };\n}\n\n/**\n * Build the node for `element` on `yogaNode`. Function components must be\n * rendered first (`renderComponents`), so the caller can make text a text\n * node (`createTextYogaNode`).\n */\nasync function buildNode(\n element: ReactNode | TextRun,\n parentStyle: ComputedStyle,\n yogaNode: YogaNode,\n viewportWidth: number,\n viewportHeight: number,\n emojiEnabled?: boolean,\n fontFamilies?: string[],\n context?: RenderContext,\n): Promise<IntermediateNode> {\n // Handle null/undefined/boolean\n if (\n element === null ||\n element === undefined ||\n typeof element === \"boolean\"\n ) {\n return {\n type: \"empty\",\n style: parentStyle,\n children: [],\n props: {},\n yogaNode,\n };\n }\n\n // Handle text/number primitives, and runs of text\n if (isText(element) || isTextRun(element)) {\n const text = isTextRun(element) ? textContentOf(element) : String(element);\n return buildTextNode(text, parentStyle, yogaNode, emojiEnabled);\n }\n\n // Handle React elements (host elements: components are rendered already)\n const el = element as ReactElement<Record<string, unknown>>;\n const type = el.type;\n\n const props = (el.props ?? {}) as Record<string, unknown>;\n const rawStyle = (props.style ?? {}) as Record<string, unknown>;\n const expanded = expandStyle(rawStyle, fontFamilies);\n const style = resolveStyle(expanded, parentStyle);\n resolveUnits(style, viewportWidth, viewportHeight);\n\n const tagName = String(type);\n\n // For <svg> elements, merge width/height props into style when not set via CSS\n if (tagName === \"svg\") {\n if (props.width != null && style.width === undefined) {\n const v = props.width;\n if (typeof v === \"string\") {\n const resolved = resolveUnit(v, viewportWidth, viewportHeight, 16, 16);\n style.width =\n typeof resolved === \"string\" && resolved.endsWith(\"%\")\n ? resolved\n : Number(resolved);\n } else {\n style.width = Number(v);\n }\n }\n if (props.height != null && style.height === undefined) {\n const v = props.height;\n if (typeof v === \"string\") {\n const resolved = resolveUnit(v, viewportWidth, viewportHeight, 16, 16);\n style.height =\n typeof resolved === \"string\" && resolved.endsWith(\"%\")\n ? resolved\n : Number(resolved);\n } else {\n style.height = Number(v);\n }\n }\n\n // Derive missing dimension from viewBox aspect ratio\n const viewBox = props.viewBox as string | undefined;\n if (viewBox) {\n const parts = viewBox.split(/[\\s,]+/).map(Number);\n if (parts.length === 4) {\n const [, , vbW, vbH] = parts as [number, number, number, number];\n if (vbW > 0 && vbH > 0) {\n const wSet = style.width !== undefined;\n const hSet = style.height !== undefined;\n if (!wSet && !hSet) {\n style.width = vbW;\n style.height = vbH;\n } else if (!hSet && typeof style.width === \"number\") {\n style.height = style.width * (vbH / vbW);\n } else if (!wSet && typeof style.height === \"number\") {\n style.width = style.height * (vbW / vbH);\n }\n // When either/both are %, leave as-is for Yoga\n }\n }\n }\n }\n\n // For <img> elements, derive missing dimensions from intrinsic aspect ratio\n if (tagName === \"img\") {\n // Map HTML width/height attributes to style (like <svg>)\n if (props.width != null && style.width === undefined) {\n const v = props.width;\n style.width = typeof v === \"string\" && v.endsWith(\"%\") ? v : Number(v);\n }\n if (props.height != null && style.height === undefined) {\n const v = props.height;\n style.height = typeof v === \"string\" && v.endsWith(\"%\") ? v : Number(v);\n }\n\n const src = props.src as string | Buffer | undefined;\n if (src) {\n try {\n const image = await cachedLoadImage(\n context?.imageCache ?? new Map(),\n src,\n context?.userAgent,\n );\n const naturalW = image.width;\n const naturalH = image.height;\n\n const wSet = style.width !== undefined;\n const hSet = style.height !== undefined;\n\n if (naturalW > 0 && naturalH > 0 && !(wSet && hSet)) {\n if (!wSet && !hSet) {\n // No dimensions given — fill parent, let aspect ratio derive height.\n style.width = \"100%\";\n }\n yogaNode.setAspectRatio(naturalW / naturalH);\n }\n } catch (err) {\n // Don't fail layout when the image is unreachable — render at whatever\n // size Yoga computes. Surface the error (only in debug) so misconfigured\n // URLs and UA-gated CDNs are diagnosable instead of silently dropping\n // pixels, without spamming logs on every frame of a normal render.\n if (context?.debug) {\n const id = Buffer.isBuffer(src) ? \"<Buffer>\" : src;\n console.warn(\n `[@effing/canvas] failed to load image for layout (${id}): ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n }\n }\n }\n\n // Apply styles to Yoga node\n applyStylesToYoga(yogaNode, style);\n\n // SVG containers: children use SVG coordinate space, not flex layout.\n // Skip Yoga child nodes and keep React children in props for the SVG drawer.\n if (tagName === \"svg\") {\n const resolvedChildren = resolveSvgTree(props.children as ReactNode);\n return {\n type: tagName,\n style,\n children: [],\n props: { ...props, children: resolvedChildren },\n yogaNode,\n };\n }\n\n // The children as the DOM has them: components rendered, fragments and\n // arrays unwrapped, and adjacent text and <br>s one run. Text of nothing but\n // white space is no flex item at all (see below).\n const items = flattenChildren(props.children as ReactNode).filter(\n (item) => !isTextRun(item) || !isBlankRun(item),\n );\n\n // If this node has only text content, create a child text node.\n // Using a child node (instead of setMeasureFunc on this node directly)\n // ensures Yoga's baseline calculation accounts for this node's padding/border\n // when a parent uses alignItems: \"baseline\". A node whose only text is white\n // space has no line box.\n const onlyText = items.length === 1 && isTextRun(items[0]) ? items[0] : null;\n if (onlyText !== null) {\n const childYogaNode = createTextYogaNode();\n const child = buildTextNode(\n textContentOf(onlyText),\n style,\n childYogaNode,\n emojiEnabled,\n );\n const jc = style.justifyContent;\n if (!jc || jc === \"flex-start\") {\n childYogaNode.setFlexGrow(1);\n }\n childYogaNode.setFlexShrink(1);\n yogaNode.insertChild(childYogaNode, 0);\n\n // Match satori: text-only nodes default to flexShrink=1 so they shrink to\n // fit the available flex space. Without this, text containers overflow their\n // flex parent when siblings consume part of the main axis.\n if (style.flexShrink === undefined) {\n yogaNode.setFlexShrink(1);\n }\n // But no narrower than their text, as CSS has it, nor in a column shorter\n // than its lines: the element, and its text in the element's own line.\n const textMeasure = child.textMeasure!;\n child.autoMinimum = {\n textMeasure,\n column: !isRow(style),\n text: childYogaNode,\n };\n\n return {\n type: tagName,\n style,\n children: [child],\n props,\n yogaNode,\n autoMinimum: hasAutoMinimum(style, parentStyle)\n ? {\n textMeasure,\n style,\n column: !isRow(parentStyle),\n text: childYogaNode,\n }\n : undefined,\n };\n }\n\n // Process children. Each run of text and <br>s between other elements is a\n // flex item of its own (CSS Flexbox §4), its white space collapsed as its\n // box's text (see `layoutText`): the spaces at its start and end, and\n // around a <br>, are removed. A run of nothing but white space isn't\n // rendered at all, whatever its `white-space`.\n const children: IntermediateNode[] = [];\n for (const rendered of items) {\n const childYogaNode = isTextRun(rendered)\n ? createTextYogaNode()\n : createYogaNode();\n yogaNode.insertChild(childYogaNode, children.length);\n children.push(\n await buildNode(\n rendered,\n style,\n childYogaNode,\n viewportWidth,\n viewportHeight,\n emojiEnabled,\n fontFamilies,\n context,\n ),\n );\n }\n\n return {\n type: tagName,\n style,\n children,\n props,\n yogaNode,\n };\n}\n\ntype IntermediateNode = {\n type: string;\n style: ComputedStyle;\n children: IntermediateNode[];\n textContent?: TextContent;\n /** Set on text nodes, which Yoga measures. */\n textMeasure?: TextMeasure;\n /**\n * Set on a flex item that CSS gives an automatic minimum size (see\n * `enforceAutoMinimums`).\n */\n autoMinimum?: AutoMinimum;\n props: Record<string, unknown>;\n yogaNode: YogaNode;\n};\n\n/**\n * How many times the layout is computed again for text that Yoga sized at\n * another width than it's drawn at (see `TextMeasure`). One normally settles\n * it; the bound is for layouts where a node's width depends on its height\n * (wrapping columns, aspect ratios), which could otherwise keep changing.\n */\nconst MAX_TEXT_RELAYOUTS = 2;\n\n/**\n * Lay every text node out at its final width, and compute the layout again\n * while Yoga sized one from a different height.\n */\nfunction settleText(\n root: IntermediateNode,\n relayout: () => void,\n debug: boolean,\n): void {\n const textNodes: IntermediateNode[] = [];\n const collect = (node: IntermediateNode) => {\n // Nothing under `display: none` is laid out or drawn.\n if (node.style.display === \"none\") return;\n if (node.textMeasure) textNodes.push(node);\n node.children.forEach(collect);\n };\n collect(root);\n // Text nodes have no padding or border: their width is the content's.\n const settle = (node: IntermediateNode, pin: boolean) =>\n node.textMeasure!.settle(node.yogaNode.getComputedWidth(), pin);\n\n for (let pass = 0; pass < MAX_TEXT_RELAYOUTS; pass++) {\n let unsettled = false;\n for (const node of textNodes) {\n if (settle(node, true)) {\n node.yogaNode.markDirty();\n unsettled = true;\n }\n }\n if (!unsettled) return;\n relayout();\n }\n if (!textNodes.some((node) => settle(node, false))) return;\n\n // Each pin moved the layout on to widths the drawn heights don't fit. Go\n // back to Yoga's own layout, as without the pins, and draw the text at the\n // widths it gives.\n for (const node of textNodes) {\n if (node.textMeasure!.unpin()) node.yogaNode.markDirty();\n }\n relayout();\n const unsettled = textNodes.filter((node) => settle(node, false)).length;\n if (debug && unsettled > 0) {\n console.warn(\n `[@effing/canvas] ${unsettled} text node(s) sized for other lines ` +\n `than drawn: the layout didn't settle in ${MAX_TEXT_RELAYOUTS} relayouts`,\n );\n }\n}\n\n/** Build a text node for `text` on `yogaNode`, which Yoga measures. */\nfunction buildTextNode(\n text: TextContent,\n parentStyle: ComputedStyle,\n yogaNode: YogaNode,\n emojiEnabled?: boolean,\n): IntermediateNode {\n const style = resolveStyle(undefined, parentStyle);\n const textMeasure = new TextMeasure(text, style, emojiEnabled);\n setTextMeasure(yogaNode, textMeasure);\n return {\n type: \"text\",\n style,\n children: [],\n textContent: text,\n textMeasure,\n props: {},\n yogaNode,\n };\n}\n\n/** Whether a flex container lays its items out in a row. */\nconst isRow = (style: ComputedStyle) =>\n style.flexDirection === undefined ||\n style.flexDirection === \"row\" ||\n style.flexDirection === \"row-reverse\";\n\n/**\n * A flex item that holds nothing but text, which CSS's automatic minimum\n * size keeps from shrinking below its text. In a row, `min-width: auto`\n * keeps it as wide as the text's min-content width: a word, or a line that\n * can't wrap. That keeps text that doesn't fit centred in a centring parent,\n * overflowing it on both sides, as in Chrome. In a column, `min-height: auto`\n * keeps it as tall as the text's lines at its width, which overflow the\n * column rather than the item. The text of such an element is an item in\n * the element's own line, with a minimum of its own.\n */\ntype AutoMinimum = {\n textMeasure: TextMeasure;\n /** The element's style; none for its text. */\n style?: ComputedStyle;\n /** Whether the item is in a column, and its minimum a height. */\n column: boolean;\n /** The text's node, at whose width the text is laid out. */\n text: YogaNode;\n /** Takes back the minimum given to Yoga, once it was. */\n lift?: () => void;\n /**\n * The minimum height given to Yoga, which follows the text's width (in a\n * column, where the item's flex basis doesn't).\n */\n held?: number;\n /**\n * Set once the item was laid out afresh at the height it's held at, in\n * a round of layouts (see `buildLayoutTree`).\n */\n refreshed?: boolean;\n /** Set once the minimum is lifted for good (see `buildLayoutTree`). */\n lifted?: boolean;\n};\n\n/**\n * Whether an element that holds nothing but text has an automatic minimum\n * size along its parent's main axis. A scroll container (`overflow: hidden`,\n * `scroll` or `auto`) has none, as in CSS, nor has an item positioned\n * absolutely or one with a `min-width` (in a column, `min-height`) of its\n * own.\n */\nfunction hasAutoMinimum(\n style: ComputedStyle,\n parentStyle: ComputedStyle,\n): boolean {\n const min = isRow(parentStyle) ? style.minWidth : style.minHeight;\n return (\n style.position !== \"absolute\" &&\n (min === undefined || min === \"auto\") &&\n ![style.overflow, style.overflowX, style.overflowY].some(\n (overflow) =>\n overflow === \"hidden\" || overflow === \"scroll\" || overflow === \"auto\",\n )\n );\n}\n\n/**\n * How many times the layout is computed again for items squeezed below\n * their automatic minimum width (in a column, height). Each minimum given\n * can squeeze the items next to it in turn.\n */\nconst MAX_AUTO_MINIMUM_RELAYOUTS = 4;\n\n/**\n * The nodes with an automatic minimum width or height, but under\n * `display: none`.\n */\nfunction collectAutoMinimums(root: IntermediateNode): IntermediateNode[] {\n const nodes: IntermediateNode[] = [];\n const collect = (node: IntermediateNode) => {\n if (node.style.display === \"none\") return;\n if (node.autoMinimum) nodes.push(node);\n node.children.forEach(collect);\n };\n collect(root);\n return nodes;\n}\n\n/**\n * Hold each item Yoga laid out narrower (in a column, shorter) than its\n * automatic minimum at that minimum (see `holdAtMinimum`), for the caller to\n * compute the layout again.\n *\n * Only the items that need it are held: a minimum Yoga doesn't hold an item\n * to doesn't change the layout, and these are the items CSS freezes at their\n * minimums. Holding them can squeeze the items next to them below theirs in\n * turn, as CSS freezes items in rounds.\n *\n * @returns Whether any item was held, or held at another minimum\n */\nfunction enforceAutoMinimums(nodes: IntermediateNode[]): boolean {\n let enforced = false;\n for (const node of nodes) {\n const autoMinimum = node.autoMinimum!;\n if (autoMinimum.lifted) continue;\n if (autoMinimum.column) {\n if (enforceAutoMinimumHeight(node)) enforced = true;\n continue;\n }\n if (autoMinimum.lift) continue;\n const { yogaNode } = node;\n const { textMeasure, style } = autoMinimum;\n const width = yogaNode.getComputedWidth();\n // Yoga puts elements on whole pixels; text it leaves as measured.\n const tolerance = style ? 1 : 1e-3;\n // As wide as a bound on its minimum: not squeezed.\n const edges = style ? horizontalEdges(yogaNode, style) : 0;\n if (width + tolerance >= textMeasure.minContentBound + edges) continue;\n const minimum = autoMinimumWidth(node);\n if (minimum === undefined || width + tolerance >= minimum) continue;\n autoMinimum.lift = holdAtMinimum(yogaNode, minimum, {\n atBasis:\n textMeasure.unbreakable &&\n (!style || (isAuto(style.width) && isAuto(style.flexBasis))),\n // The text in an element sizes the element's own flex basis, which a\n // pin would take from it.\n pin: style !== undefined,\n column: false,\n });\n enforced = true;\n }\n return enforced;\n}\n\n/**\n * Hold an item in a column that Yoga laid out shorter than its text at its\n * width at that height (`min-height: auto`), or hold it at the height its\n * text has now, where its width changed since it was held.\n *\n * An item whose flex basis is its text's height (`atBasis`) first only\n * stops shrinking, and its basis follows its text. Where Yoga gives the\n * column no room, it makes that basis the room there is, 0, as it does for\n * a box of text it measures there: the item gets a min height then.\n *\n * @returns Whether the item was held, or held at another minimum, or the\n * layout must be computed again for a hold Yoga didn't apply\n */\nfunction enforceAutoMinimumHeight(node: IntermediateNode): boolean {\n const autoMinimum = node.autoMinimum!;\n const { yogaNode } = node;\n const { style } = autoMinimum;\n const minimum = autoMinimumHeight(node);\n if (minimum === undefined) return false;\n const height = yogaNode.getComputedHeight();\n // Yoga puts elements on whole pixels, which takes less than a pixel off\n // their heights; text it leaves as measured. Held a little early, an\n // element is held a fraction of a pixel taller than it was.\n const tolerance = style ? 0.5 : 1e-3;\n const short = height + tolerance < minimum;\n const atBasis = !style || (isAuto(style.height) && isAuto(style.flexBasis));\n if (autoMinimum.lift) {\n const { held } = autoMinimum;\n if (held === undefined) {\n // Held at its basis.\n if (!short) return false;\n } else if (\n Math.abs(held - minimum) < tolerance ||\n // In a column that wraps, the heights decide the widths: an item is\n // only ever held higher there, or they could swing back and forth.\n (minimum < held && yogaNode.getParent()?.getFlexWrap() !== Wrap.NoWrap)\n ) {\n // Held there, but Yoga can keep a layout it cached before (after the\n // runaway guard pinned items, say): lay the item out afresh.\n // Once a round: where Yoga runs away with the line, it can't hold it\n // anyway, until the runaway items are pinned.\n if (height + (style ? 1 : 1e-3) >= held || autoMinimum.refreshed) {\n return false;\n }\n autoMinimum.text.markDirty();\n autoMinimum.refreshed = true;\n return true;\n }\n autoMinimum.lift();\n } else if (!short) {\n return false;\n } else if (atBasis) {\n autoMinimum.lift = holdAtMinimum(yogaNode, minimum, {\n atBasis: true,\n pin: false,\n column: true,\n });\n return true;\n }\n autoMinimum.held = minimum;\n autoMinimum.lift = holdAtMinimum(yogaNode, minimum, {\n atBasis: false,\n pin: !atBasis,\n column: true,\n });\n return true;\n}\n\nconst isAuto = (\n value: number | string | undefined,\n): value is undefined | \"auto\" => value === undefined || value === \"auto\";\n\n/**\n * A node's padding and borders on the left and right, as Yoga has them, or\n * as its style has them where they're lengths.\n */\nfunction horizontalEdges(yogaNode: YogaNode, style?: ComputedStyle): number {\n const lengths = style && [\n style.paddingLeft,\n style.paddingRight,\n style.borderLeftWidth,\n style.borderRightWidth,\n ];\n if (lengths?.every((v) => v === undefined || typeof v === \"number\")) {\n return lengths.reduce<number>(\n (sum, v) => sum + toLayoutUnit((v as number | undefined) ?? 0),\n 0,\n );\n }\n return (\n yogaNode.getComputedPadding(Edge.Left) +\n yogaNode.getComputedPadding(Edge.Right) +\n yogaNode.getComputedBorder(Edge.Left) +\n yogaNode.getComputedBorder(Edge.Right)\n );\n}\n\n/**\n * A node's automatic minimum width: its text's min-content width, and an\n * element's padding and borders, capped at its width and max width as CSS\n * does, a percentage of its parent's content box.\n *\n * @returns The minimum, or undefined where a width can't be resolved\n */\nfunction autoMinimumWidth(node: IntermediateNode): number | undefined {\n const { yogaNode } = node;\n const { textMeasure, style } = node.autoMinimum!;\n if (!style) return textMeasure.minContentWidth;\n const parent = yogaNode.getParent();\n return capped(\n textMeasure.minContentWidth + horizontalEdges(yogaNode, style),\n [style.width, style.maxWidth],\n parent ? parent.getComputedWidth() - horizontalEdges(parent) : NaN,\n );\n}\n\n/**\n * A node's automatic minimum height in a column: the height of its text's\n * lines at the text's width, and an element's padding and borders, capped\n * at its height and max height as CSS does, a percentage of its parent's\n * content box.\n *\n * @returns The minimum, or undefined where a height can't be resolved\n */\nfunction autoMinimumHeight(node: IntermediateNode): number | undefined {\n const { yogaNode } = node;\n const { textMeasure, style, text } = node.autoMinimum!;\n const height = textMeasure.heightAt(text.getComputedWidth());\n if (!style) return height;\n const parent = yogaNode.getParent();\n return capped(\n height + verticalEdges(yogaNode),\n [style.height, style.maxHeight],\n parent ? parent.getComputedHeight() - verticalEdges(parent) : NaN,\n );\n}\n\n/**\n * `minimum` capped at the sizes given, a percentage of `parentContentSize`.\n *\n * @returns The minimum, or undefined where a size can't be resolved\n */\nfunction capped(\n minimum: number,\n sizes: (number | string | undefined)[],\n parentContentSize: number,\n): number | undefined {\n for (const value of sizes) {\n if (isAuto(value)) continue;\n let cap: number;\n if (typeof value === \"number\") {\n cap = toLayoutUnit(value);\n } else if (value.endsWith(\"%\") && Number.isFinite(parentContentSize)) {\n cap = (parseFloat(value) / 100) * parentContentSize;\n } else {\n return undefined;\n }\n if (!Number.isFinite(cap)) return undefined;\n minimum = Math.min(minimum, cap);\n }\n return minimum;\n}\n\n/** A node's padding and borders at the top and bottom, as Yoga has them. */\nconst verticalEdges = (yogaNode: YogaNode): number =>\n yogaNode.getComputedPadding(Edge.Top) +\n yogaNode.getComputedPadding(Edge.Bottom) +\n yogaNode.getComputedBorder(Edge.Top) +\n yogaNode.getComputedBorder(Edge.Bottom);\n\n/**\n * Hold a flex item Yoga squeezed below its automatic minimum width (in a\n * column, height) at that minimum, as CSS does: it freezes an item at its\n * minimum when it would shrink below it, and lays the others out in the\n * space left.\n *\n * An item whose flex basis is its minimum already (`atBasis`) only stops\n * shrinking. An element in a line that doesn't wrap (`pin`) is pinned at\n * its minimum (a flex basis of it, and neither growing nor shrinking),\n * which leaves it out of the items Yoga flexes. A min width (in a column,\n * min height) would keep it in, and when every item Yoga shrinks in a line\n * is held at its minimum, Yoga can lose its sums (see `findRunawayItems`),\n * or size them from their flex bases. Other items get a min width (min\n * height): one in a line that wraps, where its flex basis decides which\n * line it's on, the text in an element, the only item in its line, whose\n * flex basis is the element's, and an item in a column whose flex basis is\n * its text's height (see `enforceAutoMinimumHeight`).\n *\n * @returns A function that takes the minimum back\n */\nfunction holdAtMinimum(\n yogaNode: YogaNode,\n minimum: number,\n { atBasis, pin, column }: { atBasis: boolean; pin: boolean; column: boolean },\n): () => void {\n const flexShrink = yogaNode.getFlexShrink();\n if (atBasis) {\n yogaNode.setFlexShrink(0);\n return () => yogaNode.setFlexShrink(flexShrink);\n }\n const wraps = yogaNode.getParent()?.getFlexWrap() !== Wrap.NoWrap;\n if (!pin || wraps) {\n const setMin = (value: number | undefined) =>\n column ? yogaNode.setMinHeight(value) : yogaNode.setMinWidth(value);\n setMin(minimum);\n return () => setMin(undefined);\n }\n const flexGrow = yogaNode.getFlexGrow();\n const flexBasis = yogaNode.getFlexBasis();\n yogaNode.setFlexBasis(minimum);\n yogaNode.setFlexShrink(0);\n yogaNode.setFlexGrow(0);\n return () => {\n yogaNode.setFlexShrink(flexShrink);\n yogaNode.setFlexGrow(flexGrow);\n if (flexBasis.unit === Unit.Point) yogaNode.setFlexBasis(flexBasis.value);\n else if (flexBasis.unit === Unit.Percent)\n yogaNode.setFlexBasis(`${flexBasis.value}%`);\n else yogaNode.setFlexBasis(\"auto\");\n };\n}\n\n/**\n * Take back the automatic minimum width (or height) given to Yoga, for\n * good.\n *\n * @returns Whether there was one\n */\nfunction liftAutoMinimum(node: IntermediateNode): boolean {\n const autoMinimum = node.autoMinimum!;\n const { lift } = autoMinimum;\n lift?.();\n autoMinimum.lift = undefined;\n autoMinimum.lifted = true;\n return lift !== undefined;\n}\n\n/**\n * A node this many times as wide or tall as the canvas is taken for one\n * Yoga lost its sums for.\n */\nconst RUNAWAY_SIZE = 100;\n\n/** How many times runaway flex items are pinned, and the layout computed. */\nconst MAX_RUNAWAY_RELAYOUTS = 2;\n\nconst isRunaway = (size: number, limit: number) => !(Math.abs(size) <= limit);\n\n/** A flex item Yoga sized out of all proportion, in its parent's line. */\ntype RunawayItem = {\n node: IntermediateNode;\n parent: IntermediateNode;\n /** Whether the parent's main axis is horizontal. */\n row: boolean;\n};\n\n/**\n * The flex items Yoga shrank to a runaway size: larger than `limit` (or NaN)\n * along their parent's main axis, in a parent that isn't.\n *\n * Yoga shrinks flex items in float32. When every item it shrinks in a line\n * is held at its minimum (its min width, or its padding and borders), the\n * shrink factors it sums and takes away again can leave a rounding error\n * behind, which it then divides by: the items grow to millions of pixels.\n * Lengths and text widths on a grid of 1/64px keep those sums exact, but\n * percentages, shares of free space and fractional `flexShrink`s aren't.\n * Only an item that can shrink is taken for one: a wide item that doesn't\n * is as wide as it says.\n */\nfunction findRunawayItems(\n root: IntermediateNode,\n limit: number,\n): RunawayItem[] {\n const items: RunawayItem[] = [];\n const visit = (node: IntermediateNode, parent?: IntermediateNode) => {\n if (node.style.display === \"none\") return;\n const { yogaNode } = node;\n if (parent) {\n const row = [FlexDirection.Row, FlexDirection.RowReverse].includes(\n parent.yogaNode.getFlexDirection(),\n );\n const size = (n: YogaNode) =>\n row ? n.getComputedWidth() : n.getComputedHeight();\n if (\n yogaNode.getFlexShrink() > 0 &&\n isRunaway(size(yogaNode), limit) &&\n !isRunaway(size(parent.yogaNode), limit)\n ) {\n // Its children follow it.\n items.push({ node, parent, row });\n return;\n }\n }\n for (const child of node.children) visit(child, node);\n };\n visit(root);\n return items;\n}\n\n/**\n * Pin a runaway item at its minimum, as CSS holds every item in such a line:\n * a flex basis of the minimum, and no shrinking.\n */\nfunction pinAtMinimum({ node, parent, row }: RunawayItem): void {\n const { yogaNode } = node;\n // Its automatic minimum too, which Yoga may not have yet: the minimum is\n // along the parent's main axis.\n const autoMinimum = node.autoMinimum;\n const auto =\n autoMinimum && autoMinimum.column !== row\n ? row\n ? autoMinimumWidth(node)\n : autoMinimumHeight(node)\n : 0;\n yogaNode.setFlexBasis(\n Math.max(minimumSize(yogaNode, parent.yogaNode, row), auto ?? 0),\n );\n yogaNode.setFlexShrink(0);\n}\n\n/**\n * The size a flex item can't shrink below along its parent's main axis: its\n * min width or height, and its padding and borders.\n */\nfunction minimumSize(\n yogaNode: YogaNode,\n parent: YogaNode,\n row: boolean,\n): number {\n const [start, end] = row ? [Edge.Left, Edge.Right] : [Edge.Top, Edge.Bottom];\n const edges = (node: YogaNode) =>\n node.getComputedPadding(start) +\n node.getComputedPadding(end) +\n node.getComputedBorder(start) +\n node.getComputedBorder(end);\n const min = row ? yogaNode.getMinWidth() : yogaNode.getMinHeight();\n let minimum = 0;\n if (min.unit === Unit.Point) {\n minimum = min.value;\n } else if (min.unit === Unit.Percent) {\n const parentSize = row\n ? parent.getComputedWidth()\n : parent.getComputedHeight();\n minimum = (min.value / 100) * (parentSize - edges(parent));\n }\n return Math.max(minimum, edges(yogaNode));\n}\n\n/** Measure `yogaNode` with `textMeasure`. */\nfunction setTextMeasure(yogaNode: YogaNode, textMeasure: TextMeasure): void {\n yogaNode.setMeasureFunc((width, widthMode) =>\n widthMode === MeasureMode.Undefined || Number.isNaN(width)\n ? textMeasure.measure(Infinity)\n : textMeasure.measure(width, widthMode === MeasureMode.Exactly),\n );\n}\n\nconst isText = (node: unknown): node is string | number =>\n typeof node === \"string\" || typeof node === \"number\";\n\n/** Render function components until something else is left. */\nfunction renderComponents(node: ReactNode): ReactNode {\n while (\n node !== null &&\n typeof node === \"object\" &&\n \"type\" in node &&\n typeof node.type === \"function\"\n ) {\n const el = node as ReactElement<Record<string, unknown>>;\n node = (el.type as (props: Record<string, unknown>) => ReactNode)(\n el.props ?? {},\n );\n }\n return node;\n}\n\n/**\n * A run of adjacent text and `<br>`s, which a browser lays out as one\n * anonymous flex item: the pieces of text between the `<br>`s, one more than\n * there are `<br>`s.\n */\nclass TextRun {\n readonly pieces: string[];\n\n constructor(...pieces: string[]) {\n this.pieces = pieces;\n }\n}\n\nconst isTextRun = (node: unknown): node is TextRun => node instanceof TextRun;\n\n/** A run's text, as a string when there's no `<br>` in it. */\nconst textContentOf = (run: TextRun): TextContent =>\n run.pieces.length === 1 ? run.pieces[0]! : run.pieces;\n\n/** Whether a run is nothing but white space, with no `<br>` either. */\nconst isBlankRun = (run: TextRun): boolean =>\n run.pieces.length === 1 && isWhiteSpaceOnly(run.pieces[0]!);\n\n/** A child as the DOM has it: an element, or a run of text. */\ntype Item = ReactNode | TextRun;\n\n/**\n * The children as the DOM has them: function components rendered, fragments\n * and arrays unwrapped, null, undefined and booleans left out, and adjacent\n * text, as `Hello {name}` or a fragment of text gives, merged into one run,\n * with the `<br>`s between it, which are forced breaks in that run, as in\n * the browser. A `<br>` that isn't displayed is left out.\n */\nfunction flattenChildren(node: ReactNode, items: Item[] = []): Item[] {\n const rendered = renderComponents(node);\n if (\n rendered === null ||\n rendered === undefined ||\n typeof rendered === \"boolean\"\n ) {\n return items;\n }\n if (Array.isArray(rendered)) {\n for (const child of rendered as ReactNode[]) flattenChildren(child, items);\n return items;\n }\n const el = rendered as ReactElement<{ children?: ReactNode }>;\n if (typeof rendered === \"object\" && (el.type as unknown) === REACT_FRAGMENT) {\n return flattenChildren(el.props?.children, items);\n }\n const last = items[items.length - 1];\n if (isText(rendered)) {\n if (isTextRun(last)) {\n last.pieces[last.pieces.length - 1] += String(rendered);\n } else {\n items.push(new TextRun(String(rendered)));\n }\n } else if (!isBreak(rendered)) {\n items.push(rendered);\n } else if (!isHidden(rendered)) {\n if (isTextRun(last)) last.pieces.push(\"\");\n else items.push(new TextRun(\"\", \"\"));\n }\n return items;\n}\n\nconst isBreak = (node: ReactNode): node is ReactElement<{ style?: unknown }> =>\n typeof node === \"object\" &&\n node !== null &&\n (node as ReactElement).type === \"br\";\n\nconst isHidden = (el: ReactElement<{ style?: unknown }>): boolean =>\n (el.props.style as { display?: unknown } | undefined)?.display === \"none\";\n\n/** Floor to a whole pixel, as Yoga does text (snapping values within 1e-4). */\nfunction floorToPixel(value: number): number {\n const rounded = Math.round(value);\n return Math.abs(value - rounded) < 1e-4 ? rounded : Math.floor(value);\n}\n\nfunction extractLayout(node: IntermediateNode, yogaNode: YogaNode): LayoutNode {\n const layout = yogaNode.getComputedLayout();\n // Yoga leaves text nodes unrounded (see `createTextYogaNode`) for their\n // width; they're placed on whole pixels, floored as Yoga rounds text.\n const place = node.textMeasure ? floorToPixel : (v: number) => v;\n\n return {\n type: node.type,\n style: node.style,\n children: node.children.map((child, i) => {\n const childYoga = yogaNode.getChild(i);\n return extractLayout(child, childYoga);\n }),\n textContent: node.textContent,\n textLayout: node.textMeasure?.layout,\n props: node.props,\n x: place(layout.left),\n y: place(layout.top),\n width: layout.width,\n height: layout.height,\n };\n}\n\n/**\n * React's `Fragment` type. A registered symbol shared by all React copies,\n * so we can detect fragments without a runtime dependency on `react`.\n */\nconst REACT_FRAGMENT = Symbol.for(\"react.fragment\");\n\n/**\n * Resolve function components, unwrap fragments, and flatten nested arrays\n * inside an `<svg>` subtree. The SVG drawer switches on primitive element\n * strings (path, rect, etc.) and does not flatten its own children, so\n * without this preprocessing (a) function components and fragments silently\n * disappear and (b) helpers returning arrays crash the defs collector.\n */\nfunction resolveSvgTree(node: ReactNode): ReactNode {\n if (node === null || node === undefined || typeof node === \"boolean\")\n return null;\n if (typeof node === \"string\" || typeof node === \"number\") return node;\n\n if (Array.isArray(node)) {\n const out: ReactNode[] = [];\n let changed = false;\n for (const child of node as ReactNode[]) {\n const resolved = resolveSvgTree(child);\n if (resolved === null || resolved === undefined) {\n changed = true;\n continue;\n }\n if (Array.isArray(resolved)) {\n changed = true;\n for (const r of resolved) out.push(r);\n } else {\n if (resolved !== child) changed = true;\n out.push(resolved);\n }\n }\n return changed ? out : node;\n }\n\n const el = node as ReactElement<Record<string, unknown>>;\n if (typeof el.type === \"function\") {\n const rendered = (el.type as (props: Record<string, unknown>) => ReactNode)(\n el.props ?? {},\n );\n return resolveSvgTree(rendered);\n }\n\n // Unwrap fragments: their children take the fragment's place in the parent\n // (callers flatten arrays), since the drawer only knows SVG element strings.\n if ((el.type as unknown) === REACT_FRAGMENT) {\n return resolveSvgTree((el.props ?? {}).children as ReactNode);\n }\n\n const elProps = (el.props ?? {}) as Record<string, unknown>;\n if (elProps.children !== undefined) {\n const resolvedChildren = resolveSvgTree(elProps.children as ReactNode);\n if (resolvedChildren !== elProps.children) {\n return { ...el, props: { ...elProps, children: resolvedChildren } };\n }\n }\n return el;\n}\n","import type { SKRSContext2D } from \"@effing/skia\";\nimport type { ReactNode } from \"react\";\n\nimport type { RenderReactElementOptions } from \"../types.ts\";\nimport { drawNode } from \"./draw/index.ts\";\nimport { ensureFontsRegistered } from \"./font.ts\";\nimport { buildLayoutTree } from \"./layout.ts\";\nimport { releaseParagraphs } from \"./text/native.ts\";\nimport type { RenderContext } from \"./context.ts\";\n\n/**\n * Render a React element tree to a canvas context.\n *\n * Width and height default to `ctx.canvas.width` / `ctx.canvas.height` but\n * can be overridden via `options.width` and `options.height`. This is useful\n * for HiDPI rendering where the canvas is larger than the logical layout size.\n *\n * @param ctx - Canvas 2D rendering context to draw into\n * @param element - React element tree to render\n * @param options - Rendering options (fonts, dimensions, debug mode)\n *\n * @example\n * ```tsx\n * import { createCanvas, renderReactElement } from \"@effing/canvas\";\n *\n * const canvas = createCanvas(1080, 1080);\n * const ctx = canvas.getContext(\"2d\");\n *\n * await renderReactElement(ctx, <MyComponent />, { fonts: [myFont] });\n *\n * const png = await canvas.encode(\"png\");\n * ```\n *\n * @example HiDPI rendering (2x)\n * ```tsx\n * const dpr = 2;\n * const canvas = createCanvas(1080 * dpr, 1080 * dpr);\n * const ctx = canvas.getContext(\"2d\");\n * ctx.scale(dpr, dpr);\n *\n * await renderReactElement(ctx, <MyComponent />, {\n * fonts: [myFont],\n * width: 1080,\n * height: 1080,\n * });\n * ```\n *\n * @example Custom User-Agent for remote image fetches\n * ```tsx\n * await renderReactElement(ctx, <MyComponent />, {\n * userAgent: \"my-renderer/1.0\",\n * });\n * ```\n *\n * @example Persistent image cache for repeated calls (e.g. per frame)\n * ```tsx\n * const imageCache: ImageCache = new Map();\n * for (let frame = 0; frame < frameCount; frame++) {\n * await renderReactElement(ctx, <Frame n={frame} />, { fonts, imageCache });\n * }\n * ```\n */\nexport async function renderReactElement(\n ctx: SKRSContext2D,\n element: ReactNode,\n options: RenderReactElementOptions = {},\n): Promise<void> {\n const fonts = options.fonts ?? [];\n\n // Register fonts\n ensureFontsRegistered(fonts);\n\n // Get dimensions (option overrides take precedence over canvas size)\n const width = options.width ?? ctx.canvas.width;\n const height = options.height ?? ctx.canvas.height;\n\n // Per-render context: shared image cache + cross-cutting fetch/diagnostic\n // config, threaded through both the layout and draw phases. The caller may\n // supply the cache to persist image loads across calls.\n const renderContext: RenderContext = {\n imageCache: options.imageCache ?? new Map(),\n userAgent: options.userAgent,\n debug: options.debug ?? false,\n };\n\n // Build layout tree (Yoga)\n const emojiStyle =\n options.emoji === \"none\" ? undefined : (options.emoji ?? \"twemoji\");\n const fontFamilies = [...new Set(fonts.map((f) => f.name))];\n const { tree: layoutTree } = await buildLayoutTree(\n element,\n width,\n height,\n !!emojiStyle,\n fontFamilies,\n renderContext,\n );\n\n // Draw to canvas\n await drawNode(ctx, layoutTree, 0, 0, renderContext, emojiStyle);\n\n // Text is laid out as native paragraphs, whose memory Node releases only on\n // a turn of the event loop: take one when a caller's loop hasn't.\n await releaseParagraphs();\n}\n","import type { FontData } from \"./types.ts\";\nimport type { ComputedStyle } from \"./jsx/style/compute.ts\";\nimport { registerFont } from \"./jsx/font.ts\";\nimport { layoutText } from \"./jsx/text/index.ts\";\n\n/**\n * Options for {@link findLargestUsableFontSize}.\n */\nexport type FindLargestUsableFontSizeOptions = {\n /** The text to fit */\n text: string;\n /** Font data to use for measurement */\n font: FontData;\n /** Maximum width in pixels */\n maxWidth: number;\n /** Maximum height in pixels */\n maxHeight: number;\n /** Line height — `\"normal\"` uses font metrics, numeric values are CSS multipliers */\n lineHeight?: number | \"normal\";\n /**\n * Whitespace handling, as in CSS (default: `\"normal\"`). Use `\"nowrap\"` to\n * fit the text on one line instead of wrapping to `maxWidth`, its newlines\n * collapsing to spaces, or `\"pre\"` to fit each newline-separated paragraph\n * on a line of its own.\n */\n whiteSpace?: ComputedStyle[\"whiteSpace\"];\n /** Minimum font size to consider (default: 1) */\n minFontSize?: number;\n /** Maximum font size to consider (default: 1000) */\n maxFontSize?: number;\n};\n\n/**\n * Find the largest integer font size that keeps text within the given bounds.\n *\n * Uses binary search over integer font sizes, measuring with {@link layoutText}\n * at each step. Returns `minFontSize` if even the smallest size overflows.\n *\n * By default text wraps to `maxWidth` and is fit into the `maxWidth` × `maxHeight`\n * box. Set `whiteSpace: \"nowrap\"` to fit the text on one line instead (or\n * `\"pre\"` for one line per newline-separated paragraph), in which case\n * `maxWidth` constrains the full line width.\n */\nexport function findLargestUsableFontSize(\n options: FindLargestUsableFontSizeOptions,\n): number {\n const {\n text,\n font,\n maxWidth,\n maxHeight,\n lineHeight = \"normal\",\n whiteSpace,\n minFontSize = 1,\n maxFontSize = 1000,\n } = options;\n\n registerFont(font);\n\n let lo = minFontSize;\n let hi = maxFontSize;\n let best = minFontSize;\n\n while (lo <= hi) {\n const mid = Math.floor((lo + hi) / 2);\n const style: ComputedStyle = {\n fontSize: mid,\n fontFamily: font.name,\n fontWeight: font.weight,\n fontStyle: font.style,\n lineHeight: lineHeight === \"normal\" ? undefined : lineHeight,\n whiteSpace,\n };\n\n const result = layoutText(text, style, maxWidth);\n\n if (result.width <= maxWidth && result.height <= maxHeight) {\n best = mid;\n lo = mid + 1;\n } else {\n hi = mid - 1;\n }\n }\n\n return best;\n}\n"],"mappings":"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","names":["GlobalFonts","Path2D","graphemeSegmenter","resolveRadius","x","y","Path2D","Path2D","createCanvas","canvas","Path2D","Path2D","Path2D","Path2D","loadImage","parseCssColor","EMOJI_CHAR","loadImage","parseCssColor","runaway","unsettled","createCanvas"]}