@docx4j/core-ts 0.1.0 → 0.1.1
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/README.md +410 -10
- package/dist/model/content/Body.d.mts +109 -4
- package/dist/model/content/Body.mjs +300 -29
- package/dist/model/content/Comment.d.mts +78 -0
- package/dist/model/content/Comment.mjs +429 -0
- package/dist/model/content/ContentControl.d.mts +173 -0
- package/dist/model/content/ContentControl.mjs +638 -0
- package/dist/model/content/Font.d.mts +48 -8
- package/dist/model/content/Font.mjs +55 -13
- package/dist/model/content/InlinePicture.d.mts +103 -0
- package/dist/model/content/InlinePicture.mjs +361 -0
- package/dist/model/content/List.d.mts +253 -0
- package/dist/model/content/List.mjs +778 -0
- package/dist/model/content/Paragraph.d.mts +213 -16
- package/dist/model/content/Paragraph.mjs +611 -57
- package/dist/model/content/Range.d.mts +48 -4
- package/dist/model/content/Range.mjs +161 -4
- package/dist/model/content/Table.d.mts +130 -0
- package/dist/model/content/Table.mjs +429 -0
- package/dist/model/content/TrackedChange.d.mts +96 -0
- package/dist/model/content/TrackedChange.mjs +352 -0
- package/dist/model/content/comments.d.mts +122 -0
- package/dist/model/content/comments.mjs +248 -0
- package/dist/model/content/index.d.mts +13 -3
- package/dist/model/content/index.mjs +15 -3
- package/dist/model/content/ooxml.d.mts +17 -0
- package/dist/model/content/ooxml.mjs +214 -0
- package/dist/model/content/styles.d.mts +21 -0
- package/dist/model/content/styles.mjs +86 -0
- package/dist/model/content/tracking.d.mts +104 -0
- package/dist/model/content/tracking.mjs +313 -0
- package/dist/model/content/tree.d.mts +56 -9
- package/dist/model/content/tree.mjs +104 -31
- package/dist/model/customxml/CustomXmlPart.d.mts +158 -0
- package/dist/model/customxml/CustomXmlPart.mjs +415 -0
- package/dist/model/customxml/CustomXmlPartCollection.d.mts +68 -0
- package/dist/model/customxml/CustomXmlPartCollection.mjs +183 -0
- package/dist/model/customxml/XmlMapping.d.mts +46 -0
- package/dist/model/customxml/XmlMapping.mjs +98 -0
- package/dist/model/customxml/bindings.d.mts +41 -0
- package/dist/model/customxml/bindings.mjs +230 -0
- package/dist/model/customxml/index.d.mts +7 -0
- package/dist/model/customxml/index.mjs +9 -0
- package/dist/model/customxml/insert.d.mts +20 -0
- package/dist/model/customxml/insert.mjs +22 -0
- package/dist/model/customxml/kinds.d.mts +103 -0
- package/dist/model/customxml/kinds.mjs +267 -0
- package/dist/model/customxml/xpath.d.mts +52 -0
- package/dist/model/customxml/xpath.mjs +205 -0
- package/dist/model/fonts/CJKToEnglish.d.mts +2 -0
- package/dist/model/fonts/CJKToEnglish.mjs +16 -0
- package/dist/model/fonts/FontFallback.d.mts +58 -0
- package/dist/model/fonts/FontFallback.mjs +219 -0
- package/dist/model/fonts/IdentityPlusMapper.d.mts +7 -0
- package/dist/model/fonts/IdentityPlusMapper.mjs +19 -0
- package/dist/model/fonts/LanguageTagToScriptMapping.d.mts +7 -0
- package/dist/model/fonts/LanguageTagToScriptMapping.mjs +67 -0
- package/dist/model/fonts/Mapper.d.mts +190 -0
- package/dist/model/fonts/Mapper.mjs +481 -0
- package/dist/model/fonts/PhysicalFont.d.mts +34 -0
- package/dist/model/fonts/PhysicalFont.mjs +62 -0
- package/dist/model/fonts/RunFontSelector.d.mts +194 -0
- package/dist/model/fonts/RunFontSelector.mjs +441 -0
- package/dist/model/fonts/ThemeFonts.d.mts +17 -0
- package/dist/model/fonts/ThemeFonts.mjs +76 -0
- package/dist/model/fonts/defaultTheme.d.mts +37 -0
- package/dist/model/fonts/defaultTheme.mjs +57 -0
- package/dist/model/fonts/families.generated.d.mts +11 -0
- package/dist/model/fonts/families.generated.mjs +17 -0
- package/dist/model/fonts/fontsInUse.d.mts +39 -0
- package/dist/model/fonts/fontsInUse.mjs +183 -0
- package/dist/model/fonts/index.d.mts +14 -0
- package/dist/model/fonts/index.mjs +29 -0
- package/dist/model/fonts/lookup.d.mts +5 -0
- package/dist/model/fonts/lookup.mjs +12 -0
- package/dist/model/fonts/registry.d.mts +31 -0
- package/dist/model/fonts/registry.mjs +103 -0
- package/dist/model/fonts/scripts.d.mts +2 -0
- package/dist/model/fonts/scripts.mjs +78 -0
- package/dist/model/fonts/substitutions.generated.d.mts +30 -0
- package/dist/model/fonts/substitutions.generated.mjs +12 -0
- package/dist/model/fonts/themes.generated.d.mts +6 -0
- package/dist/model/fonts/themes.generated.mjs +11 -0
- package/dist/model/index.d.mts +5 -0
- package/dist/model/index.mjs +13 -1
- package/dist/model/listnumbering/Emulator.d.mts +187 -0
- package/dist/model/listnumbering/Emulator.mjs +332 -0
- package/dist/model/listnumbering/definitions.d.mts +251 -0
- package/dist/model/listnumbering/definitions.mjs +571 -0
- package/dist/model/listnumbering/formats.d.mts +25 -0
- package/dist/model/listnumbering/formats.mjs +320 -0
- package/dist/model/listnumbering/index.d.mts +4 -0
- package/dist/model/listnumbering/index.mjs +15 -0
- package/dist/model/listnumbering/state.d.mts +97 -0
- package/dist/model/listnumbering/state.mjs +179 -0
- package/dist/model/properties/PropertyResolver.d.mts +216 -0
- package/dist/model/properties/PropertyResolver.mjs +524 -0
- package/dist/model/properties/catalogue.d.mts +179 -0
- package/dist/model/properties/catalogue.mjs +860 -0
- package/dist/model/properties/index.d.mts +4 -0
- package/dist/model/properties/index.mjs +9 -0
- package/dist/model/properties/log.d.mts +7 -0
- package/dist/model/properties/log.mjs +25 -0
- package/dist/model/properties/styleUtil.d.mts +112 -0
- package/dist/model/properties/styleUtil.mjs +359 -0
- package/dist/node/index.d.mts +1 -0
- package/dist/node/index.mjs +12 -0
- package/dist/office-js/document.d.mts +111 -0
- package/dist/office-js/document.mjs +267 -0
- package/dist/office-js/enums.d.mts +187 -0
- package/dist/office-js/enums.mjs +176 -0
- package/dist/office-js/errors.d.mts +29 -0
- package/dist/office-js/errors.mjs +39 -0
- package/dist/office-js/extras.d.mts +5 -0
- package/dist/office-js/extras.mjs +29 -0
- package/dist/office-js/fragment.d.mts +10 -0
- package/dist/office-js/fragment.mjs +23 -0
- package/dist/office-js/index.d.mts +183 -0
- package/dist/office-js/index.mjs +54 -0
- package/dist/office-js/proxy.d.mts +72 -0
- package/dist/office-js/proxy.mjs +279 -0
- package/dist/office-js/run.d.mts +32 -0
- package/dist/office-js/run.mjs +66 -0
- package/dist/office-js/supported.d.mts +7 -0
- package/dist/office-js/supported.generated.d.mts +1 -0
- package/dist/office-js/supported.generated.mjs +235 -0
- package/dist/office-js/supported.mjs +53 -0
- package/dist/office-js/toApiScript.d.mts +25 -0
- package/dist/office-js/toApiScript.mjs +394 -0
- package/dist/opc/ContentTypes.d.mts +1 -0
- package/dist/opc/ContentTypes.mjs +1 -0
- package/dist/opc/DirectoryPartStore.d.mts +47 -0
- package/dist/opc/DirectoryPartStore.mjs +123 -0
- package/dist/opc/exceptions.d.mts +30 -0
- package/dist/opc/exceptions.mjs +38 -0
- package/dist/opc/index.d.mts +1 -1
- package/dist/opc/index.mjs +1 -1
- package/dist/packages/OpcPackage.d.mts +19 -1
- package/dist/packages/OpcPackage.mjs +29 -0
- package/dist/packages/PresentationMLPackage.d.mts +71 -1
- package/dist/packages/PresentationMLPackage.mjs +179 -0
- package/dist/packages/SpreadsheetMLPackage.d.mts +30 -1
- package/dist/packages/SpreadsheetMLPackage.mjs +78 -0
- package/dist/packages/WordprocessingMLPackage.d.mts +124 -2
- package/dist/packages/WordprocessingMLPackage.mjs +309 -2
- package/dist/packages/index.d.mts +1 -1
- package/dist/packages/index.mjs +1 -1
- package/dist/parts/DefaultXmlPart.d.mts +18 -0
- package/dist/parts/DefaultXmlPart.mjs +34 -5
- package/dist/parts/PartRegistry.mjs +1 -0
- package/dist/parts/XmlPart.d.mts +33 -0
- package/dist/parts/XmlPart.mjs +105 -2
- package/dist/parts/pml/defaults.d.mts +6 -0
- package/dist/parts/pml/defaults.mjs +53 -0
- package/dist/parts/pml/index.d.mts +66 -3
- package/dist/parts/pml/index.mjs +206 -7
- package/dist/parts/pml/placeholders.d.mts +71 -0
- package/dist/parts/pml/placeholders.mjs +141 -0
- package/dist/parts/sml/index.d.mts +19 -1
- package/dist/parts/sml/index.mjs +60 -1
- package/dist/parts/wml/comments.d.mts +1 -0
- package/dist/parts/wml/comments.mjs +179 -0
- package/dist/parts/wml/defaultNumbering.d.mts +1 -0
- package/dist/parts/wml/defaultNumbering.mjs +216 -0
- package/dist/parts/wml/index.d.mts +121 -0
- package/dist/parts/wml/index.mjs +291 -0
- package/dist/xml/dom.mjs +1 -2
- package/package.json +25 -4
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { VCL_ENTRIES } from './substitutions.generated.mjs';
|
|
2
|
+
import { scriptOf } from './scripts.mjs';
|
|
3
|
+
/** The key convention `FontSubstitutions.xml` uses: the name lower-cased, everything but
|
|
4
|
+
* letters and digits removed. */
|
|
5
|
+
export function shortKey(fontName) {
|
|
6
|
+
let key = '';
|
|
7
|
+
for (const c of fontName) {
|
|
8
|
+
// Character.isLetterOrDigit over the whole of Unicode, which is what docx4j's key() uses
|
|
9
|
+
if (/[\p{L}\p{Nd}]/u.test(c))
|
|
10
|
+
key += c.toLowerCase();
|
|
11
|
+
}
|
|
12
|
+
return key;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The `FontSubstitutions.xml` entry for this name, or undefined. The table knows families,
|
|
16
|
+
* not the foundry and weight suffixes a document adds to them ("Calisto MT", "Segoe UI
|
|
17
|
+
* Light"), so trailing words are dropped one at a time until one matches.
|
|
18
|
+
*/
|
|
19
|
+
export function vclEntryFor(documentFontName) {
|
|
20
|
+
if (documentFontName === undefined || documentFontName === null)
|
|
21
|
+
return undefined;
|
|
22
|
+
const direct = VCL_ENTRIES[shortKey(documentFontName)];
|
|
23
|
+
if (direct)
|
|
24
|
+
return direct;
|
|
25
|
+
const words = documentFontName.trim().split(/\s+/);
|
|
26
|
+
for (let drop = 1; drop < words.length; drop++) {
|
|
27
|
+
const entry = VCL_ENTRIES[shortKey(words.slice(0, words.length - drop).join(''))];
|
|
28
|
+
if (entry)
|
|
29
|
+
return entry;
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
/** Whether `FontSubstitutions.xml` calls this font condensed (Arial Narrow and the like): no
|
|
34
|
+
* ordinary stand-in has its widths, and docx4j's corpus showed the document default is the
|
|
35
|
+
* lesser evil, so these are deliberately left unmapped. */
|
|
36
|
+
export function isCondensed(documentFontName) {
|
|
37
|
+
const entry = vclEntryFor(documentFontName);
|
|
38
|
+
if (entry && entry.fontWidth.toLowerCase().includes('condensed'))
|
|
39
|
+
return true;
|
|
40
|
+
const n = (documentFontName !== null && documentFontName !== void 0 ? documentFontName : '').toLowerCase();
|
|
41
|
+
return n.includes('narrow') || n.includes('condensed');
|
|
42
|
+
}
|
|
43
|
+
/** `.+-(bold|italic|...)(mt|ps)?`: a PostScript name, which no system has a family by, so
|
|
44
|
+
* Word does not resolve it either and falls back to the document default. */
|
|
45
|
+
const POSTSCRIPT_NAME = /^.+-(bold|italic|bolditalic|regular|roman|light|medium|semibold|demibold|black|oblique)(mt|ps)?$/;
|
|
46
|
+
/** Families measured to be better off falling back to the document default than to a stand-in
|
|
47
|
+
* of their own class, because the stand-in's widths are further from theirs than the
|
|
48
|
+
* default's are. Kept short and evidence-based, as docx4j's is. */
|
|
49
|
+
function leaveUnmapped(documentFontName) {
|
|
50
|
+
if (documentFontName === undefined)
|
|
51
|
+
return false;
|
|
52
|
+
const n = documentFontName.toLowerCase();
|
|
53
|
+
// Lato is a narrow humanist sans; Arimo (Arial's widths) set a Lato document a page longer
|
|
54
|
+
if (n.startsWith('lato'))
|
|
55
|
+
return true;
|
|
56
|
+
return POSTSCRIPT_NAME.test(n);
|
|
57
|
+
}
|
|
58
|
+
/** Whether this family is one docx4j deliberately leaves to the document default rather than
|
|
59
|
+
* standing in for it: a condensed face, or one of the measured exceptions. */
|
|
60
|
+
export function leftToTheDocumentDefault(documentFontName) {
|
|
61
|
+
return isCondensed(documentFontName) || leaveUnmapped(documentFontName);
|
|
62
|
+
}
|
|
63
|
+
/** The class `FontSubstitutions.xml` gives this font, or undefined where it does not say. */
|
|
64
|
+
function classFromTable(documentFontName) {
|
|
65
|
+
const entry = vclEntryFor(documentFontName);
|
|
66
|
+
if (!entry || entry.fontType.length === 0)
|
|
67
|
+
return undefined;
|
|
68
|
+
const type = entry.fontType.toLowerCase();
|
|
69
|
+
// CJK, Symbol, Special, Decorative and Script faces have no stand-in of "their class"
|
|
70
|
+
if (type.includes('cjk') || type.includes('symbol') || type.includes('special')
|
|
71
|
+
|| type.includes('decorative') || type.includes('script') || type.includes('ctl'))
|
|
72
|
+
return 'UNKNOWN';
|
|
73
|
+
if (type.includes('fixed') || type.includes('typewriter'))
|
|
74
|
+
return 'MONO';
|
|
75
|
+
if (type.includes('sansserif'))
|
|
76
|
+
return 'SANS';
|
|
77
|
+
if (type.includes('serif'))
|
|
78
|
+
return 'SERIF';
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
const MONO_WORDS = ['cousine', 'monospace', 'courier', 'consol', 'typewriter', 'terminal',
|
|
82
|
+
'fixedsys', 'inconsolata', 'menlo'];
|
|
83
|
+
// NB no bare "gothic": in a Microsoft font name it is as often Japanese (MS Gothic, Yu Gothic)
|
|
84
|
+
// as it is a sans. "urw gothic" is the whole family name of the Avant Garde clone.
|
|
85
|
+
const SANS_WORDS = ['arimo', 'carlito', 'cantarell', 'helvetica', 'arial', 'urw gothic',
|
|
86
|
+
'selawik', 'verdana', 'tahoma', 'segoe', 'gadugi', 'trebuchet', 'calibri', 'grotesk',
|
|
87
|
+
'grotesque', 'futura', 'frutiger', 'myriad', 'univers', 'avenir', 'lato', 'roboto',
|
|
88
|
+
'franklin', 'open sans'];
|
|
89
|
+
// "p052" and "c059" are the URW Palatino and Century Schoolbook clones, "gelasio" Georgia's.
|
|
90
|
+
const SERIF_WORDS = ['tinos', 'caladea', 'charter', 'times', 'georgia', 'gelasio', 'garamond',
|
|
91
|
+
'palatino', 'p052', 'c059', 'bookman', 'book antiqua', 'cambria', 'constantia', 'century',
|
|
92
|
+
'baskerville', 'caslon', 'utopia', 'minion', 'sylfaen', 'roman'];
|
|
93
|
+
/**
|
|
94
|
+
* The class a name says, sans before serif so that "HelveticaNeue LT 55 Roman" is a sans.
|
|
95
|
+
*
|
|
96
|
+
* @param generic whether a name which only ends in "Sans" or "Serif" counts. It does when the
|
|
97
|
+
* question is what class an installed font is (Liberation Sans, DejaVu Serif), but not when
|
|
98
|
+
* it is whether to stand in for a document font: measured, that guess was worth less than the
|
|
99
|
+
* document default.
|
|
100
|
+
*/
|
|
101
|
+
export function classFromName(documentFontName, generic = true) {
|
|
102
|
+
if (documentFontName === undefined)
|
|
103
|
+
return 'UNKNOWN';
|
|
104
|
+
const n = documentFontName.toLowerCase();
|
|
105
|
+
for (const mono of MONO_WORDS)
|
|
106
|
+
if (n.includes(mono))
|
|
107
|
+
return 'MONO';
|
|
108
|
+
// "mono" only as a word: Monotype Corsiva is a script face, not a monospace one
|
|
109
|
+
for (const word of n.split(/[^a-z0-9]+/))
|
|
110
|
+
if (word === 'mono')
|
|
111
|
+
return 'MONO';
|
|
112
|
+
for (const sans of SANS_WORDS)
|
|
113
|
+
if (n.includes(sans))
|
|
114
|
+
return 'SANS';
|
|
115
|
+
for (const serif of SERIF_WORDS)
|
|
116
|
+
if (n.includes(serif))
|
|
117
|
+
return 'SERIF';
|
|
118
|
+
if (generic) {
|
|
119
|
+
if (n.includes('sans'))
|
|
120
|
+
return 'SANS';
|
|
121
|
+
if (n.includes('serif'))
|
|
122
|
+
return 'SERIF';
|
|
123
|
+
}
|
|
124
|
+
return 'UNKNOWN';
|
|
125
|
+
}
|
|
126
|
+
/** The font's class, from `FontSubstitutions.xml` where it knows the font, else from its name. */
|
|
127
|
+
export function classOf(documentFontName) {
|
|
128
|
+
var _a;
|
|
129
|
+
return (_a = classFromTable(documentFontName)) !== null && _a !== void 0 ? _a : classFromName(documentFontName);
|
|
130
|
+
}
|
|
131
|
+
/** The class to stand in for: the table's word, else what the name says for certain. */
|
|
132
|
+
export function substitutionClass(documentFontName) {
|
|
133
|
+
var _a;
|
|
134
|
+
return (_a = classFromTable(documentFontName)) !== null && _a !== void 0 ? _a : classFromName(documentFontName, false);
|
|
135
|
+
}
|
|
136
|
+
const SANS_DEFAULTS = ['Arimo Regular', 'Arimo', 'Liberation Sans', 'Nimbus Sans', 'DejaVu Sans',
|
|
137
|
+
'Noto Sans', 'FreeSans'];
|
|
138
|
+
const SERIF_DEFAULTS = ['Tinos Regular', 'Tinos', 'Liberation Serif', 'Nimbus Roman',
|
|
139
|
+
'DejaVu Serif', 'Noto Serif', 'FreeSerif'];
|
|
140
|
+
const MONO_DEFAULTS = ['Cousine Regular', 'Cousine', 'Liberation Mono', 'Nimbus Mono PS',
|
|
141
|
+
'DejaVu Sans Mono', 'Noto Mono', 'FreeMono'];
|
|
142
|
+
function defaultsFor(fontClass) {
|
|
143
|
+
switch (fontClass) {
|
|
144
|
+
case 'SANS': return SANS_DEFAULTS;
|
|
145
|
+
case 'SERIF': return SERIF_DEFAULTS;
|
|
146
|
+
case 'MONO': return MONO_DEFAULTS;
|
|
147
|
+
default: return [];
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/** The families `FontSubstitutions.xml` offers for this font, in its order, as short keys. */
|
|
151
|
+
function vclSubstituteKeys(documentFontName) {
|
|
152
|
+
const entry = vclEntryFor(documentFontName);
|
|
153
|
+
if (!entry || entry.substFonts.length === 0)
|
|
154
|
+
return [];
|
|
155
|
+
return entry.substFonts.split(';').map(shortKey).filter((k) => k.length > 0);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* A physical font of this document font's class, without regard to what it can render. Used
|
|
159
|
+
* where the characters are Latin (or Greek/Cyrillic), which any of these covers.
|
|
160
|
+
*
|
|
161
|
+
* `FontSubstitutions.xml`'s own list first - it is ordered by closeness - then the class
|
|
162
|
+
* defaults. Undefined where the font's class is unknown, or it is condensed or one of the
|
|
163
|
+
* measured exceptions, or the registry has nothing of that class.
|
|
164
|
+
*/
|
|
165
|
+
export function selectByClass(registry, documentFontName) {
|
|
166
|
+
if (documentFontName === undefined)
|
|
167
|
+
return undefined;
|
|
168
|
+
if (isCondensed(documentFontName) || leaveUnmapped(documentFontName))
|
|
169
|
+
return undefined;
|
|
170
|
+
const fontClass = substitutionClass(documentFontName);
|
|
171
|
+
if (fontClass === 'UNKNOWN')
|
|
172
|
+
return undefined;
|
|
173
|
+
const byKey = new Map();
|
|
174
|
+
for (const font of registry.all())
|
|
175
|
+
byKey.set(shortKey(font.name), font);
|
|
176
|
+
for (const candidate of vclSubstituteKeys(documentFontName)) {
|
|
177
|
+
const pf = byKey.get(candidate);
|
|
178
|
+
if (pf && classOf(pf.name) === fontClass)
|
|
179
|
+
return pf;
|
|
180
|
+
}
|
|
181
|
+
for (const candidate of defaultsFor(fontClass)) {
|
|
182
|
+
const pf = registry.get(candidate);
|
|
183
|
+
if (pf)
|
|
184
|
+
return pf;
|
|
185
|
+
}
|
|
186
|
+
return undefined;
|
|
187
|
+
}
|
|
188
|
+
// ---------------------------------------------------------------------- coverage groups
|
|
189
|
+
//
|
|
190
|
+
// Used by `RunFontSelector.spanScript`, which cuts a span where the script changes.
|
|
191
|
+
/** U+2190-U+2BFF, the symbol blocks: Arrows, Mathematical Operators, Miscellaneous Technical,
|
|
192
|
+
* Box Drawing, Block Elements, Geometric Shapes, Miscellaneous Symbols, Dingbats, Braille and
|
|
193
|
+
* the supplemental arrow and maths blocks. Every one of them is `COMMON`, so they are their
|
|
194
|
+
* own group rather than shared: the space and the digits beside an arrow are not dragged into
|
|
195
|
+
* the symbol font with it. */
|
|
196
|
+
export function isSymbol(cp) {
|
|
197
|
+
return cp >= 0x2190 && cp <= 0x2BFF;
|
|
198
|
+
}
|
|
199
|
+
/** U+1F000-U+1FAFF, the emoji blocks (`COMMON`, and like the symbols a group of their own). */
|
|
200
|
+
export function isEmoji(cp) {
|
|
201
|
+
return cp >= 0x1F000 && cp <= 0x1FAFF;
|
|
202
|
+
}
|
|
203
|
+
/** The East Asian punctuation and form blocks, which are `COMMON` - a fullwidth comma U+FF0C,
|
|
204
|
+
* an ideographic comma U+3001 - and which a Latin face does not have. */
|
|
205
|
+
export function isEastAsianForm(cp) {
|
|
206
|
+
return (cp >= 0x2E80 && cp <= 0x33FF) || (cp >= 0xFE10 && cp <= 0xFE4F)
|
|
207
|
+
|| (cp >= 0xFF00 && cp <= 0xFFEF);
|
|
208
|
+
}
|
|
209
|
+
export const SYMBOL_GROUP = 'SYMBOL';
|
|
210
|
+
export const EMOJI_GROUP = 'EMOJI';
|
|
211
|
+
/** The key a code point groups under: its Unicode script, except that the symbol and emoji
|
|
212
|
+
* blocks are their own groups. */
|
|
213
|
+
export function coverageGroupOf(cp) {
|
|
214
|
+
if (isSymbol(cp))
|
|
215
|
+
return SYMBOL_GROUP;
|
|
216
|
+
if (isEmoji(cp))
|
|
217
|
+
return EMOJI_GROUP;
|
|
218
|
+
return scriptOf(cp);
|
|
219
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type * as wml from '@docx4j/generated-objects-ts/modules/org_docx4j_wml';
|
|
2
|
+
import { Mapper } from './Mapper.mjs';
|
|
3
|
+
import type { PhysicalFont } from './PhysicalFont.mjs';
|
|
4
|
+
export declare class IdentityPlusMapper extends Mapper {
|
|
5
|
+
/** A variant of the name: "Noto Sans Symbols" is registered as "Noto Sans Symbols Regular". */
|
|
6
|
+
protected resolveDocumentFont(documentFontName: string, _fontTableEntry: wml.Fonts.Font | undefined): PhysicalFont | undefined;
|
|
7
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Mapper } from './Mapper.mjs';
|
|
2
|
+
/** The order a family whose plain face is absent is asked for. Bold before italic since
|
|
3
|
+
* docx4j 17.1.1: with italic first, "Franklin Gothic Demi" was set upright in Franklin Gothic
|
|
4
|
+
* Demi Italic, and a bold upright is nearer a missing regular than an italic is. */
|
|
5
|
+
const VARIANTS = [' regular', ' bold', ' italic', ' bold italic'];
|
|
6
|
+
export class IdentityPlusMapper extends Mapper {
|
|
7
|
+
/** A variant of the name: "Noto Sans Symbols" is registered as "Noto Sans Symbols Regular". */
|
|
8
|
+
resolveDocumentFont(documentFontName, _fontTableEntry) {
|
|
9
|
+
this.resolvedVia = undefined;
|
|
10
|
+
for (const variant of VARIANTS) {
|
|
11
|
+
const pf = this.registry.get(documentFontName + variant);
|
|
12
|
+
if (pf !== undefined) {
|
|
13
|
+
this.resolvedVia = `a variant of the name: ${documentFontName}${variant}`;
|
|
14
|
+
return pf;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The theme's `script` for a language tag, or undefined where the tag selects none (and the
|
|
3
|
+
* theme's `a:latin`, `a:ea` or `a:cs` answers instead). Chinese is decided on the region as
|
|
4
|
+
* well: mainland China and Singapore use simplified characters (`Hans`), everywhere else
|
|
5
|
+
* traditional (`Hant`).
|
|
6
|
+
*/
|
|
7
|
+
export declare function getScriptForLanguageTag(langTag: string | undefined): string | undefined;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// docx4j `org.docx4j.fonts.LanguageTagToScriptMapping`.
|
|
2
|
+
//
|
|
3
|
+
// Maps `w:themeFontLang` in the settings part - `<w:themeFontLang w:val="en-US"
|
|
4
|
+
// w:eastAsia="ko-KR"/>` - to the `script` attribute of an `a:font` in the theme part's font
|
|
5
|
+
// scheme (`<a:font script="Jpan" typeface="MS 明朝"/>`), so that `ThemePart.getFont` can pick
|
|
6
|
+
// the face for the document's language.
|
|
7
|
+
//
|
|
8
|
+
// **By exact subtag.** Until docx4j 17.1.1 this was a substring test over comma-separated
|
|
9
|
+
// lists, so Estonian (`et`) matched inside `eth` and took the Ethiopic face (Nyala), Mongolian
|
|
10
|
+
// (`mn`) inside `mni` the Bengali one, and Wolof (`wo`) inside `bwo`. CR-016 probe
|
|
11
|
+
// `fonts-theme-lang` measured Word: with `<w:themeFontLang w:val="et-EE"/>` and docDefaults
|
|
12
|
+
// naming `minorHAnsi`, Word sets the text in Calibri, the theme's Latin face, on every line.
|
|
13
|
+
/** The script a primary language subtag selects in a theme's font list. */
|
|
14
|
+
const SCRIPT_BY_LANGUAGE = new Map();
|
|
15
|
+
function put(script, ...langs) {
|
|
16
|
+
for (const lang of langs)
|
|
17
|
+
SCRIPT_BY_LANGUAGE.set(lang, script);
|
|
18
|
+
}
|
|
19
|
+
put('Jpan', 'ja');
|
|
20
|
+
put('Hang', 'ko');
|
|
21
|
+
put('Arab', 'ar');
|
|
22
|
+
put('Hebr', 'he', 'yi', 'iw');
|
|
23
|
+
put('Thai', 'th');
|
|
24
|
+
put('Ethi', 'ti', 'bwo', 'eth', 'kxh', 'mdy');
|
|
25
|
+
put('Beng', 'bn', 'as', 'mni');
|
|
26
|
+
put('Gujr', 'gu');
|
|
27
|
+
put('Khmr', 'km');
|
|
28
|
+
put('Knda', 'kn');
|
|
29
|
+
put('Guru', 'pa');
|
|
30
|
+
put('Cans', 'iu');
|
|
31
|
+
put('Cher', 'chr');
|
|
32
|
+
// Yiii (Microsoft Yi Baiti) omitted; see http://en.wikipedia.org/wiki/Yi_script
|
|
33
|
+
put('Tibt', 'bo');
|
|
34
|
+
put('Thaa', 'dv');
|
|
35
|
+
put('Deva', 'hi', 'ks', 'kok', 'mr', 'ne', 'sa', 'sd');
|
|
36
|
+
put('Telu', 'te');
|
|
37
|
+
put('Taml', 'ta');
|
|
38
|
+
put('Syrc', 'syr');
|
|
39
|
+
put('Orya', 'or');
|
|
40
|
+
put('Mlym', 'ml');
|
|
41
|
+
put('Laoo', 'lo');
|
|
42
|
+
put('Sinh', 'si');
|
|
43
|
+
// Mong (Mongolian Baiti) and Uigh (Microsoft Uighur) omitted, as in docx4j
|
|
44
|
+
put('Viet', 'vi', 'lha', 'nut');
|
|
45
|
+
put('Geor', 'ka');
|
|
46
|
+
/**
|
|
47
|
+
* The theme's `script` for a language tag, or undefined where the tag selects none (and the
|
|
48
|
+
* theme's `a:latin`, `a:ea` or `a:cs` answers instead). Chinese is decided on the region as
|
|
49
|
+
* well: mainland China and Singapore use simplified characters (`Hans`), everywhere else
|
|
50
|
+
* traditional (`Hant`).
|
|
51
|
+
*/
|
|
52
|
+
export function getScriptForLanguageTag(langTag) {
|
|
53
|
+
if (langTag === undefined || langTag === null)
|
|
54
|
+
return undefined;
|
|
55
|
+
let lang = langTag.trim();
|
|
56
|
+
let pos = lang.indexOf('-');
|
|
57
|
+
if (pos < 0)
|
|
58
|
+
pos = lang.indexOf('_');
|
|
59
|
+
if (pos > -1)
|
|
60
|
+
lang = lang.slice(0, pos);
|
|
61
|
+
lang = lang.toLowerCase();
|
|
62
|
+
if (lang === 'zh') {
|
|
63
|
+
const tag = langTag.toLowerCase();
|
|
64
|
+
return tag === 'zh-cn' || tag === 'zh-sg' ? 'Hans' : 'Hant';
|
|
65
|
+
}
|
|
66
|
+
return SCRIPT_BY_LANGUAGE.get(lang);
|
|
67
|
+
}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import type * as wml from '@docx4j/generated-objects-ts/modules/org_docx4j_wml';
|
|
2
|
+
import { PhysicalFont } from './PhysicalFont.mjs';
|
|
3
|
+
import { type FontRegistry } from './registry.mjs';
|
|
4
|
+
/** Which pass answered for a document font (docx4j `FontDecision.Source`). */
|
|
5
|
+
export type FontDecisionSource =
|
|
6
|
+
/** The environment has a font of that name. */
|
|
7
|
+
'INSTALLED'
|
|
8
|
+
/** The document embeds it (`w:embedRegular` and the rest). */
|
|
9
|
+
| 'EMBEDDED'
|
|
10
|
+
/** A metric-compatible clone from `font-substitutes.xml`: Word's advances. */
|
|
11
|
+
| 'METRIC_CLONE'
|
|
12
|
+
/** No clone exists; the closest face measured against Word's own PDF. */
|
|
13
|
+
| 'MEASURED_STAND_IN'
|
|
14
|
+
/** The document's own `w:altName`, resolved. */
|
|
15
|
+
| 'ALT_NAME'
|
|
16
|
+
/** A face of the same class: the widths are not the document font's. */
|
|
17
|
+
| 'CLASS'
|
|
18
|
+
/** What Word itself draws a font it cannot find. */
|
|
19
|
+
| 'WORD_DEFAULT'
|
|
20
|
+
/** The mapper's own answer: a variant of the name. */
|
|
21
|
+
| 'MAPPER_OWN'
|
|
22
|
+
/** A symbol font, drawn in the face that has the glyphs. */
|
|
23
|
+
| 'SYMBOL'
|
|
24
|
+
/** Nothing mapped it. */
|
|
25
|
+
| 'UNMAPPED';
|
|
26
|
+
/** What was decided for one document font, and why. */
|
|
27
|
+
export interface FontDecision {
|
|
28
|
+
/** The name as the document has it. */
|
|
29
|
+
readonly documentFont: string;
|
|
30
|
+
readonly source: FontDecisionSource;
|
|
31
|
+
/** How it got there - the `w:altName` chain, the class, Word's default family - or null
|
|
32
|
+
* where the source says it all. */
|
|
33
|
+
readonly via: string | null;
|
|
34
|
+
/** What is known of the substitute's width error, or null. */
|
|
35
|
+
readonly widthError: string | null;
|
|
36
|
+
/** The physical font as the mapping now stands; null where nothing mapped it. */
|
|
37
|
+
readonly physicalFont: PhysicalFont | null;
|
|
38
|
+
}
|
|
39
|
+
/** What the report says where nothing was measured. */
|
|
40
|
+
export declare const UNKNOWN_ERROR = "unknown";
|
|
41
|
+
/** Word's own fallback where a document font resolves to nothing at all. */
|
|
42
|
+
export declare const FONT_FALLBACK = "Times New Roman";
|
|
43
|
+
/** docx4j `WordLineMetrics.isEastAsianFamily`: the table's optional field 7. */
|
|
44
|
+
export declare function isEastAsianFamily(documentFont: string | undefined): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Whether docx4j's tables know this family: `MicrosoftFonts.xml`, `word-line-metrics` (512
|
|
47
|
+
* Microsoft and Office cloud families) or `FontSubstitutions.xml`.
|
|
48
|
+
*
|
|
49
|
+
* A known family the environment merely lacks is substituted for its widths (the passes before
|
|
50
|
+
* `addWordDefaultSubstitutes`), since Word on the author's machine had the font; an unknown one
|
|
51
|
+
* is what Word itself could not find either. "Known" is `substitutionClass`, **not** `classOf`,
|
|
52
|
+
* which will also guess a class from a name that merely ends in "Sans": docx4j measured a
|
|
53
|
+
* corporate face that fell between the two and was drawn in the document default's serif
|
|
54
|
+
* throughout. A family deliberately left to the document default is "known" for this purpose
|
|
55
|
+
* too, the measurement that put it there being that the default beat a stand-in.
|
|
56
|
+
*/
|
|
57
|
+
export declare function isKnownFamily(documentFontName: string | undefined): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Whether this document font has a bold face of its own: the `MicrosoftFonts.xml` entry where
|
|
60
|
+
* there is one (Franklin Gothic Book has none), else a family whose name ends in a weight word
|
|
61
|
+
* (Calibri Light, Segoe UI Semibold, Arial Black) is a single weight in Windows' font model and
|
|
62
|
+
* has none; any other family is taken to have one.
|
|
63
|
+
*/
|
|
64
|
+
export declare function hasBoldFace(documentFontName: string | undefined): boolean;
|
|
65
|
+
/** The font table keyed by lower-cased name. */
|
|
66
|
+
export declare function fontTableOf(fonts: wml.Fonts | undefined): Map<string, wml.Fonts.Font>;
|
|
67
|
+
/**
|
|
68
|
+
* The font Word draws an unknown font in, by its fontTable entry: measured (docx4j CR-016
|
|
69
|
+
* probe `fonts-unresolvable`, Word 365) a face whose entry says `w:family="roman"` is drawn in
|
|
70
|
+
* **Cambria**, one saying `swiss` in **Calibri**, one with an entry that names no family in
|
|
71
|
+
* Calibri, one with no fontTable entry at all in Cambria; an exact panose does not change that
|
|
72
|
+
* (Arial's gave Calibri), and the document's default font is never used.
|
|
73
|
+
*/
|
|
74
|
+
export declare function wordDefaultFor(documentFontName: string, table: Map<string, wml.Fonts.Font>): string;
|
|
75
|
+
/**
|
|
76
|
+
* Maps the document's font names to physical fonts, over a {@link FontRegistry} the caller
|
|
77
|
+
* supplies. One per package, as in docx4j.
|
|
78
|
+
*/
|
|
79
|
+
export declare abstract class Mapper {
|
|
80
|
+
/** The fonts the consumer has; the docx4j font jars' faces where nothing is given, which
|
|
81
|
+
* is the environment the parity goldens were made in. */
|
|
82
|
+
readonly registry: FontRegistry;
|
|
83
|
+
constructor(
|
|
84
|
+
/** The fonts the consumer has; the docx4j font jars' faces where nothing is given, which
|
|
85
|
+
* is the environment the parity goldens were made in. */
|
|
86
|
+
registry?: FontRegistry);
|
|
87
|
+
/** The mapping, keyed by the lower-cased document font name. */
|
|
88
|
+
private readonly fontMappings;
|
|
89
|
+
/** The document's embedded faces, keyed by the name the font table part uses. */
|
|
90
|
+
private readonly regularForms;
|
|
91
|
+
private readonly boldForms;
|
|
92
|
+
private readonly italicForms;
|
|
93
|
+
private readonly boldItalicForms;
|
|
94
|
+
private readonly decisions;
|
|
95
|
+
/** The document fonts `addWordDefaultSubstitutes` mapped: Word substitutes such a font whole,
|
|
96
|
+
* bold face included, so `addNoBoldFaceAliases` leaves them alone. */
|
|
97
|
+
private readonly wordDefaulted;
|
|
98
|
+
private readonly lineMetricsAliases;
|
|
99
|
+
/** The physical font a document font maps to, by case-insensitive name; undefined for a slot
|
|
100
|
+
* nothing names (docx4j `Mapper.get`, which tolerates null since 17.1.1). */
|
|
101
|
+
get(key: string | undefined | null): PhysicalFont | undefined;
|
|
102
|
+
put(key: string, pf: PhysicalFont): void;
|
|
103
|
+
get size(): number;
|
|
104
|
+
/** What was decided for this document font, or undefined where no pass met it. */
|
|
105
|
+
getDecision(documentFont: string | undefined): FontDecision | undefined;
|
|
106
|
+
/** Every decision, ordered by the document font's name (case-insensitively), so that two
|
|
107
|
+
* runs over the same document give the same list. */
|
|
108
|
+
getDecisions(): FontDecision[];
|
|
109
|
+
/** Whose Word line metrics a document font takes, where a pass resolved it through another
|
|
110
|
+
* family; undefined where it takes its own. Per mapper, i.e. per package: docx4j's was a
|
|
111
|
+
* JVM-wide map until 17.1.1, and one document's `w:altName` answered for every later one. */
|
|
112
|
+
lineMetricsFamily(documentFont: string | undefined): string | undefined;
|
|
113
|
+
registerLineMetricsAlias(documentFont: string | undefined, family: string | undefined): void;
|
|
114
|
+
protected decide(documentFont: string, source: FontDecisionSource, via?: string | null, widthError?: string | null): void;
|
|
115
|
+
registerRegularForm(name: string, pf: PhysicalFont | undefined): void;
|
|
116
|
+
registerBoldForm(name: string, pf: PhysicalFont | undefined): void;
|
|
117
|
+
registerItalicForm(name: string, pf: PhysicalFont | undefined): void;
|
|
118
|
+
registerBoldItalicForm(name: string, pf: PhysicalFont | undefined): void;
|
|
119
|
+
/** Whether the document embeds this font. */
|
|
120
|
+
isEmbedded(name: string): boolean;
|
|
121
|
+
/** The installed font of this name, else the document's embedded form of it (docx4j
|
|
122
|
+
* CR-016 Decisions 2: the installed font wins, for all four faces and in both mappers). */
|
|
123
|
+
protected installedOrEmbedded(name: string): PhysicalFont | undefined;
|
|
124
|
+
/**
|
|
125
|
+
* The mapper's own answer for a document font the environment has neither under that name
|
|
126
|
+
* nor embedded; undefined where it has none. {@link resolvedVia} says how it was reached.
|
|
127
|
+
*/
|
|
128
|
+
protected resolveDocumentFont(_documentFontName: string, _fontTableEntry: wml.Fonts.Font | undefined): PhysicalFont | undefined;
|
|
129
|
+
/** How the mapper's own answer was reached, set by {@link resolveDocumentFont} as it answers. */
|
|
130
|
+
protected resolvedVia: string | undefined;
|
|
131
|
+
/** An entry for each of the document's fonts: steps 1 to 3 of the precedence. */
|
|
132
|
+
populateFontMappings(documentFontNames: Iterable<string>, fonts: wml.Fonts | undefined): void;
|
|
133
|
+
/**
|
|
134
|
+
* `font-substitutes.xml`: for each document font the table knows, the first of its open
|
|
135
|
+
* substitutes this environment has. The measurements that chose each substitute are in
|
|
136
|
+
* docx4j's `Mapper.addMetricallyCompatibleSubstitutes` javadoc, and the table's `error`
|
|
137
|
+
* attributes quote them.
|
|
138
|
+
*/
|
|
139
|
+
addMetricallyCompatibleSubstitutes(): void;
|
|
140
|
+
/** Map this document font to an open substitute, unless the environment has the font itself
|
|
141
|
+
* or the document embeds it (the embedded font is what the author intended, and it is the
|
|
142
|
+
* only thing certain to be available). */
|
|
143
|
+
protected addMetricallyCompatibleSubstitute(documentFont: string, substitute: string): void;
|
|
144
|
+
/**
|
|
145
|
+
* `w:altName` in `word/fontTable.xml` (ECMA-376 17.8.3.1): "the name of an alternate font
|
|
146
|
+
* which shall be used if the font specified is not available". That is the document author's
|
|
147
|
+
* own answer to a missing font, and Word takes it.
|
|
148
|
+
*
|
|
149
|
+
* After the metric clones - a clone of the document's own font is a better answer than any
|
|
150
|
+
* alias - and before the class pass, which is only a guess from the name. The chain is
|
|
151
|
+
* followed: the alternate may itself be absent and name an alternate (CR-016 probe
|
|
152
|
+
* `fonts-unresolvable` (e), (f)); a few hops, never a cycle.
|
|
153
|
+
*/
|
|
154
|
+
addAltNameSubstitutes(documentFontNames: Iterable<string> | undefined, fonts: wml.Fonts | undefined): void;
|
|
155
|
+
/** Whether {@link addClassBasedSubstitutes} applies to this mapper. True for every mapper
|
|
156
|
+
* since docx4j 17.1.1. */
|
|
157
|
+
wantsClassBasedSubstitutes(): boolean;
|
|
158
|
+
/**
|
|
159
|
+
* Map whatever is still unmapped to a font of the same class. Without it an unmapped font
|
|
160
|
+
* falls back to whatever the document's *default* font maps to, which is a Times clone
|
|
161
|
+
* standing in for a sans as often as not. Deliberately conservative: a condensed face is
|
|
162
|
+
* left unmapped, its widths being further from an ordinary condensed face's than the
|
|
163
|
+
* default's are.
|
|
164
|
+
*/
|
|
165
|
+
addClassBasedSubstitutes(documentFontNames: Iterable<string> | undefined): void;
|
|
166
|
+
/** The mapper's own guesses for what the measured passes left (`BestMatchingMapper`'s panose
|
|
167
|
+
* match and `FontSubstitutions.xml`). Nothing here: that mapper needs font files. */
|
|
168
|
+
addMapperSubstitutes(_documentFontNames: Iterable<string> | undefined, _fonts: wml.Fonts | undefined): void;
|
|
169
|
+
/**
|
|
170
|
+
* Word's own answer for a font it cannot find, for whatever is still unmapped: Cambria or
|
|
171
|
+
* Calibri (or Courier New) by the fontTable entry's family ({@link wordDefaultFor}), mapped
|
|
172
|
+
* to whatever this mapper maps that font to. Applied only to a family none of docx4j's
|
|
173
|
+
* tables know ({@link isKnownFamily}).
|
|
174
|
+
*/
|
|
175
|
+
addWordDefaultSubstitutes(documentFontNames: Iterable<string> | undefined, fonts: wml.Fonts | undefined): void;
|
|
176
|
+
/**
|
|
177
|
+
* For each document font with no bold face of its own, an alias of its mapped physical font
|
|
178
|
+
* reporting none, so that the consumer synthesises bold at the regular advances as Word does.
|
|
179
|
+
* Last of the passes: it re-maps, and it is not a source of its own - the decision says so by
|
|
180
|
+
* reporting a synthetic bold face.
|
|
181
|
+
*/
|
|
182
|
+
addNoBoldFaceAliases(documentFontNames: Iterable<string> | undefined): void;
|
|
183
|
+
/**
|
|
184
|
+
* Every pass in order, as docx4j's `WordprocessingMLPackage.setFontMapper` runs them.
|
|
185
|
+
*
|
|
186
|
+
* @param documentFontNames the document's font names (`MainDocumentPart.fontsInUse()`)
|
|
187
|
+
* @param fonts the font table part's content, for `w:altName` and `w:family`
|
|
188
|
+
*/
|
|
189
|
+
populate(documentFontNames: Iterable<string>, fonts: wml.Fonts | undefined): void;
|
|
190
|
+
}
|