@codehz/draw-call 0.5.2 → 0.6.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.
@@ -1,11 +1,9 @@
1
- Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  let _napi_rs_canvas = require("@napi-rs/canvas");
3
-
4
3
  //#region src/compat/index.ts
5
4
  function createRawCanvas(width, height) {
6
5
  return (0, _napi_rs_canvas.createCanvas)(width, height);
7
6
  }
8
-
9
7
  //#endregion
10
8
  //#region src/types/base.ts
11
9
  function linearGradient(angle, ...stops) {
@@ -76,7 +74,6 @@ function normalizeBorderRadius(value) {
76
74
  ];
77
75
  return value;
78
76
  }
79
-
80
77
  //#endregion
81
78
  //#region src/layout/components/box.ts
82
79
  /**
@@ -189,7 +186,6 @@ function measureBoxSize(element, ctx, availableWidth, measureChild) {
189
186
  height: typeof element.height === "number" ? element.height : intrinsicHeight
190
187
  };
191
188
  }
192
-
193
189
  //#endregion
194
190
  //#region src/layout/components/customDraw.ts
195
191
  /**
@@ -206,7 +202,6 @@ function measureCustomDrawSize(element, ctx, availableWidth, measureChild) {
206
202
  height: 0
207
203
  };
208
204
  }
209
-
210
205
  //#endregion
211
206
  //#region src/layout/components/image.ts
212
207
  /**
@@ -232,7 +227,6 @@ function measureImageSize(element, _ctx, _availableWidth) {
232
227
  height: 0
233
228
  };
234
229
  }
235
-
236
230
  //#endregion
237
231
  //#region src/layout/components/richtext.ts
238
232
  /**
@@ -400,7 +394,6 @@ function wrapRichText(ctx, spans, maxWidth, lineHeightScale = 1.2, elementStyle
400
394
  }];
401
395
  return lines;
402
396
  }
403
-
404
397
  //#endregion
405
398
  //#region src/layout/components/stack.ts
406
399
  /**
@@ -437,7 +430,6 @@ function measureStackSize(element, ctx, availableWidth, measureChild) {
437
430
  height: typeof element.height === "number" ? element.height : intrinsicHeight
438
431
  };
439
432
  }
440
-
441
433
  //#endregion
442
434
  //#region src/layout/components/svg.ts
443
435
  /**
@@ -471,7 +463,6 @@ function measureSvgSize(element, _ctx, _availableWidth) {
471
463
  height: 0
472
464
  };
473
465
  }
474
-
475
466
  //#endregion
476
467
  //#region src/render/utils/font.ts
477
468
  /**
@@ -482,23 +473,42 @@ function measureSvgSize(element, _ctx, _availableWidth) {
482
473
  function buildFontString(font) {
483
474
  return `${font.style ?? "normal"} ${font.weight ?? "normal"} ${font.size ?? 16}px ${font.family ?? "sans-serif"}`;
484
475
  }
485
-
486
476
  //#endregion
487
477
  //#region src/layout/utils/measure.ts
478
+ const MEASURE_CACHE_LIMIT = 256;
488
479
  function createCanvasMeasureContext(ctx) {
480
+ const cache = /* @__PURE__ */ new Map();
481
+ let lastFontString = null;
489
482
  return { measureText(text, font) {
490
- ctx.font = buildFontString(font);
491
- ctx.textBaseline = "middle";
483
+ const fontString = buildFontString(font);
484
+ const key = fontString + "\0" + text;
485
+ const hit = cache.get(key);
486
+ if (hit !== void 0) {
487
+ cache.delete(key);
488
+ cache.set(key, hit);
489
+ return hit;
490
+ }
491
+ if (fontString !== lastFontString) {
492
+ ctx.font = fontString;
493
+ ctx.textBaseline = "middle";
494
+ lastFontString = fontString;
495
+ }
492
496
  const metrics = ctx.measureText(text);
493
497
  const height = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
494
498
  const fontSize = font.size || 16;
495
- return {
499
+ const result = {
496
500
  width: metrics.width,
497
501
  height: height || fontSize,
498
502
  offset: (metrics.actualBoundingBoxAscent - metrics.actualBoundingBoxDescent) / 2,
499
503
  ascent: metrics.actualBoundingBoxAscent,
500
504
  descent: metrics.actualBoundingBoxDescent
501
505
  };
506
+ if (cache.size >= MEASURE_CACHE_LIMIT) {
507
+ const oldest = cache.keys().next().value;
508
+ if (oldest !== void 0) cache.delete(oldest);
509
+ }
510
+ cache.set(key, result);
511
+ return result;
502
512
  } };
503
513
  }
504
514
  function wrapText(ctx, text, maxWidth, font) {
@@ -574,7 +584,6 @@ function truncateText(ctx, text, maxWidth, font, ellipsis = "...") {
574
584
  offset
575
585
  };
576
586
  }
577
-
578
587
  //#endregion
579
588
  //#region src/layout/components/text.ts
580
589
  /**
@@ -600,7 +609,6 @@ function measureTextSize(element, ctx, availableWidth) {
600
609
  height: Math.max(height, lineHeightPx)
601
610
  };
602
611
  }
603
-
604
612
  //#endregion
605
613
  //#region src/layout/components/transform.ts
606
614
  /**
@@ -611,7 +619,6 @@ function measureTextSize(element, ctx, availableWidth) {
611
619
  function measureTransformSize(element, ctx, availableWidth, measureIntrinsicSize) {
612
620
  return measureIntrinsicSize(element.children, ctx, availableWidth);
613
621
  }
614
-
615
622
  //#endregion
616
623
  //#region src/layout/components/index.ts
617
624
  /**
@@ -633,7 +640,6 @@ function measureIntrinsicSize(element, ctx, availableWidth) {
633
640
  };
634
641
  }
635
642
  }
636
-
637
643
  //#endregion
638
644
  //#region src/layout/utils/offset.ts
639
645
  /**
@@ -646,7 +652,6 @@ function applyOffset(node, dx, dy) {
646
652
  node.layout.contentY += dy;
647
653
  for (const child of node.children) applyOffset(child, dx, dy);
648
654
  }
649
-
650
655
  //#endregion
651
656
  //#region src/types/layout.ts
652
657
  function resolveSize(size, available, auto) {
@@ -661,7 +666,6 @@ function sizeNeedsParent(size) {
661
666
  if (typeof size === "string" && size.endsWith("%")) return true;
662
667
  return false;
663
668
  }
664
-
665
669
  //#endregion
666
670
  //#region src/layout/engine.ts
667
671
  /**
@@ -781,7 +785,14 @@ function computeLayoutImpl(element, ctx, constraints, x = 0, y = 0) {
781
785
  }
782
786
  if (layoutElement.type === "richtext") {
783
787
  const lineHeight = layoutElement.lineHeight ?? 1.2;
784
- let lines = wrapRichText(ctx, layoutElement.spans, contentWidth, lineHeight);
788
+ const elementStyle = {
789
+ font: layoutElement.font,
790
+ color: layoutElement.color,
791
+ background: layoutElement.background,
792
+ underline: layoutElement.underline,
793
+ strikethrough: layoutElement.strikethrough
794
+ };
795
+ let lines = wrapRichText(ctx, layoutElement.spans, contentWidth, lineHeight, elementStyle);
785
796
  if (layoutElement.maxLines && lines.length > layoutElement.maxLines) {
786
797
  lines = lines.slice(0, layoutElement.maxLines);
787
798
  if (layoutElement.ellipsis && lines.length > 0) {
@@ -1079,7 +1090,6 @@ function computeLayoutImpl(element, ctx, constraints, x = 0, y = 0) {
1079
1090
  }
1080
1091
  return node;
1081
1092
  }
1082
-
1083
1093
  //#endregion
1084
1094
  //#region src/render/utils/colors.ts
1085
1095
  function isGradientDescriptor$1(color) {
@@ -1115,7 +1125,6 @@ function resolveColor$1(ctx, color, x, y, width, height) {
1115
1125
  if (isGradientDescriptor$1(color)) return resolveGradient$1(ctx, color, x, y, width, height);
1116
1126
  return color;
1117
1127
  }
1118
-
1119
1128
  //#endregion
1120
1129
  //#region src/render/utils/shadows.ts
1121
1130
  function applyShadow$1(ctx, shadow) {
@@ -1137,7 +1146,6 @@ function clearShadow$1(ctx) {
1137
1146
  ctx.shadowBlur = 0;
1138
1147
  ctx.shadowColor = "transparent";
1139
1148
  }
1140
-
1141
1149
  //#endregion
1142
1150
  //#region src/render/utils/shapes.ts
1143
1151
  function roundRectPath(ctx, x, y, width, height, radius) {
@@ -1154,7 +1162,6 @@ function roundRectPath(ctx, x, y, width, height, radius) {
1154
1162
  ctx.quadraticCurveTo(x, y, x + tl, y);
1155
1163
  ctx.closePath();
1156
1164
  }
1157
-
1158
1165
  //#endregion
1159
1166
  //#region src/render/components/box.ts
1160
1167
  function renderBox(ctx, node) {
@@ -1183,125 +1190,90 @@ function renderBox(ctx, node) {
1183
1190
  }
1184
1191
  if (element.opacity !== void 0 && element.opacity < 1) ctx.globalAlpha = 1;
1185
1192
  }
1186
-
1187
1193
  //#endregion
1188
- //#region src/render/components/ProxiedCanvasContext.ts
1189
- /**
1190
- * ProxiedCanvasContext - Canvas 上下文代理类
1191
- *
1192
- * 该类提供对真实 CanvasRenderingContext2D 的代理,有以下功能:
1193
- * 1. 管理 save/restore 的平衡(计数器)
1194
- * 2. 追踪相对变换而不是绝对变换
1195
- * 3. 在析构时自动恢复所有未恢复的状态
1196
- * 4. 转发所有其他 Canvas API 调用
1197
- */
1198
- var ProxiedCanvasContext = class {
1199
- /**
1200
- * 真实的 Canvas 上下文
1201
- */
1202
- ctx;
1203
- /**
1204
- * 基础变换矩阵(初始化时设置,保持不变)
1205
- */
1194
+ //#region src/render/components/CustomDrawContext.ts
1195
+ function cloneMatrix(matrix) {
1196
+ return new _napi_rs_canvas.DOMMatrix([
1197
+ matrix.a,
1198
+ matrix.b,
1199
+ matrix.c,
1200
+ matrix.d,
1201
+ matrix.e,
1202
+ matrix.f
1203
+ ]);
1204
+ }
1205
+ function toRelativeMatrix(transform) {
1206
+ if (transform === void 0) return new _napi_rs_canvas.DOMMatrix();
1207
+ if (transform instanceof _napi_rs_canvas.DOMMatrix) return cloneMatrix(transform);
1208
+ return new _napi_rs_canvas.DOMMatrix(transform);
1209
+ }
1210
+ var ManagedCustomDrawContext = class {
1211
+ canvas;
1206
1212
  baseTransform;
1207
- /**
1208
- * 相对变换矩阵(用户通过 setTransform 设置)
1209
- */
1210
1213
  relativeTransform;
1211
- /**
1212
- * save/restore 计数器
1213
- */
1214
+ transformStack = [];
1214
1215
  saveCount = 0;
1215
- /**
1216
- * 构造函数
1217
- * @param ctx 真实的 CanvasRenderingContext2D
1218
- * @param baseTransform 初始的基础变换矩阵
1219
- */
1220
- constructor(ctx, baseTransform) {
1221
- this.ctx = ctx;
1222
- this.baseTransform = baseTransform;
1216
+ constructor(canvas, baseTransform) {
1217
+ this.canvas = canvas;
1218
+ this.baseTransform = cloneMatrix(baseTransform);
1223
1219
  this.relativeTransform = new _napi_rs_canvas.DOMMatrix();
1224
1220
  }
1225
- /**
1226
- * save() - 保存当前状态并增加计数
1227
- */
1228
1221
  save() {
1229
1222
  this.saveCount++;
1230
- this.ctx.save();
1223
+ this.transformStack.push(cloneMatrix(this.relativeTransform));
1224
+ this.canvas.save();
1231
1225
  }
1232
- /**
1233
- * restore() - 恢复上一个状态并减少计数
1234
- */
1235
1226
  restore() {
1236
- if (this.saveCount > 0) {
1237
- this.saveCount--;
1238
- this.ctx.restore();
1239
- }
1227
+ if (this.saveCount === 0) return;
1228
+ this.saveCount--;
1229
+ this.relativeTransform = this.transformStack.pop() ?? new _napi_rs_canvas.DOMMatrix();
1230
+ this.canvas.restore();
1231
+ this.applyRelativeTransform();
1240
1232
  }
1241
- /**
1242
- * setTransform() - 设置相对变换
1243
- */
1244
- setTransform(...args) {
1245
- let matrix;
1246
- if (args.length === 1 && args[0] instanceof _napi_rs_canvas.DOMMatrix) matrix = args[0];
1247
- else if (args.length === 6) matrix = new _napi_rs_canvas.DOMMatrix([
1248
- args[0],
1249
- args[1],
1250
- args[2],
1251
- args[3],
1252
- args[4],
1253
- args[5]
1254
- ]);
1255
- else return;
1256
- this.relativeTransform = matrix;
1257
- const actualTransform = this.baseTransform.multiply(matrix);
1258
- this.ctx.setTransform(actualTransform);
1259
- }
1260
- /**
1261
- * getTransform() - 返回相对变换(而不是绝对变换)
1262
- */
1263
1233
  getTransform() {
1264
- return this.relativeTransform;
1234
+ return cloneMatrix(this.relativeTransform);
1235
+ }
1236
+ setTransform(transform) {
1237
+ this.relativeTransform = toRelativeMatrix(transform);
1238
+ this.applyRelativeTransform();
1239
+ }
1240
+ resetTransform() {
1241
+ this.relativeTransform = new _napi_rs_canvas.DOMMatrix();
1242
+ this.applyRelativeTransform();
1243
+ }
1244
+ translate(x, y) {
1245
+ this.relativeTransform = this.relativeTransform.translate(x, y);
1246
+ this.applyRelativeTransform();
1247
+ }
1248
+ rotate(angle) {
1249
+ this.relativeTransform = this.relativeTransform.rotate(angle * 180 / Math.PI);
1250
+ this.applyRelativeTransform();
1251
+ }
1252
+ scale(x, y) {
1253
+ this.relativeTransform = this.relativeTransform.scale(x, y ?? x);
1254
+ this.applyRelativeTransform();
1255
+ }
1256
+ transform(a, b, c, d, e, f) {
1257
+ this.relativeTransform = this.relativeTransform.multiply(new _napi_rs_canvas.DOMMatrix([
1258
+ a,
1259
+ b,
1260
+ c,
1261
+ d,
1262
+ e,
1263
+ f
1264
+ ]));
1265
+ this.applyRelativeTransform();
1265
1266
  }
1266
- /**
1267
- * 析构函数级的清理 - 自动恢复所有未恢复的 save
1268
- */
1269
1267
  destroy() {
1270
- while (this.saveCount > 0) {
1271
- console.log("destroy restore", this.saveCount);
1272
- this.saveCount--;
1273
- this.ctx.restore();
1274
- }
1268
+ while (this.saveCount > 0) this.restore();
1269
+ }
1270
+ applyRelativeTransform() {
1271
+ this.canvas.setTransform(this.baseTransform.multiply(this.relativeTransform));
1275
1272
  }
1276
1273
  };
1277
- function createProxiedCanvasContext(ctx, baseTransform) {
1278
- const proxy = new ProxiedCanvasContext(ctx, baseTransform);
1279
- return new Proxy(proxy, {
1280
- get(target, prop, receiver) {
1281
- if (prop === "save" || prop === "restore" || prop === "setTransform" || prop === "getTransform" || prop === "destroy") return Reflect.get(target, prop, receiver).bind(proxy);
1282
- const ownValue = Reflect.get(target, prop, receiver);
1283
- if (ownValue !== void 0) return ownValue;
1284
- const contextValue = target.ctx[prop];
1285
- if (typeof contextValue === "function") return contextValue.bind(target.ctx);
1286
- return contextValue;
1287
- },
1288
- set(target, prop, value, _receiver) {
1289
- target.ctx[prop] = value;
1290
- return true;
1291
- },
1292
- has(target, prop) {
1293
- if (prop === "save" || prop === "restore" || prop === "setTransform" || prop === "getTransform" || prop === "destroy") return true;
1294
- return prop in target.ctx;
1295
- },
1296
- ownKeys(target) {
1297
- return Reflect.ownKeys(target.ctx);
1298
- },
1299
- getOwnPropertyDescriptor(target, prop) {
1300
- return Reflect.getOwnPropertyDescriptor(target.ctx, prop);
1301
- }
1302
- });
1274
+ function createCustomDrawContext(canvas, baseTransform) {
1275
+ return new ManagedCustomDrawContext(canvas, baseTransform);
1303
1276
  }
1304
-
1305
1277
  //#endregion
1306
1278
  //#region src/render/components/customDraw.ts
1307
1279
  /**
@@ -1312,7 +1284,7 @@ function renderCustomDraw(ctx, node) {
1312
1284
  const element = node.element;
1313
1285
  ctx.save();
1314
1286
  ctx.translate(node.layout.x, node.layout.y);
1315
- const proxyCtx = createProxiedCanvasContext(ctx, ctx.getTransform());
1287
+ const customCtx = createCustomDrawContext(ctx, ctx.getTransform());
1316
1288
  const inner = () => {
1317
1289
  if (node.children && node.children.length > 0) {
1318
1290
  ctx.save();
@@ -1321,15 +1293,14 @@ function renderCustomDraw(ctx, node) {
1321
1293
  ctx.restore();
1322
1294
  }
1323
1295
  };
1324
- element.draw(proxyCtx, {
1296
+ element.draw(customCtx, {
1325
1297
  inner,
1326
1298
  width: node.layout.contentWidth,
1327
1299
  height: node.layout.contentHeight
1328
1300
  });
1329
- proxyCtx.destroy();
1301
+ customCtx.destroy();
1330
1302
  ctx.restore();
1331
1303
  }
1332
-
1333
1304
  //#endregion
1334
1305
  //#region src/render/components/image.ts
1335
1306
  function renderImage(ctx, node) {
@@ -1415,7 +1386,6 @@ function renderImage(ctx, node) {
1415
1386
  }
1416
1387
  if (element.opacity !== void 0 && element.opacity < 1) ctx.globalAlpha = 1;
1417
1388
  }
1418
-
1419
1389
  //#endregion
1420
1390
  //#region src/render/components/richtext.ts
1421
1391
  function renderRichText(ctx, node) {
@@ -1466,7 +1436,6 @@ function renderRichText(ctx, node) {
1466
1436
  currentY += line.height;
1467
1437
  }
1468
1438
  }
1469
-
1470
1439
  //#endregion
1471
1440
  //#region src/render/components/svg.ts
1472
1441
  function isGradientDescriptor(color) {
@@ -1738,7 +1707,6 @@ function renderSvg(ctx, node) {
1738
1707
  for (const child of element.children) renderSvgChild(ctx, child, transform, bounds, baseTransform);
1739
1708
  ctx.restore();
1740
1709
  }
1741
-
1742
1710
  //#endregion
1743
1711
  //#region src/render/components/text.ts
1744
1712
  function renderText(ctx, node) {
@@ -1773,7 +1741,6 @@ function renderText(ctx, node) {
1773
1741
  }
1774
1742
  if (element.shadow) clearShadow$1(ctx);
1775
1743
  }
1776
-
1777
1744
  //#endregion
1778
1745
  //#region src/render/components/transform.ts
1779
1746
  /**
@@ -1849,7 +1816,6 @@ function renderTransform(ctx, node) {
1849
1816
  renderNode(ctx, childNode);
1850
1817
  ctx.restore();
1851
1818
  }
1852
-
1853
1819
  //#endregion
1854
1820
  //#region src/render/index.ts
1855
1821
  function renderNode(ctx, node) {
@@ -1889,7 +1855,6 @@ function renderNode(ctx, node) {
1889
1855
  break;
1890
1856
  }
1891
1857
  }
1892
-
1893
1858
  //#endregion
1894
1859
  //#region src/canvas.ts
1895
1860
  /**
@@ -1959,7 +1924,6 @@ function createCanvas(options) {
1959
1924
  }
1960
1925
  };
1961
1926
  }
1962
-
1963
1927
  //#endregion
1964
1928
  //#region src/components/Box.ts
1965
1929
  function Box(props) {
@@ -1968,7 +1932,6 @@ function Box(props) {
1968
1932
  ...props
1969
1933
  };
1970
1934
  }
1971
-
1972
1935
  //#endregion
1973
1936
  //#region src/components/CustomDraw.ts
1974
1937
  function CustomDraw(props) {
@@ -1977,7 +1940,6 @@ function CustomDraw(props) {
1977
1940
  ...props
1978
1941
  };
1979
1942
  }
1980
-
1981
1943
  //#endregion
1982
1944
  //#region src/components/Image.ts
1983
1945
  function Image(props) {
@@ -1986,7 +1948,6 @@ function Image(props) {
1986
1948
  ...props
1987
1949
  };
1988
1950
  }
1989
-
1990
1951
  //#endregion
1991
1952
  //#region src/components/RichText.ts
1992
1953
  function RichText(props) {
@@ -1995,7 +1956,6 @@ function RichText(props) {
1995
1956
  ...props
1996
1957
  };
1997
1958
  }
1998
-
1999
1959
  //#endregion
2000
1960
  //#region src/components/Stack.ts
2001
1961
  function Stack(props) {
@@ -2004,7 +1964,6 @@ function Stack(props) {
2004
1964
  ...props
2005
1965
  };
2006
1966
  }
2007
-
2008
1967
  //#endregion
2009
1968
  //#region src/components/Svg.ts
2010
1969
  function Svg(props) {
@@ -2051,7 +2010,6 @@ const svg = {
2051
2010
  ...props
2052
2011
  })
2053
2012
  };
2054
-
2055
2013
  //#endregion
2056
2014
  //#region src/components/Text.ts
2057
2015
  function Text(props) {
@@ -2060,7 +2018,6 @@ function Text(props) {
2060
2018
  ...props
2061
2019
  };
2062
2020
  }
2063
-
2064
2021
  //#endregion
2065
2022
  //#region src/components/Transform.ts
2066
2023
  function Transform(props) {
@@ -2069,7 +2026,6 @@ function Transform(props) {
2069
2026
  ...props
2070
2027
  };
2071
2028
  }
2072
-
2073
2029
  //#endregion
2074
2030
  //#region src/layout/utils/print.ts
2075
2031
  /**
@@ -2129,7 +2085,6 @@ function printLayout(node) {
2129
2085
  function layoutToString(node, _indent = " ") {
2130
2086
  return printLayoutToString(node, "", true).join("\n");
2131
2087
  }
2132
-
2133
2088
  //#endregion
2134
2089
  exports.Box = Box;
2135
2090
  exports.CustomDraw = CustomDraw;
@@ -2146,4 +2101,4 @@ exports.layoutToString = layoutToString;
2146
2101
  exports.linearGradient = linearGradient;
2147
2102
  exports.printLayout = printLayout;
2148
2103
  exports.radialGradient = radialGradient;
2149
- exports.svg = svg;
2104
+ exports.svg = svg;