modern-text 0.2.37 → 0.2.38

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.cjs CHANGED
@@ -76,27 +76,6 @@ function drawPath(options) {
76
76
  ctx.restore();
77
77
  }
78
78
 
79
- function fillBackground(ctx, text) {
80
- const { computedStyle: style, paragraphs } = text;
81
- function fillBackground2(color, x, y, width, height) {
82
- ctx.fillStyle = color;
83
- ctx.fillRect(x, y, width, height);
84
- }
85
- if (style?.backgroundColor) {
86
- fillBackground2(style.backgroundColor, 0, 0, ctx.canvas.width, ctx.canvas.height);
87
- }
88
- paragraphs.forEach((paragraph) => {
89
- if (paragraph.style?.backgroundColor) {
90
- fillBackground2(paragraph.computedStyle.backgroundColor, ...paragraph.boundingBox.toArray());
91
- }
92
- paragraph.fragments.forEach((fragment) => {
93
- if (fragment.style?.backgroundColor) {
94
- fillBackground2(fragment.computedStyle.backgroundColor, ...fragment.boundingBox.toArray());
95
- }
96
- });
97
- });
98
- }
99
-
100
79
  function setupView(ctx, pixelRatio, boundingBox) {
101
80
  const { left, top, width, height } = boundingBox;
102
81
  const view = ctx.canvas;
@@ -117,9 +96,9 @@ function uploadColors(ctx, text) {
117
96
  const { paragraphs, computedStyle: style, renderBoundingBox } = text;
118
97
  uploadColor(style, renderBoundingBox, ctx);
119
98
  paragraphs.forEach((paragraph) => {
120
- uploadColor(paragraph.computedStyle, paragraph.boundingBox, ctx);
99
+ uploadColor(paragraph.computedStyle, paragraph.lineBox, ctx);
121
100
  paragraph.fragments.forEach((fragment) => {
122
- uploadColor(fragment.computedStyle, fragment.boundingBox, ctx);
101
+ uploadColor(fragment.computedStyle, fragment.inlineBox, ctx);
123
102
  });
124
103
  });
125
104
  }
@@ -161,13 +140,9 @@ class Character {
161
140
  this.content = content;
162
141
  this.index = index;
163
142
  this.parent = parent;
164
- // measure dom
165
- __publicField$3(this, "boundingBox", new modernPath2d.BoundingBox());
166
- __publicField$3(this, "textWidth", 0);
167
- __publicField$3(this, "textHeight", 0);
168
- // font glyph
169
- __publicField$3(this, "glyphHeight", 0);
170
- __publicField$3(this, "glyphWidth", 0);
143
+ __publicField$3(this, "lineBox", new modernPath2d.BoundingBox());
144
+ __publicField$3(this, "inlineBox", new modernPath2d.BoundingBox());
145
+ __publicField$3(this, "glyphBox", new modernPath2d.BoundingBox());
171
146
  __publicField$3(this, "underlinePosition", 0);
172
147
  __publicField$3(this, "underlineThickness", 0);
173
148
  __publicField$3(this, "yStrikeoutPosition", 0);
@@ -175,7 +150,6 @@ class Character {
175
150
  __publicField$3(this, "baseline", 0);
176
151
  __publicField$3(this, "centerDiviation", 0);
177
152
  __publicField$3(this, "path", new modernPath2d.Path2D());
178
- __publicField$3(this, "glyphBox", new modernPath2d.BoundingBox());
179
153
  __publicField$3(this, "center", new modernPath2d.Vector2());
180
154
  }
181
155
  get computedStyle() {
@@ -187,6 +161,9 @@ class Character {
187
161
  get fontSize() {
188
162
  return this.computedStyle.fontSize;
189
163
  }
164
+ get fontHeight() {
165
+ return this.fontSize * this.computedStyle.lineHeight;
166
+ }
190
167
  _font() {
191
168
  const font = modernFont.fonts.get(this.computedStyle.fontFamily)?.font;
192
169
  if (font instanceof modernFont.Woff || font instanceof modernFont.Ttf) {
@@ -199,25 +176,24 @@ class Character {
199
176
  return this;
200
177
  }
201
178
  const { unitsPerEm, ascender, descender, os2, post } = font;
202
- const { content, computedStyle, boundingBox } = this;
203
- const { height } = boundingBox;
179
+ const { content, computedStyle } = this;
204
180
  const { fontSize } = computedStyle;
205
181
  const rate = unitsPerEm / fontSize;
206
- const glyphWidth = font.getAdvanceWidth(content, fontSize);
207
- const glyphHeight = (ascender + Math.abs(descender)) / rate;
182
+ const advanceWidth = font.getAdvanceWidth(content, fontSize);
183
+ const advanceHeight = (ascender + Math.abs(descender)) / rate;
208
184
  const baseline = ascender / rate;
209
185
  const yStrikeoutPosition = (ascender - os2.yStrikeoutPosition) / rate;
210
186
  const yStrikeoutSize = os2.yStrikeoutSize / rate;
211
187
  const underlinePosition = (ascender - post.underlinePosition) / rate;
212
188
  const underlineThickness = post.underlineThickness / rate;
213
- this.glyphWidth = glyphWidth;
214
- this.glyphHeight = glyphHeight;
189
+ this.inlineBox.width = advanceWidth;
190
+ this.inlineBox.height = advanceHeight;
215
191
  this.underlinePosition = underlinePosition;
216
192
  this.underlineThickness = underlineThickness;
217
193
  this.yStrikeoutPosition = yStrikeoutPosition;
218
194
  this.yStrikeoutSize = yStrikeoutSize;
219
195
  this.baseline = baseline;
220
- this.centerDiviation = 0.5 * height - baseline;
196
+ this.centerDiviation = advanceHeight / 2 - baseline;
221
197
  return this;
222
198
  }
223
199
  updatePath() {
@@ -228,45 +204,39 @@ class Character {
228
204
  const {
229
205
  isVertical,
230
206
  content,
231
- textWidth,
232
- textHeight,
233
- boundingBox,
234
207
  computedStyle,
235
208
  baseline,
236
- glyphHeight,
237
- glyphWidth
209
+ inlineBox
238
210
  } = this.updateGlyph(font);
239
211
  const { os2, ascender, descender } = font;
240
- const usWinAscent = ascender;
241
- const usWinDescent = descender;
242
212
  const typoAscender = os2.sTypoAscender;
243
- const { left, top } = boundingBox;
213
+ const { left, top } = inlineBox;
244
214
  const { fontSize, fontStyle } = computedStyle;
245
215
  let x = left;
246
216
  let y = top + baseline;
247
217
  let glyphIndex;
248
218
  const path = new modernPath2d.Path2D();
249
219
  if (isVertical) {
250
- x += (glyphHeight - glyphWidth) / 2;
251
- if (Math.abs(textWidth - textHeight) > 0.1) {
252
- y -= (usWinAscent - typoAscender) / (usWinAscent + Math.abs(usWinDescent)) * glyphHeight;
220
+ x += (inlineBox.height - inlineBox.width) / 2;
221
+ if (Math.abs(inlineBox.width - inlineBox.height) > 0.1) {
222
+ y -= (ascender - typoAscender) / (ascender + Math.abs(descender)) * inlineBox.height;
253
223
  }
254
224
  glyphIndex = void 0;
255
225
  }
256
226
  if (isVertical && !set1.has(content) && (content.codePointAt(0) <= 256 || set2.has(content))) {
257
227
  path.addCommands(
258
- font.getPathCommands(content, x, top + baseline - (glyphHeight - glyphWidth) / 2, fontSize) ?? []
228
+ font.getPathCommands(content, x, top + baseline - (inlineBox.height - inlineBox.width) / 2, fontSize) ?? []
259
229
  );
260
230
  const point = {
261
- y: top - (glyphHeight - glyphWidth) / 2 + glyphHeight / 2,
262
- x: x + glyphWidth / 2
231
+ y: top - (inlineBox.height - inlineBox.width) / 2 + inlineBox.height / 2,
232
+ x: x + inlineBox.width / 2
263
233
  };
264
234
  if (fontStyle === "italic") {
265
235
  this._italic(
266
236
  path,
267
237
  isVertical ? {
268
238
  x: point.x,
269
- y: top - (glyphHeight - glyphWidth) / 2 + baseline
239
+ y: top - (inlineBox.height - inlineBox.width) / 2 + baseline
270
240
  } : void 0
271
241
  );
272
242
  }
@@ -280,8 +250,8 @@ class Character {
280
250
  this._italic(
281
251
  path,
282
252
  isVertical ? {
283
- x: x + glyphWidth / 2,
284
- y: top + typoAscender / (usWinAscent + Math.abs(usWinDescent)) * glyphHeight
253
+ x: x + inlineBox.width / 2,
254
+ y: top + typoAscender / (ascender + Math.abs(descender)) * inlineBox.height
285
255
  } : void 0
286
256
  );
287
257
  }
@@ -292,7 +262,7 @@ class Character {
292
262
  if (fontStyle === "italic") {
293
263
  this._italic(
294
264
  path,
295
- isVertical ? { x: x + glyphHeight / 2, y } : void 0
265
+ isVertical ? { x: x + inlineBox.height / 2, y } : void 0
296
266
  );
297
267
  }
298
268
  }
@@ -319,7 +289,7 @@ class Character {
319
289
  _decoration() {
320
290
  const { isVertical, underlinePosition, yStrikeoutPosition } = this;
321
291
  const { textDecoration, fontSize } = this.computedStyle;
322
- const { left, top, width, height } = this.boundingBox;
292
+ const { left, top, width, height } = this.inlineBox;
323
293
  const lineWidth = 0.1 * fontSize;
324
294
  let start;
325
295
  switch (textDecoration) {
@@ -361,8 +331,8 @@ class Character {
361
331
  }
362
332
  _italic(path, startPoint) {
363
333
  path.skew(-0.24, 0, startPoint || {
364
- y: this.boundingBox.top + this.baseline,
365
- x: this.boundingBox.left + this.glyphWidth / 2
334
+ y: this.inlineBox.top + this.baseline,
335
+ x: this.inlineBox.left + this.inlineBox.width / 2
366
336
  });
367
337
  }
368
338
  getGlyphMinMax(min, max, withStyle) {
@@ -371,9 +341,7 @@ class Character {
371
341
  } else {
372
342
  min ?? (min = modernPath2d.Vector2.MAX);
373
343
  max ?? (max = modernPath2d.Vector2.MIN);
374
- const { left, top } = this.boundingBox;
375
- const right = left + this.glyphWidth;
376
- const bottom = top + this.glyphHeight;
344
+ const { left, top, right, bottom } = this.inlineBox;
377
345
  min.x = Math.min(min.x, left);
378
346
  min.y = Math.min(min.y, top);
379
347
  max.x = Math.max(max.x, right);
@@ -422,7 +390,7 @@ class Fragment {
422
390
  this.content = content;
423
391
  this.style = style;
424
392
  this.parent = parent;
425
- __publicField$2(this, "boundingBox", new modernPath2d.BoundingBox());
393
+ __publicField$2(this, "inlineBox", new modernPath2d.BoundingBox());
426
394
  this.updateComputedStyle().initCharacters();
427
395
  }
428
396
  get computedContent() {
@@ -457,7 +425,7 @@ class Paragraph {
457
425
  constructor(style, parentStyle) {
458
426
  this.style = style;
459
427
  this.parentStyle = parentStyle;
460
- __publicField$1(this, "boundingBox", new modernPath2d.BoundingBox());
428
+ __publicField$1(this, "lineBox", new modernPath2d.BoundingBox());
461
429
  __publicField$1(this, "fragments", []);
462
430
  this.updateComputedStyle();
463
431
  }
@@ -559,7 +527,7 @@ class Measurer {
559
527
  height: pBox.height
560
528
  });
561
529
  li.querySelectorAll("span").forEach((span, fragmentIndex) => {
562
- const fBox = li.getBoundingClientRect();
530
+ const fBox = span.getBoundingClientRect();
563
531
  fragments.push({
564
532
  paragraphIndex,
565
533
  fragmentIndex,
@@ -612,64 +580,43 @@ class Measurer {
612
580
  measureDom(dom) {
613
581
  const { paragraphs } = this._text;
614
582
  const rect = dom.getBoundingClientRect();
615
- const innerEl = dom.querySelector("ul");
616
- const isVertical = window.getComputedStyle(dom).writingMode.includes("vertical");
617
- const oldLineHeight = innerEl.style.lineHeight;
618
- innerEl.style.lineHeight = "4000px";
619
- const _paragraphs = [[]];
620
- let fragments = _paragraphs[0];
621
- const { characters: oldCharacters } = this._measureDom(dom);
622
- if (oldCharacters.length > 0) {
623
- fragments.push(oldCharacters[0]);
624
- oldCharacters.reduce((prev, current) => {
625
- const attr = isVertical ? "left" : "top";
626
- if (Math.abs(current[attr] - prev[attr]) > 4e3 / 2) {
627
- fragments = [];
628
- _paragraphs.push(fragments);
629
- }
630
- fragments.push(current);
631
- return current;
632
- });
633
- }
634
- innerEl.style.lineHeight = oldLineHeight;
635
583
  const measured = this._measureDom(dom);
636
584
  measured.paragraphs.forEach((p) => {
637
585
  const _p = paragraphs[p.paragraphIndex];
638
- _p.boundingBox.left = p.left - rect.left;
639
- _p.boundingBox.top = p.top - rect.top;
640
- _p.boundingBox.width = p.width;
641
- _p.boundingBox.height = p.height;
586
+ _p.lineBox.left = p.left - rect.left;
587
+ _p.lineBox.top = p.top - rect.top;
588
+ _p.lineBox.width = p.width;
589
+ _p.lineBox.height = p.height;
642
590
  });
643
591
  measured.fragments.forEach((f) => {
644
592
  const _f = paragraphs[f.paragraphIndex].fragments[f.fragmentIndex];
645
- _f.boundingBox.left = f.left - rect.left;
646
- _f.boundingBox.top = f.top - rect.top;
647
- _f.boundingBox.width = f.width;
648
- _f.boundingBox.height = f.height;
593
+ _f.inlineBox.left = f.left - rect.left;
594
+ _f.inlineBox.top = f.top - rect.top;
595
+ _f.inlineBox.width = f.width;
596
+ _f.inlineBox.height = f.height;
649
597
  });
650
598
  const results = [];
651
599
  let i = 0;
652
- _paragraphs.forEach((oldCharacters2) => {
653
- oldCharacters2.forEach((oldCharacter) => {
654
- const character = measured.characters[i];
655
- const { paragraphIndex, fragmentIndex, characterIndex } = character;
656
- results.push({
657
- ...character,
658
- newParagraphIndex: paragraphIndex,
659
- textWidth: oldCharacter.width,
660
- textHeight: oldCharacter.height,
661
- left: character.left - rect.left,
662
- top: character.top - rect.top
663
- });
664
- const item = paragraphs[paragraphIndex].fragments[fragmentIndex].characters[characterIndex];
665
- item.boundingBox.left = results[i].left;
666
- item.boundingBox.top = results[i].top;
667
- item.boundingBox.width = results[i].width;
668
- item.boundingBox.height = results[i].height;
669
- item.textWidth = results[i].textWidth;
670
- item.textHeight = results[i].textHeight;
671
- i++;
600
+ measured.characters.forEach((character) => {
601
+ const { paragraphIndex, fragmentIndex, characterIndex } = character;
602
+ results.push({
603
+ ...character,
604
+ newParagraphIndex: paragraphIndex,
605
+ left: character.left - rect.left,
606
+ top: character.top - rect.top
672
607
  });
608
+ const item = paragraphs[paragraphIndex].fragments[fragmentIndex].characters[characterIndex];
609
+ const result = results[i];
610
+ item.inlineBox.left = result.left;
611
+ item.inlineBox.top = result.top;
612
+ item.inlineBox.width = result.width;
613
+ item.inlineBox.height = result.height;
614
+ const fontHeight = item.fontHeight;
615
+ item.lineBox.left = result.left;
616
+ item.lineBox.top = result.top + (result.height - fontHeight) / 2;
617
+ item.lineBox.height = fontHeight;
618
+ item.lineBox.width = result.width;
619
+ i++;
673
620
  });
674
621
  return {
675
622
  paragraphs,
@@ -746,82 +693,6 @@ function definePlugin(options) {
746
693
  return options;
747
694
  }
748
695
 
749
- const tempV1 = new modernPath2d.Vector2();
750
- const tempM1 = new modernPath2d.Matrix3();
751
- const tempM2 = new modernPath2d.Matrix3();
752
- function effect() {
753
- return definePlugin({
754
- name: "effect",
755
- getBoundingBox: (text) => {
756
- const { characters, fontSize, effects } = text;
757
- const boxes = [];
758
- characters.forEach((character) => {
759
- effects?.forEach((style) => {
760
- const aabb = character.glyphBox.clone();
761
- const m = getTransform2D(text, style);
762
- tempV1.set(aabb.left, aabb.top);
763
- tempV1.applyMatrix3(m);
764
- aabb.left = tempV1.x;
765
- aabb.top = tempV1.y;
766
- tempV1.set(aabb.right, aabb.bottom);
767
- tempV1.applyMatrix3(m);
768
- aabb.width = tempV1.x - aabb.left;
769
- aabb.height = tempV1.y - aabb.top;
770
- const shadowOffsetX = (style.shadowOffsetX ?? 0) * fontSize;
771
- const shadowOffsetY = (style.shadowOffsetY ?? 0) * fontSize;
772
- const textStrokeWidth = Math.max(0.1, style.textStrokeWidth ?? 0) * fontSize;
773
- aabb.left += shadowOffsetX - textStrokeWidth;
774
- aabb.top += shadowOffsetY - textStrokeWidth;
775
- aabb.width += textStrokeWidth * 2;
776
- aabb.height += textStrokeWidth * 2;
777
- boxes.push(aabb);
778
- });
779
- });
780
- return boxes.length ? modernPath2d.BoundingBox.from(...boxes) : void 0;
781
- },
782
- render: (ctx, text) => {
783
- const { characters, renderBoundingBox, effects } = text;
784
- if (effects) {
785
- effects.forEach((style) => {
786
- uploadColor(style, renderBoundingBox, ctx);
787
- ctx.save();
788
- const [a, c, e, b, d, f] = getTransform2D(text, style).transpose().elements;
789
- ctx.transform(a, b, c, d, e, f);
790
- characters.forEach((character) => {
791
- character.drawTo(ctx, style);
792
- });
793
- ctx.restore();
794
- });
795
- } else {
796
- characters.forEach((character) => {
797
- character.drawTo(ctx);
798
- });
799
- }
800
- }
801
- });
802
- }
803
- function getTransform2D(text, style) {
804
- const { fontSize, renderBoundingBox } = text;
805
- const offsetX = (style.offsetX ?? 0) * fontSize;
806
- const offsetY = (style.offsetY ?? 0) * fontSize;
807
- const PI_2 = Math.PI * 2;
808
- const skewX = (style.skewX ?? 0) / 360 * PI_2;
809
- const skewY = (style.skewY ?? 0) / 360 * PI_2;
810
- const { left, top, width, height } = renderBoundingBox;
811
- const centerX = left + width / 2;
812
- const centerY = top + height / 2;
813
- tempM1.identity();
814
- tempM2.makeTranslation(offsetX, offsetY);
815
- tempM1.multiply(tempM2);
816
- tempM2.makeTranslation(centerX, centerY);
817
- tempM1.multiply(tempM2);
818
- tempM2.set(1, Math.tan(skewX), 0, Math.tan(skewY), 1, 0, 0, 0, 1);
819
- tempM1.multiply(tempM2);
820
- tempM2.makeTranslation(-centerX, -centerY);
821
- tempM1.multiply(tempM2);
822
- return tempM1.clone();
823
- }
824
-
825
696
  const defaultReferImage = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MiIgaGVpZ2h0PSI3MiIgdmlld0JveD0iMCAwIDcyIDcyIiBmaWxsPSJub25lIj48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTMyLjQwMjkgMjhIMzUuMTU5NFYzMy4xNzcxQzM1Ljk4MjEgMzIuMzExNSAzNi45NzEgMzEuODczNyAzOC4wOTQ4IDMxLjg3MzdDMzkuNjY3NiAzMS44NzM3IDQwLjkxNjYgMzIuNDI5NSA0MS44MzkgMzMuNTQzN0w0MS44NDAzIDMzLjU0NTNDNDIuNjcxNyAzNC41NzA1IDQzLjA5MTUgMzUuODU1OSA0My4wOTE1IDM3LjM4NzdDNDMuMDkxNSAzOC45NzYxIDQyLjY3MjkgNDAuMzAyOCA0MS44MTgzIDQxLjMzMDRMNDEuODE3MSA0MS4zMzE4QzQwLjg3MzEgNDIuNDQ2MSAzOS41ODMyIDQzIDM3Ljk3MjEgNDNDMzYuNzQ3NyA0MyAzNS43NDg4IDQyLjY1OTkgMzQuOTk1OCA0MS45NjkzVjQyLjcyNDdIMzIuNDAyOVYyOFpNMzcuNTQyOCAzNC4wOTI0QzM2Ljg1NDkgMzQuMDkyNCAzNi4zMDE0IDM0LjM1NjEgMzUuODQ4NyAzNC45MDA0TDM1Ljg0NTIgMzQuOTA0NkMzNS4zMzU4IDM1LjQ4NTMgMzUuMDc3NiAzNi4yOTc2IDM1LjA3NzYgMzcuMzQ4NFYzNy41MDU3QzM1LjA3NzYgMzguNDY0IDM1LjI3NzIgMzkuMjQ0MyAzNS42OTQzIDM5LjgyNzlDMzYuMTQ0MSA0MC40NTg3IDM2Ljc3MjYgNDAuNzgxMyAzNy42MjQ1IDQwLjc4MTNDMzguNTg3NCA0MC43ODEzIDM5LjI3MDcgNDAuNDUyNyAzOS43MTUyIDM5LjgxMjdDNDAuMDcyOCAzOS4yNjg0IDQwLjI3MzcgMzguNDY3MyA0MC4yNzM3IDM3LjM4NzdDNDAuMjczNyAzNi4zMTA1IDQwLjA1MzMgMzUuNTMxMyAzOS42NzgzIDM1LjAwNzdDMzkuMjM3MSAzNC40MDcxIDM4LjUzNDIgMzQuMDkyNCAzNy41NDI4IDM0LjA5MjRaIiBmaWxsPSIjMjIyNTI5Ii8+PHBhdGggZD0iTTQ5Ljg2MTQgMzEuODczN0M0OC4xNTM1IDMxLjg3MzcgNDYuODAxNiAzMi40MjM5IDQ1LjgzNDggMzMuNTM5MkM0NC45MzcgMzQuNTQ3MiA0NC40OTY2IDM1Ljg1NiA0NC40OTY2IDM3LjQyN0M0NC40OTY2IDM5LjAzNjggNDQuOTM2NyA0MC4zNjU5IDQ1Ljg1NTkgNDEuMzk0M0M0Ni44MDMxIDQyLjQ3MDYgNDguMTM0OCA0MyA0OS44MjA1IDQzQzUxLjIyNiA0MyA1Mi4zODI2IDQyLjY1NjMgNTMuMjQ3OSA0MS45Njk3QzU0LjEzNTkgNDEuMjYxNCA1NC43MDYxIDQwLjE4ODcgNTQuOTU3MyAzOC43NzkxTDU1IDM4LjUzOTdINTIuMjQ4NEw1Mi4yMjU5IDM4LjcyMDFDNTIuMTM3OSAzOS40MjUxIDUxLjg5MjUgMzkuOTI3OCA1MS41MTA5IDQwLjI1NThDNTEuMTI5NSA0MC41ODM1IDUwLjU4MzEgNDAuNzYxNiA0OS44NDA5IDQwLjc2MTZDNDkuMDAwMSA0MC43NjE2IDQ4LjM5NDkgNDAuNDcxNSA0Ny45OTA3IDM5LjkyMzdMNDcuOTg3NCAzOS45MTk0QzQ3LjUzNTYgMzkuMzQwMSA0Ny4zMTQ0IDM4LjUwNjIgNDcuMzE0NCAzNy40MDc0QzQ3LjMxNDQgMzYuMzMyMiA0Ny41NTQ0IDM1LjUxNzcgNDguMDA1OCAzNC45NTY4TDQ4LjAwNzggMzQuOTU0M0M0OC40NTM3IDM0LjM4MjUgNDkuMDYxOCAzNC4xMTIxIDQ5Ljg2MTQgMzQuMTEyMUM1MC41MjMgMzQuMTEyMSA1MS4wNDUxIDM0LjI2MTUgNTEuNDI3MiAzNC41NDA3QzUxLjc4ODQgMzQuODE5NCA1Mi4wNTMgMzUuMjQ0NyA1Mi4xODgxIDM1Ljg1NzFMNTIuMjIzOSAzNi4wMTk0SDU0Ljk1NDhMNTQuOTE3IDM1Ljc4MzVDNTQuNzA2MyAzNC40NjYgNTQuMTUzNiAzMy40NzAxIDUzLjI2MzQgMzIuODAxOUw1My4yNjAyIDMyLjc5OTVDNTIuMzk1MSAzMi4xNzU1IDUxLjI2MjEgMzEuODczNyA0OS44NjE0IDMxLjg3MzdaIiBmaWxsPSIjMjIyNTI5Ii8+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yNS43NTYxIDI4LjI3NTNIMjIuNzQ0TDE3IDQyLjcyNDdIMjAuMDE0MUwyMS4zNDI5IDM5LjIwNDlIMjcuMTU3MkwyOC40ODYgNDIuNzI0N0gzMS41MDAxTDI1Ljc1NjEgMjguMjc1M1pNMjIuMjEyNSAzNi45MDc2TDI0LjI1OTYgMzEuNDUzOUwyNi4yODg1IDM2LjkwNzZIMjIuMjEyNVoiIGZpbGw9IiMyMjI1MjkiLz48L3N2Zz4=";
826
697
  function parseCharsPerRepeat(size, fontSize, total) {
827
698
  if (size === "cover") {
@@ -855,22 +726,22 @@ function parseStrokeWidthScale(strokeWidth, fontSize, total) {
855
726
  }
856
727
  function getTransformMatrix(a, b, c, isVertical) {
857
728
  let scale;
858
- if (isVertical) {
729
+ if (!isVertical) {
859
730
  scale = {
860
- x: c.width / b.height,
861
- y: c.height / b.width
731
+ x: c.width / b.width,
732
+ y: c.height / b.height
862
733
  };
863
734
  } else {
864
735
  scale = {
865
- x: c.width / b.width,
866
- y: c.height / b.height
736
+ x: c.width / b.height,
737
+ y: c.height / b.width
867
738
  };
868
739
  }
869
740
  const offset = c.getCenterPoint().add(
870
741
  a.getCenterPoint().sub(b.getCenterPoint()).scale(scale.x, scale.y)
871
742
  ).sub({
872
- x: a.width * scale.x / 2,
873
- y: a.height * scale.y / 2
743
+ x: a.width / 2 * scale.x,
744
+ y: a.height / 2 * scale.y
874
745
  });
875
746
  const m = new modernPath2d.Matrix3();
876
747
  m.translate(-a.left, -a.top);
@@ -907,7 +778,7 @@ function highlight() {
907
778
  characters.forEach((character) => {
908
779
  const { isVertical, computedStyle: style } = character;
909
780
  if (!isNone(style.highlightImage)) {
910
- if (style.highlightSize !== "1rem" && prevStyle?.highlightImage === style.highlightImage && prevStyle?.highlightSize === style.highlightSize && prevStyle?.highlightStrokeWidth === style.highlightStrokeWidth && prevStyle?.highlightOverflow === style.highlightOverflow && group.length && (isVertical ? group[0].boundingBox.left === character.boundingBox.left : group[0].boundingBox.top === character.boundingBox.top) && group[0].fontSize === character.fontSize) {
781
+ if (style.highlightSize !== "1rem" && prevStyle?.highlightImage === style.highlightImage && prevStyle?.highlightSize === style.highlightSize && prevStyle?.highlightStrokeWidth === style.highlightStrokeWidth && prevStyle?.highlightOverflow === style.highlightOverflow && group.length && (isVertical ? group[0].inlineBox.left === character.inlineBox.left : group[0].inlineBox.top === character.inlineBox.top) && group[0].fontSize === character.fontSize) {
911
782
  group.push(character);
912
783
  } else {
913
784
  group = [];
@@ -918,12 +789,14 @@ function highlight() {
918
789
  prevStyle = style;
919
790
  });
920
791
  groups.filter((characters2) => characters2.length).map((characters2) => {
792
+ const char = characters2[0];
921
793
  return {
922
- style: characters2[0].computedStyle,
794
+ style: char.computedStyle,
795
+ baseline: char.baseline,
923
796
  box: modernPath2d.BoundingBox.from(...characters2.map((c) => c.glyphBox))
924
797
  };
925
798
  }).forEach((group2) => {
926
- const { style, box: groupBox } = group2;
799
+ const { style, box: groupBox, baseline } = group2;
927
800
  const { fontSize, writingMode } = style;
928
801
  const isVertical = writingMode.includes("vertical");
929
802
  const strokeWidthScale = parseStrokeWidthScale(style.highlightStrokeWidth, fontSize, groupBox.width);
@@ -933,11 +806,12 @@ function highlight() {
933
806
  const svgPaths = getPaths(style.highlightImage);
934
807
  const box = modernPath2d.getPathsBoundingBox(svgPaths, true);
935
808
  const refBox = modernPath2d.getPathsBoundingBox(refPaths, false);
936
- const unitWidth = charsPerRepeat ? fontSize * charsPerRepeat : groupBox.width;
809
+ const unitWidth = charsPerRepeat ? fontSize * charsPerRepeat : isVertical ? groupBox.height : groupBox.width;
810
+ const unitHeight = baseline * 0.8;
937
811
  const transform = getTransformMatrix(
938
812
  box,
939
813
  refBox,
940
- new modernPath2d.BoundingBox(groupBox.left, groupBox.top, unitWidth, groupBox.height),
814
+ new modernPath2d.BoundingBox(groupBox.left, groupBox.top, isVertical ? unitHeight : unitWidth, isVertical ? unitWidth : unitHeight),
941
815
  isVertical
942
816
  );
943
817
  const styleScale = fontSize / box.width * 2;
@@ -1056,6 +930,104 @@ function listStyle() {
1056
930
  });
1057
931
  }
1058
932
 
933
+ const tempV1 = new modernPath2d.Vector2();
934
+ const tempM1 = new modernPath2d.Matrix3();
935
+ const tempM2 = new modernPath2d.Matrix3();
936
+ function render() {
937
+ return definePlugin({
938
+ name: "render",
939
+ getBoundingBox: (text) => {
940
+ const { characters, fontSize, effects } = text;
941
+ const boxes = [];
942
+ characters.forEach((character) => {
943
+ effects?.forEach((style) => {
944
+ const aabb = character.glyphBox.clone();
945
+ const m = getTransform2D(text, style);
946
+ tempV1.set(aabb.left, aabb.top);
947
+ tempV1.applyMatrix3(m);
948
+ aabb.left = tempV1.x;
949
+ aabb.top = tempV1.y;
950
+ tempV1.set(aabb.right, aabb.bottom);
951
+ tempV1.applyMatrix3(m);
952
+ aabb.width = tempV1.x - aabb.left;
953
+ aabb.height = tempV1.y - aabb.top;
954
+ const shadowOffsetX = (style.shadowOffsetX ?? 0) * fontSize;
955
+ const shadowOffsetY = (style.shadowOffsetY ?? 0) * fontSize;
956
+ const textStrokeWidth = Math.max(0.1, style.textStrokeWidth ?? 0) * fontSize;
957
+ aabb.left += shadowOffsetX - textStrokeWidth;
958
+ aabb.top += shadowOffsetY - textStrokeWidth;
959
+ aabb.width += textStrokeWidth * 2;
960
+ aabb.height += textStrokeWidth * 2;
961
+ boxes.push(aabb);
962
+ });
963
+ });
964
+ return boxes.length ? modernPath2d.BoundingBox.from(...boxes) : void 0;
965
+ },
966
+ render: (ctx, text) => {
967
+ const { characters, paragraphs, renderBoundingBox, effects, style } = text;
968
+ function fillBackground(color, box) {
969
+ ctx.fillStyle = color;
970
+ ctx.fillRect(box.left, box.top, box.width, box.height);
971
+ }
972
+ if (style?.backgroundColor) {
973
+ fillBackground(style.backgroundColor, new modernPath2d.BoundingBox(0, 0, ctx.canvas.width, ctx.canvas.height));
974
+ }
975
+ paragraphs.forEach((paragraph) => {
976
+ if (paragraph.style?.backgroundColor) {
977
+ fillBackground(paragraph.style.backgroundColor, paragraph.lineBox);
978
+ }
979
+ });
980
+ if (effects) {
981
+ effects.forEach((style2) => {
982
+ uploadColor(style2, renderBoundingBox, ctx);
983
+ ctx.save();
984
+ const [a, c, e, b, d, f] = getTransform2D(text, style2).transpose().elements;
985
+ ctx.transform(a, b, c, d, e, f);
986
+ characters.forEach((character) => {
987
+ if (character.parent.style?.backgroundColor) {
988
+ fillBackground(character.parent.style.backgroundColor, character.inlineBox);
989
+ }
990
+ character.drawTo(ctx, style2);
991
+ });
992
+ ctx.restore();
993
+ });
994
+ } else {
995
+ paragraphs.forEach((paragraph) => {
996
+ paragraph.fragments.forEach((fragment) => {
997
+ if (fragment.style?.backgroundColor) {
998
+ fillBackground(fragment.computedStyle.backgroundColor, fragment.inlineBox);
999
+ }
1000
+ fragment.characters.forEach((character) => {
1001
+ character.drawTo(ctx);
1002
+ });
1003
+ });
1004
+ });
1005
+ }
1006
+ }
1007
+ });
1008
+ }
1009
+ function getTransform2D(text, style) {
1010
+ const { fontSize, renderBoundingBox } = text;
1011
+ const offsetX = (style.offsetX ?? 0) * fontSize;
1012
+ const offsetY = (style.offsetY ?? 0) * fontSize;
1013
+ const PI_2 = Math.PI * 2;
1014
+ const skewX = (style.skewX ?? 0) / 360 * PI_2;
1015
+ const skewY = (style.skewY ?? 0) / 360 * PI_2;
1016
+ const { left, top, width, height } = renderBoundingBox;
1017
+ const centerX = left + width / 2;
1018
+ const centerY = top + height / 2;
1019
+ tempM1.identity();
1020
+ tempM2.makeTranslation(offsetX, offsetY);
1021
+ tempM1.multiply(tempM2);
1022
+ tempM2.makeTranslation(centerX, centerY);
1023
+ tempM1.multiply(tempM2);
1024
+ tempM2.set(1, Math.tan(skewX), 0, Math.tan(skewY), 1, 0, 0, 0, 1);
1025
+ tempM1.multiply(tempM2);
1026
+ tempM2.makeTranslation(-centerX, -centerY);
1027
+ tempM1.multiply(tempM2);
1028
+ return tempM1.clone();
1029
+ }
1030
+
1059
1031
  var __defProp = Object.defineProperty;
1060
1032
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1061
1033
  var __publicField = (obj, key, value) => {
@@ -1122,7 +1094,7 @@ class Text {
1122
1094
  this.style = style;
1123
1095
  this.measureDom = measureDom;
1124
1096
  this.effects = effects;
1125
- this.use(effect()).use(highlight()).use(listStyle());
1097
+ this.use(render()).use(highlight()).use(listStyle());
1126
1098
  }
1127
1099
  get fontSize() {
1128
1100
  return this.computedStyle.fontSize;
@@ -1212,14 +1184,13 @@ exports.Text = Text;
1212
1184
  exports.defaultTextStyles = defaultTextStyles;
1213
1185
  exports.definePlugin = definePlugin;
1214
1186
  exports.drawPath = drawPath;
1215
- exports.effect = effect;
1216
- exports.fillBackground = fillBackground;
1217
1187
  exports.filterEmpty = filterEmpty;
1218
1188
  exports.getTransform2D = getTransform2D;
1219
1189
  exports.highlight = highlight;
1220
1190
  exports.isNone = isNone;
1221
1191
  exports.listStyle = listStyle;
1222
1192
  exports.parseColor = parseColor;
1193
+ exports.render = render;
1223
1194
  exports.setupView = setupView;
1224
1195
  exports.uploadColor = uploadColor;
1225
1196
  exports.uploadColors = uploadColors;