@shotstack/shotstack-canvas 1.3.8 → 1.3.9
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/entry.node.cjs +64 -8
- package/dist/entry.node.d.cts +5 -0
- package/dist/entry.node.d.ts +5 -0
- package/dist/entry.node.js +64 -8
- package/dist/entry.web.d.ts +5 -0
- package/dist/entry.web.js +64 -8
- package/package.json +1 -1
package/dist/entry.node.cjs
CHANGED
|
@@ -370,10 +370,14 @@ var FontRegistry = class _FontRegistry {
|
|
|
370
370
|
fontkitFonts = /* @__PURE__ */ new Map();
|
|
371
371
|
wasmBaseURL;
|
|
372
372
|
initPromise;
|
|
373
|
+
emojiFallbackDesc;
|
|
373
374
|
static fallbackLoader;
|
|
374
375
|
static setFallbackLoader(loader) {
|
|
375
376
|
_FontRegistry.fallbackLoader = loader;
|
|
376
377
|
}
|
|
378
|
+
setEmojiFallback(desc) {
|
|
379
|
+
this.emojiFallbackDesc = desc;
|
|
380
|
+
}
|
|
377
381
|
constructor(wasmBaseURL) {
|
|
378
382
|
this.wasmBaseURL = wasmBaseURL;
|
|
379
383
|
}
|
|
@@ -531,7 +535,8 @@ var FontRegistry = class _FontRegistry {
|
|
|
531
535
|
if (fkFont) {
|
|
532
536
|
const glyph = fkFont.getGlyph(glyphId);
|
|
533
537
|
if (glyph && glyph.path) {
|
|
534
|
-
|
|
538
|
+
const path2 = glyph.path.toSVG();
|
|
539
|
+
return path2 && path2 !== "" ? path2 : "M 0 0";
|
|
535
540
|
}
|
|
536
541
|
}
|
|
537
542
|
const font = await this.getFont(desc);
|
|
@@ -587,6 +592,18 @@ var FontRegistry = class _FontRegistry {
|
|
|
587
592
|
};
|
|
588
593
|
|
|
589
594
|
// src/core/layout.ts
|
|
595
|
+
function isEmoji(char) {
|
|
596
|
+
const code = char.codePointAt(0);
|
|
597
|
+
if (!code) return false;
|
|
598
|
+
return code >= 127744 && code <= 129535 || // Emoticons, symbols, pictographs
|
|
599
|
+
code >= 9728 && code <= 9983 || // Miscellaneous symbols
|
|
600
|
+
code >= 9984 && code <= 10175 || // Dingbats
|
|
601
|
+
code >= 65024 && code <= 65039 || // Variation selectors
|
|
602
|
+
code >= 128512 && code <= 128591 || // Emoticons
|
|
603
|
+
code >= 128640 && code <= 128767 || // Transport and map symbols
|
|
604
|
+
code >= 129280 && code <= 129535 || // Supplemental symbols and pictographs
|
|
605
|
+
code >= 129648 && code <= 129791;
|
|
606
|
+
}
|
|
590
607
|
var LayoutEngine = class {
|
|
591
608
|
constructor(fonts) {
|
|
592
609
|
this.fonts = fonts;
|
|
@@ -634,14 +651,43 @@ var LayoutEngine = class {
|
|
|
634
651
|
}
|
|
635
652
|
async layout(params) {
|
|
636
653
|
try {
|
|
637
|
-
const { textTransform, desc, fontSize, letterSpacing, width } = params;
|
|
654
|
+
const { textTransform, desc, fontSize, letterSpacing, width, emojiFallback } = params;
|
|
638
655
|
const input = this.transformText(params.text, textTransform);
|
|
639
656
|
if (!input || input.length === 0) {
|
|
640
657
|
return [];
|
|
641
658
|
}
|
|
642
659
|
let shaped;
|
|
643
660
|
try {
|
|
644
|
-
|
|
661
|
+
if (!emojiFallback) {
|
|
662
|
+
shaped = await this.shapeFull(input, desc);
|
|
663
|
+
} else {
|
|
664
|
+
const chars = Array.from(input);
|
|
665
|
+
const runs = [];
|
|
666
|
+
let currentRun = { text: "", startIndex: 0, isEmoji: false };
|
|
667
|
+
for (let i = 0; i < chars.length; i++) {
|
|
668
|
+
const char = chars[i];
|
|
669
|
+
const charIsEmoji = isEmoji(char);
|
|
670
|
+
if (i === 0) {
|
|
671
|
+
currentRun = { text: char, startIndex: 0, isEmoji: charIsEmoji };
|
|
672
|
+
} else if (currentRun.isEmoji === charIsEmoji) {
|
|
673
|
+
currentRun.text += char;
|
|
674
|
+
} else {
|
|
675
|
+
runs.push(currentRun);
|
|
676
|
+
currentRun = { text: char, startIndex: currentRun.startIndex + currentRun.text.length, isEmoji: charIsEmoji };
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
if (currentRun.text) runs.push(currentRun);
|
|
680
|
+
shaped = [];
|
|
681
|
+
for (const run of runs) {
|
|
682
|
+
const runFont = run.isEmoji ? emojiFallback : desc;
|
|
683
|
+
const runShaped = await this.shapeFull(run.text, runFont);
|
|
684
|
+
for (const glyph of runShaped) {
|
|
685
|
+
glyph.cl += run.startIndex;
|
|
686
|
+
glyph.fontDesc = runFont;
|
|
687
|
+
}
|
|
688
|
+
shaped.push(...runShaped);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
645
691
|
} catch (err) {
|
|
646
692
|
throw new Error(`Text shaping failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
647
693
|
}
|
|
@@ -667,7 +713,9 @@ var LayoutEngine = class {
|
|
|
667
713
|
xOffset: g.dx * scale,
|
|
668
714
|
yOffset: -g.dy * scale,
|
|
669
715
|
cluster: g.cl,
|
|
670
|
-
char
|
|
716
|
+
char,
|
|
717
|
+
fontDesc: g.fontDesc
|
|
718
|
+
// Preserve font descriptor
|
|
671
719
|
};
|
|
672
720
|
});
|
|
673
721
|
const lines = [];
|
|
@@ -815,7 +863,7 @@ async function buildDrawOps(p) {
|
|
|
815
863
|
const lineIndex = p.lines.indexOf(line);
|
|
816
864
|
const baselineY = blockY + lineIndex * lineHeightPx;
|
|
817
865
|
for (const glyph of line.glyphs) {
|
|
818
|
-
const path = await p.glyphPathProvider(glyph.id);
|
|
866
|
+
const path = await p.glyphPathProvider(glyph.id, glyph.fontDesc);
|
|
819
867
|
if (!path || path === "M 0 0") {
|
|
820
868
|
xCursor += glyph.xAdvance;
|
|
821
869
|
continue;
|
|
@@ -2079,6 +2127,13 @@ async function createTextEngine(opts = {}) {
|
|
|
2079
2127
|
const desc = { family: main.family, weight: `${main.weight}`, style: main.style };
|
|
2080
2128
|
let lines;
|
|
2081
2129
|
try {
|
|
2130
|
+
const emojiDesc = { family: "NotoEmoji", weight: "400", style: "normal" };
|
|
2131
|
+
let emojiAvailable = false;
|
|
2132
|
+
try {
|
|
2133
|
+
await fonts.getFace(emojiDesc);
|
|
2134
|
+
emojiAvailable = true;
|
|
2135
|
+
} catch {
|
|
2136
|
+
}
|
|
2082
2137
|
lines = await layout.layout({
|
|
2083
2138
|
text: asset.text,
|
|
2084
2139
|
width: asset.width ?? width,
|
|
@@ -2086,7 +2141,8 @@ async function createTextEngine(opts = {}) {
|
|
|
2086
2141
|
fontSize: main.size,
|
|
2087
2142
|
lineHeight: asset.style?.lineHeight ?? 1.2,
|
|
2088
2143
|
desc,
|
|
2089
|
-
textTransform: asset.style?.textTransform ?? "none"
|
|
2144
|
+
textTransform: asset.style?.textTransform ?? "none",
|
|
2145
|
+
emojiFallback: emojiAvailable ? emojiDesc : void 0
|
|
2090
2146
|
});
|
|
2091
2147
|
} catch (err) {
|
|
2092
2148
|
throw new Error(
|
|
@@ -2128,8 +2184,8 @@ async function createTextEngine(opts = {}) {
|
|
|
2128
2184
|
vertical: asset.align?.vertical ?? "middle"
|
|
2129
2185
|
},
|
|
2130
2186
|
background: asset.background,
|
|
2131
|
-
glyphPathProvider: (gid) => fonts.glyphPath(desc, gid),
|
|
2132
|
-
getUnitsPerEm: () => fonts.getUnitsPerEm(desc)
|
|
2187
|
+
glyphPathProvider: (gid, fontDesc) => fonts.glyphPath(fontDesc || desc, gid),
|
|
2188
|
+
getUnitsPerEm: (fontDesc) => fonts.getUnitsPerEm(fontDesc || desc)
|
|
2133
2189
|
});
|
|
2134
2190
|
} catch (err) {
|
|
2135
2191
|
throw new Error(
|
package/dist/entry.node.d.cts
CHANGED
package/dist/entry.node.d.ts
CHANGED
package/dist/entry.node.js
CHANGED
|
@@ -331,10 +331,14 @@ var FontRegistry = class _FontRegistry {
|
|
|
331
331
|
fontkitFonts = /* @__PURE__ */ new Map();
|
|
332
332
|
wasmBaseURL;
|
|
333
333
|
initPromise;
|
|
334
|
+
emojiFallbackDesc;
|
|
334
335
|
static fallbackLoader;
|
|
335
336
|
static setFallbackLoader(loader) {
|
|
336
337
|
_FontRegistry.fallbackLoader = loader;
|
|
337
338
|
}
|
|
339
|
+
setEmojiFallback(desc) {
|
|
340
|
+
this.emojiFallbackDesc = desc;
|
|
341
|
+
}
|
|
338
342
|
constructor(wasmBaseURL) {
|
|
339
343
|
this.wasmBaseURL = wasmBaseURL;
|
|
340
344
|
}
|
|
@@ -492,7 +496,8 @@ var FontRegistry = class _FontRegistry {
|
|
|
492
496
|
if (fkFont) {
|
|
493
497
|
const glyph = fkFont.getGlyph(glyphId);
|
|
494
498
|
if (glyph && glyph.path) {
|
|
495
|
-
|
|
499
|
+
const path2 = glyph.path.toSVG();
|
|
500
|
+
return path2 && path2 !== "" ? path2 : "M 0 0";
|
|
496
501
|
}
|
|
497
502
|
}
|
|
498
503
|
const font = await this.getFont(desc);
|
|
@@ -548,6 +553,18 @@ var FontRegistry = class _FontRegistry {
|
|
|
548
553
|
};
|
|
549
554
|
|
|
550
555
|
// src/core/layout.ts
|
|
556
|
+
function isEmoji(char) {
|
|
557
|
+
const code = char.codePointAt(0);
|
|
558
|
+
if (!code) return false;
|
|
559
|
+
return code >= 127744 && code <= 129535 || // Emoticons, symbols, pictographs
|
|
560
|
+
code >= 9728 && code <= 9983 || // Miscellaneous symbols
|
|
561
|
+
code >= 9984 && code <= 10175 || // Dingbats
|
|
562
|
+
code >= 65024 && code <= 65039 || // Variation selectors
|
|
563
|
+
code >= 128512 && code <= 128591 || // Emoticons
|
|
564
|
+
code >= 128640 && code <= 128767 || // Transport and map symbols
|
|
565
|
+
code >= 129280 && code <= 129535 || // Supplemental symbols and pictographs
|
|
566
|
+
code >= 129648 && code <= 129791;
|
|
567
|
+
}
|
|
551
568
|
var LayoutEngine = class {
|
|
552
569
|
constructor(fonts) {
|
|
553
570
|
this.fonts = fonts;
|
|
@@ -595,14 +612,43 @@ var LayoutEngine = class {
|
|
|
595
612
|
}
|
|
596
613
|
async layout(params) {
|
|
597
614
|
try {
|
|
598
|
-
const { textTransform, desc, fontSize, letterSpacing, width } = params;
|
|
615
|
+
const { textTransform, desc, fontSize, letterSpacing, width, emojiFallback } = params;
|
|
599
616
|
const input = this.transformText(params.text, textTransform);
|
|
600
617
|
if (!input || input.length === 0) {
|
|
601
618
|
return [];
|
|
602
619
|
}
|
|
603
620
|
let shaped;
|
|
604
621
|
try {
|
|
605
|
-
|
|
622
|
+
if (!emojiFallback) {
|
|
623
|
+
shaped = await this.shapeFull(input, desc);
|
|
624
|
+
} else {
|
|
625
|
+
const chars = Array.from(input);
|
|
626
|
+
const runs = [];
|
|
627
|
+
let currentRun = { text: "", startIndex: 0, isEmoji: false };
|
|
628
|
+
for (let i = 0; i < chars.length; i++) {
|
|
629
|
+
const char = chars[i];
|
|
630
|
+
const charIsEmoji = isEmoji(char);
|
|
631
|
+
if (i === 0) {
|
|
632
|
+
currentRun = { text: char, startIndex: 0, isEmoji: charIsEmoji };
|
|
633
|
+
} else if (currentRun.isEmoji === charIsEmoji) {
|
|
634
|
+
currentRun.text += char;
|
|
635
|
+
} else {
|
|
636
|
+
runs.push(currentRun);
|
|
637
|
+
currentRun = { text: char, startIndex: currentRun.startIndex + currentRun.text.length, isEmoji: charIsEmoji };
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
if (currentRun.text) runs.push(currentRun);
|
|
641
|
+
shaped = [];
|
|
642
|
+
for (const run of runs) {
|
|
643
|
+
const runFont = run.isEmoji ? emojiFallback : desc;
|
|
644
|
+
const runShaped = await this.shapeFull(run.text, runFont);
|
|
645
|
+
for (const glyph of runShaped) {
|
|
646
|
+
glyph.cl += run.startIndex;
|
|
647
|
+
glyph.fontDesc = runFont;
|
|
648
|
+
}
|
|
649
|
+
shaped.push(...runShaped);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
606
652
|
} catch (err) {
|
|
607
653
|
throw new Error(`Text shaping failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
608
654
|
}
|
|
@@ -628,7 +674,9 @@ var LayoutEngine = class {
|
|
|
628
674
|
xOffset: g.dx * scale,
|
|
629
675
|
yOffset: -g.dy * scale,
|
|
630
676
|
cluster: g.cl,
|
|
631
|
-
char
|
|
677
|
+
char,
|
|
678
|
+
fontDesc: g.fontDesc
|
|
679
|
+
// Preserve font descriptor
|
|
632
680
|
};
|
|
633
681
|
});
|
|
634
682
|
const lines = [];
|
|
@@ -776,7 +824,7 @@ async function buildDrawOps(p) {
|
|
|
776
824
|
const lineIndex = p.lines.indexOf(line);
|
|
777
825
|
const baselineY = blockY + lineIndex * lineHeightPx;
|
|
778
826
|
for (const glyph of line.glyphs) {
|
|
779
|
-
const path = await p.glyphPathProvider(glyph.id);
|
|
827
|
+
const path = await p.glyphPathProvider(glyph.id, glyph.fontDesc);
|
|
780
828
|
if (!path || path === "M 0 0") {
|
|
781
829
|
xCursor += glyph.xAdvance;
|
|
782
830
|
continue;
|
|
@@ -2040,6 +2088,13 @@ async function createTextEngine(opts = {}) {
|
|
|
2040
2088
|
const desc = { family: main.family, weight: `${main.weight}`, style: main.style };
|
|
2041
2089
|
let lines;
|
|
2042
2090
|
try {
|
|
2091
|
+
const emojiDesc = { family: "NotoEmoji", weight: "400", style: "normal" };
|
|
2092
|
+
let emojiAvailable = false;
|
|
2093
|
+
try {
|
|
2094
|
+
await fonts.getFace(emojiDesc);
|
|
2095
|
+
emojiAvailable = true;
|
|
2096
|
+
} catch {
|
|
2097
|
+
}
|
|
2043
2098
|
lines = await layout.layout({
|
|
2044
2099
|
text: asset.text,
|
|
2045
2100
|
width: asset.width ?? width,
|
|
@@ -2047,7 +2102,8 @@ async function createTextEngine(opts = {}) {
|
|
|
2047
2102
|
fontSize: main.size,
|
|
2048
2103
|
lineHeight: asset.style?.lineHeight ?? 1.2,
|
|
2049
2104
|
desc,
|
|
2050
|
-
textTransform: asset.style?.textTransform ?? "none"
|
|
2105
|
+
textTransform: asset.style?.textTransform ?? "none",
|
|
2106
|
+
emojiFallback: emojiAvailable ? emojiDesc : void 0
|
|
2051
2107
|
});
|
|
2052
2108
|
} catch (err) {
|
|
2053
2109
|
throw new Error(
|
|
@@ -2089,8 +2145,8 @@ async function createTextEngine(opts = {}) {
|
|
|
2089
2145
|
vertical: asset.align?.vertical ?? "middle"
|
|
2090
2146
|
},
|
|
2091
2147
|
background: asset.background,
|
|
2092
|
-
glyphPathProvider: (gid) => fonts.glyphPath(desc, gid),
|
|
2093
|
-
getUnitsPerEm: () => fonts.getUnitsPerEm(desc)
|
|
2148
|
+
glyphPathProvider: (gid, fontDesc) => fonts.glyphPath(fontDesc || desc, gid),
|
|
2149
|
+
getUnitsPerEm: (fontDesc) => fonts.getUnitsPerEm(fontDesc || desc)
|
|
2094
2150
|
});
|
|
2095
2151
|
} catch (err) {
|
|
2096
2152
|
throw new Error(
|
package/dist/entry.web.d.ts
CHANGED
package/dist/entry.web.js
CHANGED
|
@@ -336,11 +336,15 @@ var _FontRegistry = class _FontRegistry {
|
|
|
336
336
|
__publicField(this, "fontkitFonts", /* @__PURE__ */ new Map());
|
|
337
337
|
__publicField(this, "wasmBaseURL");
|
|
338
338
|
__publicField(this, "initPromise");
|
|
339
|
+
__publicField(this, "emojiFallbackDesc");
|
|
339
340
|
this.wasmBaseURL = wasmBaseURL;
|
|
340
341
|
}
|
|
341
342
|
static setFallbackLoader(loader) {
|
|
342
343
|
_FontRegistry.fallbackLoader = loader;
|
|
343
344
|
}
|
|
345
|
+
setEmojiFallback(desc) {
|
|
346
|
+
this.emojiFallbackDesc = desc;
|
|
347
|
+
}
|
|
344
348
|
async init() {
|
|
345
349
|
if (this.initPromise) {
|
|
346
350
|
await this.initPromise;
|
|
@@ -495,7 +499,8 @@ var _FontRegistry = class _FontRegistry {
|
|
|
495
499
|
if (fkFont) {
|
|
496
500
|
const glyph = fkFont.getGlyph(glyphId);
|
|
497
501
|
if (glyph && glyph.path) {
|
|
498
|
-
|
|
502
|
+
const path2 = glyph.path.toSVG();
|
|
503
|
+
return path2 && path2 !== "" ? path2 : "M 0 0";
|
|
499
504
|
}
|
|
500
505
|
}
|
|
501
506
|
const font = await this.getFont(desc);
|
|
@@ -553,6 +558,18 @@ __publicField(_FontRegistry, "fallbackLoader");
|
|
|
553
558
|
var FontRegistry = _FontRegistry;
|
|
554
559
|
|
|
555
560
|
// src/core/layout.ts
|
|
561
|
+
function isEmoji(char) {
|
|
562
|
+
const code = char.codePointAt(0);
|
|
563
|
+
if (!code) return false;
|
|
564
|
+
return code >= 127744 && code <= 129535 || // Emoticons, symbols, pictographs
|
|
565
|
+
code >= 9728 && code <= 9983 || // Miscellaneous symbols
|
|
566
|
+
code >= 9984 && code <= 10175 || // Dingbats
|
|
567
|
+
code >= 65024 && code <= 65039 || // Variation selectors
|
|
568
|
+
code >= 128512 && code <= 128591 || // Emoticons
|
|
569
|
+
code >= 128640 && code <= 128767 || // Transport and map symbols
|
|
570
|
+
code >= 129280 && code <= 129535 || // Supplemental symbols and pictographs
|
|
571
|
+
code >= 129648 && code <= 129791;
|
|
572
|
+
}
|
|
556
573
|
var LayoutEngine = class {
|
|
557
574
|
constructor(fonts) {
|
|
558
575
|
this.fonts = fonts;
|
|
@@ -600,14 +617,43 @@ var LayoutEngine = class {
|
|
|
600
617
|
}
|
|
601
618
|
async layout(params) {
|
|
602
619
|
try {
|
|
603
|
-
const { textTransform, desc, fontSize, letterSpacing, width } = params;
|
|
620
|
+
const { textTransform, desc, fontSize, letterSpacing, width, emojiFallback } = params;
|
|
604
621
|
const input = this.transformText(params.text, textTransform);
|
|
605
622
|
if (!input || input.length === 0) {
|
|
606
623
|
return [];
|
|
607
624
|
}
|
|
608
625
|
let shaped;
|
|
609
626
|
try {
|
|
610
|
-
|
|
627
|
+
if (!emojiFallback) {
|
|
628
|
+
shaped = await this.shapeFull(input, desc);
|
|
629
|
+
} else {
|
|
630
|
+
const chars = Array.from(input);
|
|
631
|
+
const runs = [];
|
|
632
|
+
let currentRun = { text: "", startIndex: 0, isEmoji: false };
|
|
633
|
+
for (let i = 0; i < chars.length; i++) {
|
|
634
|
+
const char = chars[i];
|
|
635
|
+
const charIsEmoji = isEmoji(char);
|
|
636
|
+
if (i === 0) {
|
|
637
|
+
currentRun = { text: char, startIndex: 0, isEmoji: charIsEmoji };
|
|
638
|
+
} else if (currentRun.isEmoji === charIsEmoji) {
|
|
639
|
+
currentRun.text += char;
|
|
640
|
+
} else {
|
|
641
|
+
runs.push(currentRun);
|
|
642
|
+
currentRun = { text: char, startIndex: currentRun.startIndex + currentRun.text.length, isEmoji: charIsEmoji };
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
if (currentRun.text) runs.push(currentRun);
|
|
646
|
+
shaped = [];
|
|
647
|
+
for (const run of runs) {
|
|
648
|
+
const runFont = run.isEmoji ? emojiFallback : desc;
|
|
649
|
+
const runShaped = await this.shapeFull(run.text, runFont);
|
|
650
|
+
for (const glyph of runShaped) {
|
|
651
|
+
glyph.cl += run.startIndex;
|
|
652
|
+
glyph.fontDesc = runFont;
|
|
653
|
+
}
|
|
654
|
+
shaped.push(...runShaped);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
611
657
|
} catch (err) {
|
|
612
658
|
throw new Error(`Text shaping failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
613
659
|
}
|
|
@@ -633,7 +679,9 @@ var LayoutEngine = class {
|
|
|
633
679
|
xOffset: g.dx * scale,
|
|
634
680
|
yOffset: -g.dy * scale,
|
|
635
681
|
cluster: g.cl,
|
|
636
|
-
char
|
|
682
|
+
char,
|
|
683
|
+
fontDesc: g.fontDesc
|
|
684
|
+
// Preserve font descriptor
|
|
637
685
|
};
|
|
638
686
|
});
|
|
639
687
|
const lines = [];
|
|
@@ -781,7 +829,7 @@ async function buildDrawOps(p) {
|
|
|
781
829
|
const lineIndex = p.lines.indexOf(line);
|
|
782
830
|
const baselineY = blockY + lineIndex * lineHeightPx;
|
|
783
831
|
for (const glyph of line.glyphs) {
|
|
784
|
-
const path = await p.glyphPathProvider(glyph.id);
|
|
832
|
+
const path = await p.glyphPathProvider(glyph.id, glyph.fontDesc);
|
|
785
833
|
if (!path || path === "M 0 0") {
|
|
786
834
|
xCursor += glyph.xAdvance;
|
|
787
835
|
continue;
|
|
@@ -1761,6 +1809,13 @@ async function createTextEngine(opts = {}) {
|
|
|
1761
1809
|
const desc = { family: main.family, weight: `${main.weight}`, style: main.style };
|
|
1762
1810
|
let lines;
|
|
1763
1811
|
try {
|
|
1812
|
+
const emojiDesc = { family: "NotoEmoji", weight: "400", style: "normal" };
|
|
1813
|
+
let emojiAvailable = false;
|
|
1814
|
+
try {
|
|
1815
|
+
await fonts.getFace(emojiDesc);
|
|
1816
|
+
emojiAvailable = true;
|
|
1817
|
+
} catch {
|
|
1818
|
+
}
|
|
1764
1819
|
lines = await layout.layout({
|
|
1765
1820
|
text: asset.text,
|
|
1766
1821
|
width: asset.width ?? width,
|
|
@@ -1768,7 +1823,8 @@ async function createTextEngine(opts = {}) {
|
|
|
1768
1823
|
fontSize: main.size,
|
|
1769
1824
|
lineHeight: asset.style?.lineHeight ?? 1.2,
|
|
1770
1825
|
desc,
|
|
1771
|
-
textTransform: asset.style?.textTransform ?? "none"
|
|
1826
|
+
textTransform: asset.style?.textTransform ?? "none",
|
|
1827
|
+
emojiFallback: emojiAvailable ? emojiDesc : void 0
|
|
1772
1828
|
});
|
|
1773
1829
|
} catch (err) {
|
|
1774
1830
|
throw new Error(
|
|
@@ -1810,8 +1866,8 @@ async function createTextEngine(opts = {}) {
|
|
|
1810
1866
|
vertical: asset.align?.vertical ?? "middle"
|
|
1811
1867
|
},
|
|
1812
1868
|
background: asset.background,
|
|
1813
|
-
glyphPathProvider: (gid) => fonts.glyphPath(desc, gid),
|
|
1814
|
-
getUnitsPerEm: () => fonts.getUnitsPerEm(desc)
|
|
1869
|
+
glyphPathProvider: (gid, fontDesc) => fonts.glyphPath(fontDesc || desc, gid),
|
|
1870
|
+
getUnitsPerEm: (fontDesc) => fonts.getUnitsPerEm(fontDesc || desc)
|
|
1815
1871
|
});
|
|
1816
1872
|
} catch (err) {
|
|
1817
1873
|
throw new Error(
|
package/package.json
CHANGED