oasis-editor 0.0.98 → 0.0.99

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,7 +1,7 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
- import { v as visitRun, a as assertNever, c as createSignal, b as createEditorStateFromDocument, d as createInitialEditorState, S as STANDARD_FONT_SIZES_PT, f as fontSizePxToPt, p as probeLocalFontFamilies, e as createEditorParagraphFromRuns, i as isInlineObjectRun, g as createEditorStyledRun, h as getParagraphLength, j as getParagraphText, k as getActiveZone, l as getDocumentSections, m as getActiveSectionIndex, n as getParagraphs, o as normalizeSelection, q as positionToParagraphOffset, r as paragraphOffsetToPosition, s as clampPosition, t as findParagraphIndex, u as createCollapsedSelection, w as isSelectionCollapsed, x as parseFontSizePtToPx, y as formatFontSizePt, z as createEditorParagraph, A as getBlockParagraphs, B as findParagraphTableLocation, C as buildTableCellLayout, P as PT_PER_PX, D as createEditorTableCell, E as createEditorTableRow, F as createEditorTable, G as underlineStyleToCssDecorationStyle, H as resolveImageSrc, I as listKindForTag, J as isParagraphTag, K as collectInlineRuns, L as parseParagraphStyle, M as getRunImage, N as InlineShell, O as BalloonShell, Q as DocumentShell, R as createMemo, T as buildCanvasLayoutSnapshot, U as getCaretRectFromSnapshot, V as getParagraphRectFromSnapshot, W as createComponent, X as CaretOverlay, Y as Show, Z as createRenderEffect, _ as style, $ as setAttribute, a0 as setStyleProperty, a1 as memo, a2 as template, a3 as useI18n, a4 as createEffect, a5 as insert, a6 as use, a7 as addEventListener, a8 as Dialog, a9 as delegateEvents, aa as className, ab as For, ac as UNDERLINE_STYLE_OPTIONS, ad as Tabs, ae as onMount, af as onCleanup, ag as PluginUiHost, ah as OasisEditorEditor, ai as OasisBrandMark, aj as setPreciseFontPreference, ak as setWelcomeSeen, al as enablePreciseFontMode, am as TWIPS_PER_POINT, an as PX_PER_INCH, ao as TWIPS_PER_INCH, ap as resolveEffectiveParagraphStyle, aq as resolveEffectiveTextStyleForParagraph, ar as EMU_PER_PX, as as EMU_PER_PT, at as getRunFootnoteReference, au as getRunEndnoteReference, av as iterateFootnoteReferenceRuns, aw as iterateEndnoteReferenceRuns, ax as imageContentTypeDefaults, ay as getRunFieldChar, az as getRunFieldInstruction, aA as createEditorRun, aB as JSZip, aC as imageExtensionFromMime, aD as pxToPt$1, aE as resolveFloatingObjectRect, aF as getTextBoxFloatingGeometry, aG as getPresetPathSegments, aH as projectBlocksLayout, aI as buildListLabels, aJ as getImageFloatingGeometry, aK as textStyleToFontSizePt, aL as PX_PER_POINT, aM as DEFAULT_FONT_SIZE_PX, aN as isDoubleUnderlineStyle, aO as isWavyUnderlineStyle, aP as underlineStyleLineWidthPx, aQ as underlineStyleDashArray, aR as resolveListLabel, aS as getListLabelInset, aT as getAlignedListLabelInset, aU as getParagraphBorderInsets, aV as buildSegmentTable, aW as buildCanvasTableLayout, aX as resolveCanvasTableWidth, aY as resolveFloatingTableRect, aZ as normalizeFamily, a_ as ROBOTO_FONT_FILES, a$ as loadFontAsset, b0 as OFFICE_COMPAT_FONT_FAMILIES, b1 as buildSfnt, b2 as defaultFontDecoderRegistry, b3 as SfntFontProgram, b4 as collectPdfFontFamilies, b5 as projectDocumentLayout, b6 as getPageContentWidth, b7 as getPageHeaderZoneTop, b8 as getPageBodyTop, b9 as getPageColumnRects, ba as findFootnoteReference, bb as FOOTNOTE_MARKER_GUTTER_PX, bc as resolveImporterForFile, bd as getDocumentSectionsCanonical, be as getDocumentParagraphsCanonical, bf as getDocumentParagraphs, bg as getDocumentPageSettings, bh as getTableCellContentWidthForParagraph, bi as on, bj as debounce, bk as unwrap, bl as perfTimer, bm as getRunTextBox, bn as createEditorDocument, bo as resolveResizedDimensions, bp as resolveTextBoxRenderHeight, bq as getToolbarStyleState, br as getCachedCanvasImage, bs as measureParagraphMinContentWidthPx, bt as getEditableBlocksForZone, bu as findParagraphLocation, bv as createSectionBoundaryParagraph, bw as normalizePageSettings, bx as DEFAULT_EDITOR_PAGE_SETTINGS, by as markStart, bz as markEnd, bA as getParagraphEntries, bB as getParagraphById, bC as createEditorFootnote, bD as createFootnoteReferenceRun, bE as renumberFootnotes, bF as getFootnoteDisplayMarker, bG as getHeadingLevel, bH as preciseFontModeVersion, bI as isPreciseFontModeEnabled, bJ as resolveNamedTextStyle, bK as togglePreciseFontMode, bL as nextFontSizePt, bM as previousFontSizePt, bN as fontSizePtToPx, bO as createDefaultToolbarPreset, bP as MenuRegistry, bQ as createToolbarRegistry, bR as Editor, bS as resolveCommandRef, bT as commandRefName, bU as createOasisEditorClient, bV as createEditorZoom, bW as startLongTaskObserver, bX as installGlobalReport, bY as applyStoredPreciseFontPreference, bZ as getWelcomeSeen, b_ as isLocalFontAccessSupported, b$ as EDITOR_SCROLL_PADDING_PX, c0 as Toolbar, c1 as OasisEditorLoading, c2 as I18nProvider, c3 as createTranslator, c4 as createEditorLogger, c5 as registerDomStatsSurface } from "./index-DBzN897A.js";
4
+ import { v as visitRun, a as assertNever, c as createSignal, b as createEditorStateFromDocument, d as createInitialEditorState, S as STANDARD_FONT_SIZES_PT, f as fontSizePxToPt, p as probeLocalFontFamilies, e as createEditorParagraphFromRuns, i as isInlineObjectRun, g as createEditorStyledRun, h as getParagraphLength, j as getParagraphText, k as getActiveZone, l as getDocumentSections, m as getActiveSectionIndex, n as getParagraphs, o as normalizeSelection, q as positionToParagraphOffset, r as paragraphOffsetToPosition, s as clampPosition, t as findParagraphIndex, u as createCollapsedSelection, w as isSelectionCollapsed, x as parseFontSizePtToPx, y as formatFontSizePt, z as createEditorParagraph, A as getBlockParagraphs, B as findParagraphTableLocation, C as buildTableCellLayout, P as PT_PER_PX, D as createEditorTableCell, E as createEditorTableRow, F as createEditorTable, G as underlineStyleToCssDecorationStyle, H as resolveImageSrc, I as listKindForTag, J as isParagraphTag, K as collectInlineRuns, L as parseParagraphStyle, M as getRunImage, N as InlineShell, O as BalloonShell, Q as DocumentShell, R as createMemo, T as buildCanvasLayoutSnapshot, U as getCaretRectFromSnapshot, V as getParagraphRectFromSnapshot, W as createComponent, X as CaretOverlay, Y as Show, Z as createRenderEffect, _ as style, $ as setAttribute, a0 as setStyleProperty, a1 as memo, a2 as template, a3 as useI18n, a4 as createEffect, a5 as insert, a6 as use, a7 as addEventListener, a8 as Dialog, a9 as delegateEvents, aa as className, ab as For, ac as UNDERLINE_STYLE_OPTIONS, ad as Tabs, ae as onMount, af as onCleanup, ag as PluginUiHost, ah as OasisEditorEditor, ai as OasisBrandMark, aj as setPreciseFontPreference, ak as setWelcomeSeen, al as enablePreciseFontMode, am as TWIPS_PER_POINT, an as PX_PER_INCH, ao as TWIPS_PER_INCH, ap as resolveEffectiveParagraphStyle, aq as resolveEffectiveTextStyleForParagraph, ar as EMU_PER_PX, as as EMU_PER_PT, at as getRunFootnoteReference, au as getRunEndnoteReference, av as iterateFootnoteReferenceRuns, aw as iterateEndnoteReferenceRuns, ax as imageContentTypeDefaults, ay as getRunFieldChar, az as getRunFieldInstruction, aA as createEditorRun, aB as JSZip, aC as imageExtensionFromMime, aD as pxToPt$1, aE as resolveFloatingObjectRect, aF as getTextBoxFloatingGeometry, aG as getPresetPathSegments, aH as projectBlocksLayout, aI as buildListLabels, aJ as getImageFloatingGeometry, aK as textStyleToFontSizePt, aL as PX_PER_POINT, aM as resolveOpenTypeFeatureTags, aN as DEFAULT_FONT_SIZE_PX, aO as isDoubleUnderlineStyle, aP as isWavyUnderlineStyle, aQ as underlineStyleLineWidthPx, aR as underlineStyleDashArray, aS as resolveListLabel, aT as getListLabelInset, aU as getAlignedListLabelInset, aV as getParagraphBorderInsets, aW as buildSegmentTable, aX as buildCanvasTableLayout, aY as resolveCanvasTableWidth, aZ as resolveFloatingTableRect, a_ as normalizeFamily, a$ as ROBOTO_FONT_FILES, b0 as loadFontAsset, b1 as OFFICE_COMPAT_FONT_FAMILIES, b2 as BinaryReader, b3 as buildSfnt, b4 as defaultFontDecoderRegistry, b5 as SfntFontProgram, b6 as collectPdfFontFamilies, b7 as projectDocumentLayout, b8 as getPageContentWidth, b9 as getPageHeaderZoneTop, ba as getPageBodyTop, bb as getPageColumnRects, bc as findFootnoteReference, bd as FOOTNOTE_MARKER_GUTTER_PX, be as resolveImporterForFile, bf as getDocumentSectionsCanonical, bg as getDocumentParagraphsCanonical, bh as getDocumentParagraphs, bi as getDocumentPageSettings, bj as getTableCellContentWidthForParagraph, bk as on, bl as debounce, bm as unwrap, bn as perfTimer, bo as getRunTextBox, bp as createEditorDocument, bq as resolveResizedDimensions, br as resolveTextBoxRenderHeight, bs as getToolbarStyleState, bt as getCachedCanvasImage, bu as measureParagraphMinContentWidthPx, bv as getEditableBlocksForZone, bw as findParagraphLocation, bx as createSectionBoundaryParagraph, by as normalizePageSettings, bz as DEFAULT_EDITOR_PAGE_SETTINGS, bA as markStart, bB as markEnd, bC as getParagraphEntries, bD as getParagraphById, bE as createEditorFootnote, bF as createFootnoteReferenceRun, bG as renumberFootnotes, bH as getFootnoteDisplayMarker, bI as getHeadingLevel, bJ as preciseFontModeVersion, bK as isPreciseFontModeEnabled, bL as resolveNamedTextStyle, bM as togglePreciseFontMode, bN as nextFontSizePt, bO as previousFontSizePt, bP as fontSizePtToPx, bQ as createDefaultToolbarPreset, bR as MenuRegistry, bS as createToolbarRegistry, bT as Editor, bU as resolveCommandRef, bV as commandRefName, bW as createOasisEditorClient, bX as createEditorZoom, bY as startLongTaskObserver, bZ as installGlobalReport, b_ as applyStoredPreciseFontPreference, b$ as getWelcomeSeen, c0 as isLocalFontAccessSupported, c1 as EDITOR_SCROLL_PADDING_PX, c2 as Toolbar, c3 as OasisEditorLoading, c4 as I18nProvider, c5 as createTranslator, c6 as createEditorLogger, c7 as registerDomStatsSurface } from "./index-CNuDp_SC.js";
5
5
  function cloneStyle(style2) {
6
6
  return style2 ? { ...style2 } : void 0;
7
7
  }
@@ -36309,6 +36309,13 @@ async function drawFloatingImagesForParagraph(options) {
36309
36309
  }
36310
36310
  }
36311
36311
  }
36312
+ function blendColorWithWhite(hex, alpha) {
36313
+ const a = Math.max(0, Math.min(1, alpha));
36314
+ const r = Math.round(255 + (Number.parseInt(hex.slice(1, 3), 16) - 255) * a);
36315
+ const g = Math.round(255 + (Number.parseInt(hex.slice(3, 5), 16) - 255) * a);
36316
+ const b = Math.round(255 + (Number.parseInt(hex.slice(5, 7), 16) - 255) * a);
36317
+ return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
36318
+ }
36312
36319
  function drawFragmentHighlight(writer, pageIndex, line, fragment, originX, originY, styles) {
36313
36320
  if (!styles.highlight) {
36314
36321
  return;
@@ -36707,13 +36714,15 @@ async function drawFragmentText(writer, pageIndex, paragraph, line, fragment, do
36707
36714
  styles.color ?? "#000000"
36708
36715
  );
36709
36716
  const paragraphAlign = resolveEffectiveParagraphStyle(paragraph.style, document2.styles).align ?? "left";
36717
+ const fontFeatures = resolveOpenTypeFeatureTags(styles);
36710
36718
  const baseTextOptions = {
36711
36719
  fontSize: fontSizePt,
36712
36720
  bold: styles.bold,
36713
36721
  italic: styles.italic,
36714
36722
  fontResourceName: fontFace.writerResourceName,
36715
36723
  characterSpacing: styles.characterSpacing ?? 0,
36716
- horizontalScale: styles.characterScale ?? 100
36724
+ horizontalScale: styles.characterScale ?? 100,
36725
+ fontFeatures
36717
36726
  };
36718
36727
  const mainColor = ((_b = styles.textFill) == null ? void 0 : _b.type) === "solid" ? styles.textFill.color : ((_c = styles.textFill) == null ? void 0 : _c.type) === "gradient" && styles.textFill.stops[0] ? styles.textFill.stops[0].color : styles.color ?? "#000000";
36719
36728
  const offsetPt = pxToPt$1(1);
@@ -36728,6 +36737,30 @@ async function drawFragmentText(writer, pageIndex, paragraph, line, fragment, do
36728
36737
  color: "#BFBFBF"
36729
36738
  });
36730
36739
  }
36740
+ if (styles.glow) {
36741
+ const gl = styles.glow;
36742
+ const r = pxToPt$1(gl.radiusPt * PX_PER_POINT) * 0.5;
36743
+ const glowColor = blendColorWithWhite(gl.color, (gl.alpha ?? 0.5) * 0.4);
36744
+ const dirs = [
36745
+ [r, 0],
36746
+ [-r, 0],
36747
+ [0, r],
36748
+ [0, -r],
36749
+ [r * 0.7, r * 0.7],
36750
+ [-r * 0.7, r * 0.7],
36751
+ [r * 0.7, -r * 0.7],
36752
+ [-r * 0.7, -r * 0.7]
36753
+ ];
36754
+ for (const [dx, dy] of dirs) {
36755
+ writer.drawText(pageIndex, {
36756
+ ...baseTextOptions,
36757
+ x: pxToPt$1(leftPx) + dx,
36758
+ y: pxToPt$1(baselineY) + dy,
36759
+ text: text2,
36760
+ color: glowColor
36761
+ });
36762
+ }
36763
+ }
36731
36764
  if (styles.textShadow) {
36732
36765
  const ts = styles.textShadow;
36733
36766
  const dirRad = ts.dirDeg * Math.PI / 180;
@@ -36748,6 +36781,18 @@ async function drawFragmentText(writer, pageIndex, paragraph, line, fragment, do
36748
36781
  color: "#808080"
36749
36782
  });
36750
36783
  }
36784
+ if (styles.reflection) {
36785
+ const ref = styles.reflection;
36786
+ const avgAlpha = (ref.startAlpha + ref.endAlpha) / 2;
36787
+ const refColor = blendColorWithWhite(mainColor, avgAlpha * 0.6);
36788
+ writer.drawText(pageIndex, {
36789
+ ...baseTextOptions,
36790
+ x: pxToPt$1(leftPx),
36791
+ y: pxToPt$1(baselineY) + pxToPt$1(ref.distPt * PX_PER_POINT) + fontSizePt,
36792
+ text: text2,
36793
+ color: refColor
36794
+ });
36795
+ }
36751
36796
  const textOutline = styles.textOutline;
36752
36797
  writer.drawText(pageIndex, {
36753
36798
  ...baseTextOptions,
@@ -37739,7 +37784,11 @@ class PdfContentStream {
37739
37784
  }
37740
37785
  const fontResourceName = this.fonts.resolveAndMarkFontName(options);
37741
37786
  const unicodeState = this.fonts.getUnicodeState(fontResourceName);
37742
- const showCommand = unicodeState ? this.fonts.buildUnicodeShowCommand(unicodeState, options.text) : `<${encodePdfHexString(options.text)}> Tj`;
37787
+ const showCommand = unicodeState ? this.fonts.buildUnicodeShowCommand(
37788
+ unicodeState,
37789
+ options.text,
37790
+ options.fontFeatures
37791
+ ) : `<${encodePdfHexString(options.text)}> Tj`;
37743
37792
  if (showCommand === null) {
37744
37793
  return;
37745
37794
  }
@@ -37826,6 +37875,636 @@ class PdfContentStream {
37826
37875
  );
37827
37876
  }
37828
37877
  }
37878
+ function readTag(reader) {
37879
+ return reader.tag();
37880
+ }
37881
+ function parseCoverage(reader, offset) {
37882
+ reader.seek(offset);
37883
+ const format = reader.u16();
37884
+ if (format === 1) {
37885
+ const count = reader.u16();
37886
+ const map = /* @__PURE__ */ new Map();
37887
+ for (let i = 0; i < count; i += 1) {
37888
+ map.set(reader.u16(), i);
37889
+ }
37890
+ return (glyphId) => map.get(glyphId) ?? -1;
37891
+ }
37892
+ if (format === 2) {
37893
+ const rangeCount = reader.u16();
37894
+ const ranges = [];
37895
+ for (let i = 0; i < rangeCount; i += 1) {
37896
+ const start = reader.u16();
37897
+ const end = reader.u16();
37898
+ const startIndex = reader.u16();
37899
+ ranges.push({ start, end, startIndex });
37900
+ }
37901
+ return (glyphId) => {
37902
+ for (const range of ranges) {
37903
+ if (glyphId >= range.start && glyphId <= range.end) {
37904
+ return range.startIndex + (glyphId - range.start);
37905
+ }
37906
+ }
37907
+ return -1;
37908
+ };
37909
+ }
37910
+ return () => -1;
37911
+ }
37912
+ function parseClassDef(reader, offset) {
37913
+ reader.seek(offset);
37914
+ const format = reader.u16();
37915
+ if (format === 1) {
37916
+ const startGlyph = reader.u16();
37917
+ const glyphCount = reader.u16();
37918
+ const classes = new Array(glyphCount);
37919
+ for (let i = 0; i < glyphCount; i += 1) {
37920
+ classes[i] = reader.u16();
37921
+ }
37922
+ return (glyphId) => {
37923
+ const index = glyphId - startGlyph;
37924
+ return index >= 0 && index < glyphCount ? classes[index] : 0;
37925
+ };
37926
+ }
37927
+ if (format === 2) {
37928
+ const rangeCount = reader.u16();
37929
+ const ranges = [];
37930
+ for (let i = 0; i < rangeCount; i += 1) {
37931
+ const start = reader.u16();
37932
+ const end = reader.u16();
37933
+ const classValue = reader.u16();
37934
+ ranges.push({ start, end, classValue });
37935
+ }
37936
+ return (glyphId) => {
37937
+ for (const range of ranges) {
37938
+ if (glyphId >= range.start && glyphId <= range.end) {
37939
+ return range.classValue;
37940
+ }
37941
+ }
37942
+ return 0;
37943
+ };
37944
+ }
37945
+ return () => 0;
37946
+ }
37947
+ function parseSingleSubst(reader, offset) {
37948
+ reader.seek(offset);
37949
+ const format = reader.u16();
37950
+ const coverageOffset = offset + reader.u16();
37951
+ if (format === 1) {
37952
+ const delta = reader.i16();
37953
+ const coverage = parseCoverage(reader, coverageOffset);
37954
+ return {
37955
+ apply(glyphs, pos) {
37956
+ const glyph = glyphs[pos];
37957
+ if (!glyph || coverage(glyph.id) < 0) return null;
37958
+ glyph.id = glyph.id + delta & 65535;
37959
+ return 1;
37960
+ }
37961
+ };
37962
+ }
37963
+ if (format === 2) {
37964
+ const glyphCount = reader.u16();
37965
+ const substitutes = new Array(glyphCount);
37966
+ for (let i = 0; i < glyphCount; i += 1) {
37967
+ substitutes[i] = reader.u16();
37968
+ }
37969
+ const coverage = parseCoverage(reader, coverageOffset);
37970
+ return {
37971
+ apply(glyphs, pos) {
37972
+ const glyph = glyphs[pos];
37973
+ if (!glyph) return null;
37974
+ const index = coverage(glyph.id);
37975
+ if (index < 0 || index >= glyphCount) return null;
37976
+ glyph.id = substitutes[index];
37977
+ return 1;
37978
+ }
37979
+ };
37980
+ }
37981
+ return null;
37982
+ }
37983
+ function parseMultipleSubst(reader, offset) {
37984
+ reader.seek(offset);
37985
+ const format = reader.u16();
37986
+ if (format !== 1) return null;
37987
+ const coverageOffset = offset + reader.u16();
37988
+ const sequenceCount = reader.u16();
37989
+ const sequenceOffsets = new Array(sequenceCount);
37990
+ for (let i = 0; i < sequenceCount; i += 1) {
37991
+ sequenceOffsets[i] = offset + reader.u16();
37992
+ }
37993
+ const sequences = sequenceOffsets.map((seqOffset) => {
37994
+ reader.seek(seqOffset);
37995
+ const glyphCount = reader.u16();
37996
+ const ids = new Array(glyphCount);
37997
+ for (let i = 0; i < glyphCount; i += 1) ids[i] = reader.u16();
37998
+ return ids;
37999
+ });
38000
+ const coverage = parseCoverage(reader, coverageOffset);
38001
+ return {
38002
+ apply(glyphs, pos) {
38003
+ const glyph = glyphs[pos];
38004
+ if (!glyph) return null;
38005
+ const index = coverage(glyph.id);
38006
+ if (index < 0 || index >= sequences.length) return null;
38007
+ const ids = sequences[index];
38008
+ if (ids.length === 0) return null;
38009
+ const codePoints = glyph.codePoints;
38010
+ const replacement = ids.map((id, i) => ({
38011
+ id,
38012
+ codePoints: i === 0 ? codePoints : []
38013
+ }));
38014
+ glyphs.splice(pos, 1, ...replacement);
38015
+ return ids.length;
38016
+ }
38017
+ };
38018
+ }
38019
+ function parseAlternateSubst(reader, offset) {
38020
+ reader.seek(offset);
38021
+ const format = reader.u16();
38022
+ if (format !== 1) return null;
38023
+ const coverageOffset = offset + reader.u16();
38024
+ const altSetCount = reader.u16();
38025
+ const altSetOffsets = new Array(altSetCount);
38026
+ for (let i = 0; i < altSetCount; i += 1) {
38027
+ altSetOffsets[i] = offset + reader.u16();
38028
+ }
38029
+ const altSets = altSetOffsets.map((setOffset) => {
38030
+ reader.seek(setOffset);
38031
+ const glyphCount = reader.u16();
38032
+ const ids = new Array(glyphCount);
38033
+ for (let i = 0; i < glyphCount; i += 1) ids[i] = reader.u16();
38034
+ return ids;
38035
+ });
38036
+ const coverage = parseCoverage(reader, coverageOffset);
38037
+ return {
38038
+ apply(glyphs, pos) {
38039
+ const glyph = glyphs[pos];
38040
+ if (!glyph) return null;
38041
+ const index = coverage(glyph.id);
38042
+ if (index < 0 || index >= altSets.length) return null;
38043
+ const alts = altSets[index];
38044
+ if (alts.length === 0) return null;
38045
+ glyph.id = alts[0];
38046
+ return 1;
38047
+ }
38048
+ };
38049
+ }
38050
+ function parseLigatureSubst(reader, offset) {
38051
+ reader.seek(offset);
38052
+ const format = reader.u16();
38053
+ if (format !== 1) return null;
38054
+ const coverageOffset = offset + reader.u16();
38055
+ const ligSetCount = reader.u16();
38056
+ const ligSetOffsets = new Array(ligSetCount);
38057
+ for (let i = 0; i < ligSetCount; i += 1) {
38058
+ ligSetOffsets[i] = offset + reader.u16();
38059
+ }
38060
+ const ligatureSets = ligSetOffsets.map((setOffset) => {
38061
+ reader.seek(setOffset);
38062
+ const ligCount = reader.u16();
38063
+ const ligOffsets = new Array(ligCount);
38064
+ for (let i = 0; i < ligCount; i += 1) {
38065
+ ligOffsets[i] = setOffset + reader.u16();
38066
+ }
38067
+ return ligOffsets.map((ligOffset) => {
38068
+ reader.seek(ligOffset);
38069
+ const ligatureGlyph = reader.u16();
38070
+ const componentCount = reader.u16();
38071
+ const components = new Array(Math.max(0, componentCount - 1));
38072
+ for (let i = 0; i < components.length; i += 1) {
38073
+ components[i] = reader.u16();
38074
+ }
38075
+ return { ligatureGlyph, components };
38076
+ });
38077
+ });
38078
+ const coverage = parseCoverage(reader, coverageOffset);
38079
+ return {
38080
+ apply(glyphs, pos) {
38081
+ const first = glyphs[pos];
38082
+ if (!first) return null;
38083
+ const setIndex = coverage(first.id);
38084
+ if (setIndex < 0 || setIndex >= ligatureSets.length) return null;
38085
+ for (const ligature of ligatureSets[setIndex]) {
38086
+ const { components } = ligature;
38087
+ if (pos + components.length > glyphs.length - 1) continue;
38088
+ let matched = true;
38089
+ for (let i = 0; i < components.length; i += 1) {
38090
+ if (glyphs[pos + 1 + i].id !== components[i]) {
38091
+ matched = false;
38092
+ break;
38093
+ }
38094
+ }
38095
+ if (!matched) continue;
38096
+ const total = components.length + 1;
38097
+ const mergedCodePoints = [];
38098
+ for (let i = 0; i < total; i += 1) {
38099
+ mergedCodePoints.push(...glyphs[pos + i].codePoints);
38100
+ }
38101
+ glyphs.splice(pos, total, {
38102
+ id: ligature.ligatureGlyph,
38103
+ codePoints: mergedCodePoints
38104
+ });
38105
+ return 1;
38106
+ }
38107
+ return null;
38108
+ }
38109
+ };
38110
+ }
38111
+ function readSubstLookupRecords(reader, count) {
38112
+ const records = new Array(count);
38113
+ for (let i = 0; i < count; i += 1) {
38114
+ const sequenceIndex = reader.u16();
38115
+ const lookupListIndex = reader.u16();
38116
+ records[i] = { sequenceIndex, lookupListIndex };
38117
+ }
38118
+ return records;
38119
+ }
38120
+ function applySubstRecords(glyphs, pos, records, engine) {
38121
+ for (const record of records) {
38122
+ engine.applyLookupIndexAt(
38123
+ record.lookupListIndex,
38124
+ glyphs,
38125
+ pos + record.sequenceIndex
38126
+ );
38127
+ }
38128
+ }
38129
+ function parseChainContextSubst(reader, offset) {
38130
+ reader.seek(offset);
38131
+ const format = reader.u16();
38132
+ if (format === 3) {
38133
+ const backtrackCount = reader.u16();
38134
+ const backtrackCoverageOffsets = new Array(backtrackCount);
38135
+ for (let i = 0; i < backtrackCount; i += 1) {
38136
+ backtrackCoverageOffsets[i] = offset + reader.u16();
38137
+ }
38138
+ const inputCount = reader.u16();
38139
+ const inputCoverageOffsets = new Array(inputCount);
38140
+ for (let i = 0; i < inputCount; i += 1) {
38141
+ inputCoverageOffsets[i] = offset + reader.u16();
38142
+ }
38143
+ const lookaheadCount = reader.u16();
38144
+ const lookaheadCoverageOffsets = new Array(lookaheadCount);
38145
+ for (let i = 0; i < lookaheadCount; i += 1) {
38146
+ lookaheadCoverageOffsets[i] = offset + reader.u16();
38147
+ }
38148
+ const substCount = reader.u16();
38149
+ const records = readSubstLookupRecords(reader, substCount);
38150
+ const backtrack = backtrackCoverageOffsets.map(
38151
+ (o) => parseCoverage(reader, o)
38152
+ );
38153
+ const input = inputCoverageOffsets.map((o) => parseCoverage(reader, o));
38154
+ const lookahead = lookaheadCoverageOffsets.map(
38155
+ (o) => parseCoverage(reader, o)
38156
+ );
38157
+ return {
38158
+ apply(glyphs, pos, engine) {
38159
+ if (input.length === 0) return null;
38160
+ if (pos + input.length > glyphs.length) return null;
38161
+ for (let i = 0; i < input.length; i += 1) {
38162
+ if (input[i](glyphs[pos + i].id) < 0) return null;
38163
+ }
38164
+ for (let i = 0; i < backtrack.length; i += 1) {
38165
+ const g = glyphs[pos - 1 - i];
38166
+ if (!g || backtrack[i](g.id) < 0) return null;
38167
+ }
38168
+ for (let i = 0; i < lookahead.length; i += 1) {
38169
+ const g = glyphs[pos + input.length + i];
38170
+ if (!g || lookahead[i](g.id) < 0) return null;
38171
+ }
38172
+ applySubstRecords(glyphs, pos, records, engine);
38173
+ return input.length;
38174
+ }
38175
+ };
38176
+ }
38177
+ if (format === 1) {
38178
+ const coverageOffset = offset + reader.u16();
38179
+ const ruleSetCount = reader.u16();
38180
+ const ruleSetOffsets = new Array(ruleSetCount);
38181
+ for (let i = 0; i < ruleSetCount; i += 1) {
38182
+ ruleSetOffsets[i] = offset + reader.u16();
38183
+ }
38184
+ const coverage = parseCoverage(reader, coverageOffset);
38185
+ const ruleSets = ruleSetOffsets.map(
38186
+ (setOffset) => parseChainRuleSet(reader, setOffset)
38187
+ );
38188
+ return {
38189
+ apply(glyphs, pos, engine) {
38190
+ const glyph = glyphs[pos];
38191
+ if (!glyph) return null;
38192
+ const index = coverage(glyph.id);
38193
+ if (index < 0 || index >= ruleSets.length) return null;
38194
+ return applyChainRules(ruleSets[index], glyphs, pos, engine, null);
38195
+ }
38196
+ };
38197
+ }
38198
+ if (format === 2) {
38199
+ const coverageOffset = offset + reader.u16();
38200
+ const backtrackClassOffset = offset + reader.u16();
38201
+ const inputClassOffset = offset + reader.u16();
38202
+ const lookaheadClassOffset = offset + reader.u16();
38203
+ const classSetCount = reader.u16();
38204
+ const classSetOffsets = new Array(classSetCount);
38205
+ for (let i = 0; i < classSetCount; i += 1) {
38206
+ const raw = reader.u16();
38207
+ classSetOffsets[i] = raw === 0 ? 0 : offset + raw;
38208
+ }
38209
+ const coverage = parseCoverage(reader, coverageOffset);
38210
+ const backtrackClass = parseClassDef(reader, backtrackClassOffset);
38211
+ const inputClass = parseClassDef(reader, inputClassOffset);
38212
+ const lookaheadClass = parseClassDef(reader, lookaheadClassOffset);
38213
+ const classSets = classSetOffsets.map(
38214
+ (setOffset) => setOffset === 0 ? [] : parseChainRuleSet(reader, setOffset)
38215
+ );
38216
+ return {
38217
+ apply(glyphs, pos, engine) {
38218
+ const glyph = glyphs[pos];
38219
+ if (!glyph) return null;
38220
+ if (coverage(glyph.id) < 0) return null;
38221
+ const classIndex = inputClass(glyph.id);
38222
+ const ruleSet = classSets[classIndex];
38223
+ if (!ruleSet) return null;
38224
+ return applyChainRules(ruleSet, glyphs, pos, engine, {
38225
+ backtrack: backtrackClass,
38226
+ input: inputClass,
38227
+ lookahead: lookaheadClass
38228
+ });
38229
+ }
38230
+ };
38231
+ }
38232
+ return null;
38233
+ }
38234
+ function parseChainRuleSet(reader, setOffset) {
38235
+ reader.seek(setOffset);
38236
+ const ruleCount = reader.u16();
38237
+ const ruleOffsets = new Array(ruleCount);
38238
+ for (let i = 0; i < ruleCount; i += 1) {
38239
+ ruleOffsets[i] = setOffset + reader.u16();
38240
+ }
38241
+ return ruleOffsets.map((ruleOffset) => {
38242
+ reader.seek(ruleOffset);
38243
+ const backtrackCount = reader.u16();
38244
+ const backtrack = new Array(backtrackCount);
38245
+ for (let i = 0; i < backtrackCount; i += 1) backtrack[i] = reader.u16();
38246
+ const inputCount = reader.u16();
38247
+ const input = new Array(Math.max(0, inputCount - 1));
38248
+ for (let i = 0; i < input.length; i += 1) input[i] = reader.u16();
38249
+ const lookaheadCount = reader.u16();
38250
+ const lookahead = new Array(lookaheadCount);
38251
+ for (let i = 0; i < lookaheadCount; i += 1) lookahead[i] = reader.u16();
38252
+ const substCount = reader.u16();
38253
+ const records = readSubstLookupRecords(reader, substCount);
38254
+ return { backtrack, input, lookahead, records };
38255
+ });
38256
+ }
38257
+ function applyChainRules(rules, glyphs, pos, engine, resolver) {
38258
+ const valueAt = (index, kind) => {
38259
+ const g = glyphs[index];
38260
+ if (!g) return null;
38261
+ if (!resolver) return g.id;
38262
+ if (kind === "b") return resolver.backtrack(g.id);
38263
+ if (kind === "l") return resolver.lookahead(g.id);
38264
+ return resolver.input(g.id);
38265
+ };
38266
+ for (const rule of rules) {
38267
+ const inputLen = rule.input.length + 1;
38268
+ if (pos + inputLen > glyphs.length) continue;
38269
+ let matched = true;
38270
+ for (let i = 0; i < rule.input.length; i += 1) {
38271
+ if (valueAt(pos + 1 + i, "i") !== rule.input[i]) {
38272
+ matched = false;
38273
+ break;
38274
+ }
38275
+ }
38276
+ if (!matched) continue;
38277
+ for (let i = 0; i < rule.backtrack.length; i += 1) {
38278
+ if (valueAt(pos - 1 - i, "b") !== rule.backtrack[i]) {
38279
+ matched = false;
38280
+ break;
38281
+ }
38282
+ }
38283
+ if (!matched) continue;
38284
+ for (let i = 0; i < rule.lookahead.length; i += 1) {
38285
+ if (valueAt(pos + inputLen + i, "l") !== rule.lookahead[i]) {
38286
+ matched = false;
38287
+ break;
38288
+ }
38289
+ }
38290
+ if (!matched) continue;
38291
+ applySubstRecords(glyphs, pos, rule.records, engine);
38292
+ return inputLen;
38293
+ }
38294
+ return null;
38295
+ }
38296
+ function parseSubtable(reader, offset, lookupType) {
38297
+ switch (lookupType) {
38298
+ case 1:
38299
+ return parseSingleSubst(reader, offset);
38300
+ case 2:
38301
+ return parseMultipleSubst(reader, offset);
38302
+ case 3:
38303
+ return parseAlternateSubst(reader, offset);
38304
+ case 4:
38305
+ return parseLigatureSubst(reader, offset);
38306
+ case 6:
38307
+ return parseChainContextSubst(reader, offset);
38308
+ case 7: {
38309
+ reader.seek(offset);
38310
+ const format = reader.u16();
38311
+ if (format !== 1) return null;
38312
+ const extensionType = reader.u16();
38313
+ const extensionOffset = offset + reader.u32();
38314
+ return parseSubtable(reader, extensionOffset, extensionType);
38315
+ }
38316
+ default:
38317
+ return null;
38318
+ }
38319
+ }
38320
+ class GsubTable {
38321
+ constructor(lookups, featureToLookups) {
38322
+ this.lookups = lookups;
38323
+ this.featureToLookups = featureToLookups;
38324
+ }
38325
+ /** Parses GSUB bytes (table-relative). Returns null on any structural failure. */
38326
+ static parse(bytes) {
38327
+ try {
38328
+ const reader = new BinaryReader(bytes);
38329
+ reader.seek(0);
38330
+ reader.skip(2);
38331
+ reader.skip(2);
38332
+ const scriptListOffset = reader.u16();
38333
+ const featureListOffset = reader.u16();
38334
+ const lookupListOffset = reader.u16();
38335
+ const featureRecords = parseFeatureList(reader, featureListOffset);
38336
+ const activeFeatureIndices = parseScriptList(reader, scriptListOffset);
38337
+ const lookups = parseLookupList(reader, lookupListOffset);
38338
+ const featureToLookups = /* @__PURE__ */ new Map();
38339
+ for (const featureIndex of activeFeatureIndices) {
38340
+ const record = featureRecords[featureIndex];
38341
+ if (!record) continue;
38342
+ const existing = featureToLookups.get(record.tag) ?? [];
38343
+ for (const lookupIndex of record.lookupIndices) {
38344
+ if (!existing.includes(lookupIndex)) existing.push(lookupIndex);
38345
+ }
38346
+ featureToLookups.set(record.tag, existing);
38347
+ }
38348
+ return new GsubTable(lookups, featureToLookups);
38349
+ } catch {
38350
+ return null;
38351
+ }
38352
+ }
38353
+ /** True when at least one of the requested feature tags exists in this font. */
38354
+ hasAnyFeature(tags) {
38355
+ return tags.some((tag) => this.featureToLookups.has(tag));
38356
+ }
38357
+ /** Ordered (ascending) unique lookup indices referenced by the given tags. */
38358
+ collectLookupIndices(tags) {
38359
+ const indices = /* @__PURE__ */ new Set();
38360
+ for (const tag of tags) {
38361
+ for (const lookupIndex of this.featureToLookups.get(tag) ?? []) {
38362
+ indices.add(lookupIndex);
38363
+ }
38364
+ }
38365
+ return Array.from(indices).sort((a, b) => a - b);
38366
+ }
38367
+ /**
38368
+ * Applies one lookup (by index) at a single position. Tries each subtable in
38369
+ * order; the first that matches wins. Returns the advance (output glyph count)
38370
+ * or null when nothing matched. Used both by the shaping walk and by nested
38371
+ * chaining-contextual substitution records.
38372
+ */
38373
+ applyLookupIndexAt(lookupIndex, glyphs, pos) {
38374
+ const lookup = this.lookups[lookupIndex];
38375
+ if (!lookup || pos < 0 || pos >= glyphs.length) return null;
38376
+ for (const subtable of lookup.subtables) {
38377
+ const advance = subtable.apply(glyphs, pos, this);
38378
+ if (advance !== null) return advance;
38379
+ }
38380
+ return null;
38381
+ }
38382
+ /** Applies the lookups for the given features across the whole buffer. */
38383
+ shape(glyphs, tags) {
38384
+ const lookupIndices = this.collectLookupIndices(tags);
38385
+ for (const lookupIndex of lookupIndices) {
38386
+ let pos = 0;
38387
+ while (pos < glyphs.length) {
38388
+ const advance = this.applyLookupIndexAt(lookupIndex, glyphs, pos);
38389
+ pos += advance && advance > 0 ? advance : 1;
38390
+ }
38391
+ }
38392
+ }
38393
+ }
38394
+ function parseFeatureList(reader, featureListOffset) {
38395
+ reader.seek(featureListOffset);
38396
+ const featureCount = reader.u16();
38397
+ const records = [];
38398
+ for (let i = 0; i < featureCount; i += 1) {
38399
+ const tag = readTag(reader);
38400
+ const offset = featureListOffset + reader.u16();
38401
+ records.push({ tag, offset });
38402
+ }
38403
+ return records.map(({ tag, offset }) => {
38404
+ reader.seek(offset);
38405
+ reader.skip(2);
38406
+ const lookupIndexCount = reader.u16();
38407
+ const lookupIndices = new Array(lookupIndexCount);
38408
+ for (let i = 0; i < lookupIndexCount; i += 1) {
38409
+ lookupIndices[i] = reader.u16();
38410
+ }
38411
+ return { tag, lookupIndices };
38412
+ });
38413
+ }
38414
+ function parseScriptList(reader, scriptListOffset) {
38415
+ reader.seek(scriptListOffset);
38416
+ const scriptCount = reader.u16();
38417
+ const scripts = [];
38418
+ for (let i = 0; i < scriptCount; i += 1) {
38419
+ const tag = readTag(reader);
38420
+ const offset = scriptListOffset + reader.u16();
38421
+ scripts.push({ tag, offset });
38422
+ }
38423
+ if (scripts.length === 0) return [];
38424
+ const chosen = scripts.find((s) => s.tag === "latn") ?? scripts.find((s) => s.tag === "DFLT") ?? scripts[0];
38425
+ reader.seek(chosen.offset);
38426
+ const defaultLangSysOffset = reader.u16();
38427
+ if (defaultLangSysOffset === 0) return [];
38428
+ reader.seek(chosen.offset + defaultLangSysOffset);
38429
+ reader.skip(2);
38430
+ const requiredFeatureIndex = reader.u16();
38431
+ const featureIndexCount = reader.u16();
38432
+ const featureIndices = [];
38433
+ if (requiredFeatureIndex !== 65535) {
38434
+ featureIndices.push(requiredFeatureIndex);
38435
+ }
38436
+ for (let i = 0; i < featureIndexCount; i += 1) {
38437
+ featureIndices.push(reader.u16());
38438
+ }
38439
+ return featureIndices;
38440
+ }
38441
+ function parseLookupList(reader, lookupListOffset) {
38442
+ reader.seek(lookupListOffset);
38443
+ const lookupCount = reader.u16();
38444
+ const lookupOffsets = new Array(lookupCount);
38445
+ for (let i = 0; i < lookupCount; i += 1) {
38446
+ lookupOffsets[i] = lookupListOffset + reader.u16();
38447
+ }
38448
+ return lookupOffsets.map((lookupOffset) => {
38449
+ reader.seek(lookupOffset);
38450
+ const lookupType = reader.u16();
38451
+ reader.skip(2);
38452
+ const subTableCount = reader.u16();
38453
+ const subtableOffsets = new Array(subTableCount);
38454
+ for (let i = 0; i < subTableCount; i += 1) {
38455
+ subtableOffsets[i] = lookupOffset + reader.u16();
38456
+ }
38457
+ const subtables = [];
38458
+ for (const subtableOffset of subtableOffsets) {
38459
+ try {
38460
+ const subtable = parseSubtable(reader, subtableOffset, lookupType);
38461
+ if (subtable) subtables.push(subtable);
38462
+ } catch {
38463
+ }
38464
+ }
38465
+ return { lookupType, subtables };
38466
+ });
38467
+ }
38468
+ class OpenTypeLayouter {
38469
+ constructor(font) {
38470
+ __publicField(this, "gsub");
38471
+ this.font = font;
38472
+ const raw = font.getRawTableData("GSUB");
38473
+ this.gsub = raw ? GsubTable.parse(raw) : null;
38474
+ }
38475
+ /** True when the font exposes a GSUB table the shaper could use. */
38476
+ get hasGsub() {
38477
+ return this.gsub !== null;
38478
+ }
38479
+ layout(text, features) {
38480
+ const buffer = [];
38481
+ for (const char of text) {
38482
+ const codePoint = char.codePointAt(0) ?? 65533;
38483
+ const glyphId = this.font.glyphForCodePoint(codePoint);
38484
+ buffer.push({
38485
+ id: glyphId,
38486
+ codePoints: glyphId === 0 ? [65533] : [codePoint]
38487
+ });
38488
+ }
38489
+ if (this.gsub && features && features.length > 0) {
38490
+ this.gsub.shape(buffer, features);
38491
+ }
38492
+ const glyphs = [];
38493
+ const positions = [];
38494
+ let advanceWidth = 0;
38495
+ for (const glyph of buffer) {
38496
+ const glyphAdvance = this.font.advanceWidthForGlyph(glyph.id);
38497
+ glyphs.push({
38498
+ id: glyph.id,
38499
+ codePoints: glyph.codePoints,
38500
+ advanceWidth: glyphAdvance
38501
+ });
38502
+ positions.push({ xAdvance: glyphAdvance });
38503
+ advanceWidth += glyphAdvance;
38504
+ }
38505
+ return { glyphs, positions, advanceWidth };
38506
+ }
38507
+ }
37829
38508
  class SimpleTextLayouter {
37830
38509
  constructor(font) {
37831
38510
  this.font = font;
@@ -38041,9 +38720,11 @@ function parseEmbeddedFontSync(sourceBytes) {
38041
38720
  return SfntFontProgram.parse(sfntBytes);
38042
38721
  }
38043
38722
  function createPdfEmbeddableFont(program) {
38723
+ const shaper = new OpenTypeLayouter(program);
38724
+ const layouter = shaper.hasGsub ? shaper : new SimpleTextLayouter(program);
38044
38725
  return {
38045
38726
  program,
38046
- layouter: new SimpleTextLayouter(program),
38727
+ layouter,
38047
38728
  subsetter: new TrueTypePdfFontSubsetter()
38048
38729
  };
38049
38730
  }
@@ -38091,8 +38772,8 @@ class PdfFontTable {
38091
38772
  * Unicode run, recording the glyphs used for subsetting. Returns `null` when
38092
38773
  * the run produced no glyphs so the caller can skip emission entirely.
38093
38774
  */
38094
- buildUnicodeShowCommand(state, text) {
38095
- const run = this.layoutUnicodeText(state, text);
38775
+ buildUnicodeShowCommand(state, text, features) {
38776
+ const run = this.layoutUnicodeText(state, text, features);
38096
38777
  const encoded = this.encodeUnicodeGlyphRun(state, run);
38097
38778
  if (encoded.length === 0) {
38098
38779
  return null;
@@ -38126,13 +38807,14 @@ class PdfFontTable {
38126
38807
  const resourceXml = fontResourceEntries.map((font, index) => `/${font.resourceName} ${fontObjectIds[index]} 0 R`).join(" ");
38127
38808
  return { resourceXml };
38128
38809
  }
38129
- layoutUnicodeText(state, text) {
38130
- const cached = state.layoutCache.get(text);
38810
+ layoutUnicodeText(state, text, features) {
38811
+ const cacheKey = `${(features == null ? void 0 : features.join(",")) ?? ""}\0${text}`;
38812
+ const cached = state.layoutCache.get(cacheKey);
38131
38813
  if (cached) {
38132
38814
  return cached;
38133
38815
  }
38134
- const run = state.font.layouter.layout(text);
38135
- state.layoutCache.set(text, run);
38816
+ const run = state.font.layouter.layout(text, features);
38817
+ state.layoutCache.set(cacheKey, run);
38136
38818
  return run;
38137
38819
  }
38138
38820
  encodeUnicodeGlyphRun(state, run) {