@flowaccount/pdfmake 0.2.20-staging.2

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.
@@ -0,0 +1,157 @@
1
+ 'use strict';
2
+
3
+ var isArray = require('./helpers').isArray;
4
+ var isPattern = require('./helpers').isPattern;
5
+ var getPattern = require('./helpers').getPattern;
6
+
7
+ function groupDecorations(line) {
8
+ var groups = [], currentGroup = null;
9
+ for (var i = 0, l = line.inlines.length; i < l; i++) {
10
+ var inline = line.inlines[i];
11
+ var decoration = inline.decoration;
12
+ if (!decoration) {
13
+ currentGroup = null;
14
+ continue;
15
+ }
16
+ if (!isArray(decoration)) {
17
+ decoration = [decoration];
18
+ }
19
+ var color = inline.decorationColor || inline.color || 'black';
20
+ var style = inline.decorationStyle || 'solid';
21
+ for (var ii = 0, ll = decoration.length; ii < ll; ii++) {
22
+ var decorationItem = decoration[ii];
23
+ if (!currentGroup || decorationItem !== currentGroup.decoration ||
24
+ style !== currentGroup.decorationStyle || color !== currentGroup.decorationColor) {
25
+
26
+ currentGroup = {
27
+ line: line,
28
+ decoration: decorationItem,
29
+ decorationColor: color,
30
+ decorationStyle: style,
31
+ inlines: [inline]
32
+ };
33
+ groups.push(currentGroup);
34
+ } else {
35
+ currentGroup.inlines.push(inline);
36
+ }
37
+ }
38
+ }
39
+
40
+ return groups;
41
+ }
42
+
43
+ function drawDecoration(group, x, y, pdfKitDoc) {
44
+ function maxInline() {
45
+ var max = 0;
46
+ for (var i = 0, l = group.inlines.length; i < l; i++) {
47
+ var inline = group.inlines[i];
48
+ max = inline.fontSize > max ? i : max;
49
+ }
50
+ return group.inlines[max];
51
+ }
52
+ function width() {
53
+ var sum = 0;
54
+ for (var i = 0, l = group.inlines.length; i < l; i++) {
55
+ var justifyShift = (group.inlines[i].justifyShift || 0);
56
+ sum += group.inlines[i].width + justifyShift;
57
+ }
58
+ return sum;
59
+ }
60
+ var firstInline = group.inlines[0],
61
+ biggerInline = maxInline(),
62
+ totalWidth = width(),
63
+ lineAscent = group.line.getAscenderHeight(),
64
+ ascent = biggerInline.font.ascender / 1000 * biggerInline.fontSize,
65
+ height = biggerInline.height,
66
+ descent = height - ascent;
67
+
68
+ var lw = 0.5 + Math.floor(Math.max(biggerInline.fontSize - 8, 0) / 2) * 0.12;
69
+
70
+ switch (group.decoration) {
71
+ case 'underline':
72
+ y += lineAscent + descent * 0.45;
73
+ break;
74
+ case 'overline':
75
+ y += lineAscent - (ascent * 0.85);
76
+ break;
77
+ case 'lineThrough':
78
+ y += lineAscent - (ascent * 0.25);
79
+ break;
80
+ default:
81
+ throw 'Unknown decoration : ' + group.decoration;
82
+ }
83
+ pdfKitDoc.save();
84
+
85
+ if (group.decorationStyle === 'double') {
86
+ var gap = Math.max(0.5, lw * 2);
87
+ pdfKitDoc.fillColor(group.decorationColor)
88
+ .rect(x + firstInline.x, y - lw / 2, totalWidth, lw / 2).fill()
89
+ .rect(x + firstInline.x, y + gap - lw / 2, totalWidth, lw / 2).fill();
90
+ } else if (group.decorationStyle === 'dashed') {
91
+ var nbDashes = Math.ceil(totalWidth / (3.96 + 2.84));
92
+ var rdx = x + firstInline.x;
93
+ pdfKitDoc.rect(rdx, y, totalWidth, lw).clip();
94
+ pdfKitDoc.fillColor(group.decorationColor);
95
+ for (var i = 0; i < nbDashes; i++) {
96
+ pdfKitDoc.rect(rdx, y - lw / 2, 3.96, lw).fill();
97
+ rdx += 3.96 + 2.84;
98
+ }
99
+ } else if (group.decorationStyle === 'dotted') {
100
+ var nbDots = Math.ceil(totalWidth / (lw * 3));
101
+ var rx = x + firstInline.x;
102
+ pdfKitDoc.rect(rx, y, totalWidth, lw).clip();
103
+ pdfKitDoc.fillColor(group.decorationColor);
104
+ for (var ii = 0; ii < nbDots; ii++) {
105
+ pdfKitDoc.rect(rx, y - lw / 2, lw, lw).fill();
106
+ rx += (lw * 3);
107
+ }
108
+ } else if (group.decorationStyle === 'wavy') {
109
+ var sh = 0.7, sv = 1;
110
+ var nbWaves = Math.ceil(totalWidth / (sh * 2)) + 1;
111
+ var rwx = x + firstInline.x - 1;
112
+ pdfKitDoc.rect(x + firstInline.x, y - sv, totalWidth, y + sv).clip();
113
+ pdfKitDoc.lineWidth(0.24);
114
+ pdfKitDoc.moveTo(rwx, y);
115
+ for (var iii = 0; iii < nbWaves; iii++) {
116
+ pdfKitDoc.bezierCurveTo(rwx + sh, y - sv, rwx + sh * 2, y - sv, rwx + sh * 3, y)
117
+ .bezierCurveTo(rwx + sh * 4, y + sv, rwx + sh * 5, y + sv, rwx + sh * 6, y);
118
+ rwx += sh * 6;
119
+ }
120
+ pdfKitDoc.stroke(group.decorationColor);
121
+ } else {
122
+ pdfKitDoc.fillColor(group.decorationColor)
123
+ .rect(x + firstInline.x, y - lw / 2, totalWidth, lw)
124
+ .fill();
125
+ }
126
+ pdfKitDoc.restore();
127
+ }
128
+
129
+ function drawDecorations(line, x, y, pdfKitDoc) {
130
+ var groups = groupDecorations(line);
131
+ for (var i = 0, l = groups.length; i < l; i++) {
132
+ drawDecoration(groups[i], x, y, pdfKitDoc);
133
+ }
134
+ }
135
+
136
+ function drawBackground(line, x, y, patterns, pdfKitDoc) {
137
+ var height = line.getHeight();
138
+ for (var i = 0, l = line.inlines.length; i < l; i++) {
139
+ var inline = line.inlines[i];
140
+ if (!inline.background) {
141
+ continue;
142
+ }
143
+ var color = inline.background;
144
+ if (isPattern(inline.background)) {
145
+ color = getPattern(inline.background, patterns);
146
+ }
147
+ var justifyShift = (inline.justifyShift || 0);
148
+ pdfKitDoc.fillColor(color)
149
+ .rect(x + inline.x - justifyShift, y, inline.width + justifyShift, height)
150
+ .fill();
151
+ }
152
+ }
153
+
154
+ module.exports = {
155
+ drawBackground: drawBackground,
156
+ drawDecorations: drawDecorations
157
+ };
@@ -0,0 +1,543 @@
1
+ 'use strict';
2
+
3
+ var isString = require('./helpers').isString;
4
+ var isNumber = require('./helpers').isNumber;
5
+ var isObject = require('./helpers').isObject;
6
+ var isArray = require('./helpers').isArray;
7
+ var isUndefined = require('./helpers').isUndefined;
8
+ var LineBreaker = require('@foliojs-fork/linebreak');
9
+ var Tokenizer = require('@flowaccount/node-icu-tokenizer');
10
+ var fontkit = require('fontkit');
11
+
12
+ var LEADING = /^(\s)+/g;
13
+ var TRAILING = /(\s)+$/g;
14
+
15
+ var fontCacheName = '';
16
+ var fontCache = null;
17
+ var fontSubstituteCache = {};
18
+ var defaultFont = 'Roboto';
19
+
20
+ /**
21
+ * Creates an instance of TextTools - text measurement utility
22
+ *
23
+ * @constructor
24
+ * @param {FontProvider} fontProvider
25
+ */
26
+ function TextTools(fontProvider) {
27
+ this.fontProvider = fontProvider;
28
+ }
29
+
30
+ /**
31
+ * Converts an array of strings (or inline-definition-objects) into a collection
32
+ * of inlines and calculated minWidth/maxWidth.
33
+ * and their min/max widths
34
+ * @param {Object} textArray - an array of inline-definition-objects (or strings)
35
+ * @param {Object} styleContextStack current style stack
36
+ * @return {Object} collection of inlines, minWidth, maxWidth
37
+ */
38
+ TextTools.prototype.buildInlines = function (textArray, styleContextStack) {
39
+ primeFontCaches.call(this, styleContextStack);
40
+
41
+ var measured = measure(this.fontProvider, textArray, styleContextStack);
42
+
43
+ var minWidth = 0,
44
+ maxWidth = 0,
45
+ currentLineWidth;
46
+
47
+ measured.forEach(function (inline) {
48
+ minWidth = Math.max(minWidth, inline.width - inline.leadingCut - inline.trailingCut);
49
+
50
+ if (!currentLineWidth) {
51
+ currentLineWidth = { width: 0, leadingCut: inline.leadingCut, trailingCut: 0 };
52
+ }
53
+
54
+ currentLineWidth.width += inline.width;
55
+ currentLineWidth.trailingCut = inline.trailingCut;
56
+
57
+ maxWidth = Math.max(maxWidth, getTrimmedWidth(currentLineWidth));
58
+
59
+ if (inline.lineEnd) {
60
+ currentLineWidth = null;
61
+ }
62
+ });
63
+
64
+ if (getStyleProperty({}, styleContextStack, 'noWrap', false)) {
65
+ minWidth = maxWidth;
66
+ }
67
+
68
+ return {
69
+ items: measured,
70
+ minWidth: minWidth,
71
+ maxWidth: maxWidth
72
+ };
73
+
74
+ function getTrimmedWidth(item) {
75
+ return Math.max(0, item.width - item.leadingCut - item.trailingCut);
76
+ }
77
+ };
78
+
79
+ /**
80
+ * Returns size of the specified string (without breaking it) using the current style
81
+ * @param {String} text text to be measured
82
+ * @param {Object} styleContextStack current style stack
83
+ * @return {Object} size of the specified string
84
+ */
85
+ TextTools.prototype.sizeOfString = function (text, styleContextStack) {
86
+ text = text ? text.toString().replace(/\t/g, ' ') : '';
87
+
88
+ //TODO: refactor - extract from measure
89
+ var fontName = getStyleProperty({}, styleContextStack, 'font', 'Roboto');
90
+ var fontSize = getStyleProperty({}, styleContextStack, 'fontSize', 12);
91
+ var fontFeatures = getStyleProperty({}, styleContextStack, 'fontFeatures', null);
92
+ var bold = getStyleProperty({}, styleContextStack, 'bold', false);
93
+ var italics = getStyleProperty({}, styleContextStack, 'italics', false);
94
+ var lineHeight = getStyleProperty({}, styleContextStack, 'lineHeight', 1);
95
+ var characterSpacing = getStyleProperty({}, styleContextStack, 'characterSpacing', 0);
96
+
97
+ var font = this.fontProvider.provideFont(fontName, bold, italics);
98
+
99
+ return {
100
+ width: widthOfString(text, font, fontSize, characterSpacing, fontFeatures),
101
+ height: font.lineHeight(fontSize) * lineHeight,
102
+ fontSize: fontSize,
103
+ lineHeight: lineHeight,
104
+ ascender: font.ascender / 1000 * fontSize,
105
+ descender: font.descender / 1000 * fontSize
106
+ };
107
+ };
108
+
109
+ /**
110
+ * Returns size of the specified rotated string (without breaking it) using the current style
111
+ *
112
+ * @param {string} text text to be measured
113
+ * @param {number} angle
114
+ * @param {object} styleContextStack current style stack
115
+ * @returns {object} size of the specified string
116
+ */
117
+ TextTools.prototype.sizeOfRotatedText = function (text, angle, styleContextStack) {
118
+ var angleRad = angle * Math.PI / -180;
119
+ var size = this.sizeOfString(text, styleContextStack);
120
+ return {
121
+ width: Math.abs(size.height * Math.sin(angleRad)) + Math.abs(size.width * Math.cos(angleRad)),
122
+ height: Math.abs(size.width * Math.sin(angleRad)) + Math.abs(size.height * Math.cos(angleRad))
123
+ };
124
+ };
125
+
126
+ TextTools.prototype.widthOfString = function (text, font, fontSize, characterSpacing, fontFeatures) {
127
+ return widthOfString(text, font, fontSize, characterSpacing, fontFeatures);
128
+ };
129
+
130
+ function splitWords(text, noWrap) {
131
+ var results = [];
132
+
133
+ text = text.replace(/\t/g, ' ');
134
+ text = text.replace(/\r/g, '');
135
+
136
+ if (noWrap) {
137
+ results.push({ text: text });
138
+ return results;
139
+ }
140
+
141
+ var breaker = new LineBreaker(text);
142
+ var last = 0;
143
+ var bk;
144
+
145
+ while ((bk = breaker.nextBreak())) {
146
+ var word = text.slice(last, bk.position);
147
+ var isLineEnd = bk.required || /\r?\n$|\r$/.test(word);
148
+ var trimmed = word.trim();
149
+ var useTokenizer = !exceptTokenizer(trimmed) && needsTokenizer(trimmed);
150
+
151
+ if (!useTokenizer) {
152
+ var output = word;
153
+ if (isLineEnd) {
154
+ output = output.replace(/\r?\n$|\r$/, '');
155
+ }
156
+ results.push({ text: output, lineEnd: isLineEnd });
157
+ } else {
158
+ var tokenWord = tokenizerWords(word);
159
+ for (var tIndex = 0; tIndex < tokenWord.length; tIndex++) {
160
+ var token = tokenWord[tIndex];
161
+ if (!token || token.del) {
162
+ continue;
163
+ }
164
+
165
+ var tokenText = token.token;
166
+ var tokenResult = { text: tokenText };
167
+
168
+ if (tokenText === '\n') {
169
+ tokenResult.lineEnd = true;
170
+ tokenResult.text = '';
171
+ } else if (isLineEnd && tIndex === tokenWord.length - 1) {
172
+ tokenResult.text = tokenText.replace(/\r?\n$|\r$/, '');
173
+ tokenResult.lineEnd = true;
174
+ }
175
+
176
+ results.push(tokenResult);
177
+ }
178
+ }
179
+
180
+ last = bk.position;
181
+ }
182
+
183
+ return results;
184
+ }
185
+
186
+ function tokenizerWords(word) {
187
+ var regex = / /;
188
+ word = word.replace(regex, '[BLANK]');
189
+
190
+ var tokenizer = new Tokenizer().tokenize(word, { ignoreWhitespaceTokens: false });
191
+
192
+ for (var i = 0; i < tokenizer.length; i++) {
193
+ if (tokenizer[i] && tokenizer[i].token === '[' &&
194
+ tokenizer[i + 1] && tokenizer[i + 1].token === 'BLANK' &&
195
+ tokenizer[i + 2] && tokenizer[i + 2].token === ']') {
196
+ tokenizer[i].token = ' ';
197
+ tokenizer[i + 1].del = true;
198
+ tokenizer[i + 2].del = true;
199
+ }
200
+ }
201
+
202
+ return tokenizer;
203
+ }
204
+
205
+ function copyStyle(source, destination) {
206
+ destination = destination || {};
207
+ source = source || {}; //TODO: default style
208
+
209
+ for (var key in source) {
210
+ if (key !== 'text' && Object.prototype.hasOwnProperty.call(source, key)) {
211
+ destination[key] = source[key];
212
+ }
213
+ }
214
+
215
+ return destination;
216
+ }
217
+
218
+ function normalizeTextArray(array, styleContextStack) {
219
+ function flatten(target) {
220
+ return target.reduce(function (prev, cur) {
221
+ var current = isObject(cur) && isArray(cur.text) ? flatten(cur.text) : cur;
222
+ var more = [].concat(current).some(Array.isArray);
223
+ return prev.concat(more ? flatten(current) : current);
224
+ }, []);
225
+ }
226
+
227
+ function getOneWord(index, words, noWrap) {
228
+ if (isUndefined(words[index])) {
229
+ return null;
230
+ }
231
+
232
+ if (words[index].lineEnd) {
233
+ return null;
234
+ }
235
+
236
+ var word = words[index].text;
237
+
238
+ if (noWrap) {
239
+ var tmpWords = splitWords(normalizeString(word), false);
240
+ if (isUndefined(tmpWords[tmpWords.length - 1])) {
241
+ return null;
242
+ }
243
+ word = tmpWords[tmpWords.length - 1].text;
244
+ }
245
+
246
+ return word;
247
+ }
248
+
249
+ var results = [];
250
+
251
+ if (!isArray(array)) {
252
+ array = [array];
253
+ }
254
+
255
+ array = flatten(array);
256
+
257
+ var lastWord = null;
258
+ for (var i = 0, l = array.length; i < l; i++) {
259
+ var item = array[i];
260
+ var style = null;
261
+ var words;
262
+
263
+ var noWrap = getStyleProperty(item || {}, styleContextStack, 'noWrap', false);
264
+ if (isObject(item)) {
265
+ if (item._textRef && item._textRef._textNodeRef && item._textRef._textNodeRef.text) {
266
+ item.text = item._textRef._textNodeRef.text;
267
+ }
268
+ words = splitWords(normalizeString(item.text), noWrap);
269
+ style = copyStyle(item);
270
+ } else {
271
+ words = splitWords(normalizeString(item), noWrap);
272
+ }
273
+
274
+ if (lastWord && words.length) {
275
+ var firstWord = getOneWord(0, words, noWrap);
276
+ var wrapWords = splitWords(normalizeString(lastWord + firstWord), false);
277
+ if (wrapWords.length === 1) {
278
+ results[results.length - 1].noNewLine = true;
279
+ }
280
+ }
281
+
282
+ for (var i2 = 0, l2 = words.length; i2 < l2; i2++) {
283
+ var result = {
284
+ text: words[i2].text
285
+ };
286
+
287
+ if (words[i2].lineEnd) {
288
+ result.lineEnd = true;
289
+ }
290
+
291
+ copyStyle(style, result);
292
+ results.push(result);
293
+ }
294
+
295
+ lastWord = null;
296
+ if (i + 1 < l) {
297
+ lastWord = getOneWord(words.length - 1, words, noWrap);
298
+ }
299
+ }
300
+
301
+ return results;
302
+ }
303
+
304
+ function normalizeString(value) {
305
+ if (value === undefined || value === null) {
306
+ return '';
307
+ } else if (isNumber(value)) {
308
+ return value.toString();
309
+ } else if (isString(value)) {
310
+ return value;
311
+ } else {
312
+ return value.toString();
313
+ }
314
+ }
315
+
316
+ function getStyleProperty(item, styleContextStack, property, defaultValue) {
317
+ var value;
318
+
319
+ if (item && item[property] !== undefined && item[property] !== null) {
320
+ // item defines this property
321
+ return item[property];
322
+ }
323
+
324
+ if (!styleContextStack || typeof styleContextStack.auto !== 'function') {
325
+ return defaultValue;
326
+ }
327
+
328
+ styleContextStack.auto(item, function () {
329
+ value = styleContextStack.getProperty(property);
330
+ });
331
+
332
+ if (value !== null && value !== undefined) {
333
+ return value;
334
+ } else {
335
+ return defaultValue;
336
+ }
337
+ }
338
+
339
+ function measure(fontProvider, textArray, styleContextStack) {
340
+ var normalized = normalizeTextArray(textArray, styleContextStack);
341
+
342
+ if (normalized.length) {
343
+ var leadingIndent = getStyleProperty(normalized[0], styleContextStack, 'leadingIndent', 0);
344
+
345
+ if (leadingIndent) {
346
+ normalized[0].leadingCut = -leadingIndent;
347
+ normalized[0].leadingIndent = leadingIndent;
348
+ }
349
+ }
350
+
351
+ normalized.forEach(function (item) {
352
+ var fontName = getFontCompaitible(item);
353
+ var fontSize = getStyleProperty(item, styleContextStack, 'fontSize', 12);
354
+ var fontFeatures = getStyleProperty(item, styleContextStack, 'fontFeatures', null);
355
+ var bold = getStyleProperty(item, styleContextStack, 'bold', false);
356
+ var italics = getStyleProperty(item, styleContextStack, 'italics', false);
357
+ var color = getStyleProperty(item, styleContextStack, 'color', 'black');
358
+ var decoration = getStyleProperty(item, styleContextStack, 'decoration', null);
359
+ var decorationColor = getStyleProperty(item, styleContextStack, 'decorationColor', null);
360
+ var decorationStyle = getStyleProperty(item, styleContextStack, 'decorationStyle', null);
361
+ var background = getStyleProperty(item, styleContextStack, 'background', null);
362
+ var lineHeight = getStyleProperty(item, styleContextStack, 'lineHeight', 1);
363
+ var characterSpacing = getStyleProperty(item, styleContextStack, 'characterSpacing', 0);
364
+ var link = getStyleProperty(item, styleContextStack, 'link', null);
365
+ var linkToPage = getStyleProperty(item, styleContextStack, 'linkToPage', null);
366
+ var linkToDestination = getStyleProperty(item, styleContextStack, 'linkToDestination', null);
367
+ var noWrap = getStyleProperty(item, styleContextStack, 'noWrap', null);
368
+ var preserveLeadingSpaces = getStyleProperty(item, styleContextStack, 'preserveLeadingSpaces', false);
369
+ var preserveTrailingSpaces = getStyleProperty(item, styleContextStack, 'preserveTrailingSpaces', false);
370
+ var opacity = getStyleProperty(item, styleContextStack, 'opacity', 1);
371
+ var sup = getStyleProperty(item, styleContextStack, 'sup', false);
372
+ var sub = getStyleProperty(item, styleContextStack, 'sub', false);
373
+
374
+ if ((sup || sub) && item.fontSize === undefined) {
375
+ // font size reduction taken from here: https://en.wikipedia.org/wiki/Subscript_and_superscript#Desktop_publishing
376
+ fontSize *= 0.58;
377
+ }
378
+
379
+ var font = fontProvider.provideFont(fontName, bold, italics);
380
+
381
+ item.width = widthOfString(item.text, font, fontSize, characterSpacing, fontFeatures);
382
+ item.height = font.lineHeight(fontSize) * lineHeight;
383
+
384
+ if (!item.leadingCut) {
385
+ item.leadingCut = 0;
386
+ }
387
+
388
+ var leadingSpaces;
389
+ if (!preserveLeadingSpaces && (leadingSpaces = item.text.match(LEADING))) {
390
+ item.leadingCut += widthOfString(leadingSpaces[0], font, fontSize, characterSpacing, fontFeatures);
391
+ }
392
+
393
+ var trailingSpaces;
394
+ if (!preserveTrailingSpaces && (trailingSpaces = item.text.match(TRAILING))) {
395
+ item.trailingCut = widthOfString(trailingSpaces[0], font, fontSize, characterSpacing, fontFeatures);
396
+ } else if (item.trailingCut === undefined) {
397
+ item.trailingCut = 0;
398
+ }
399
+
400
+ item.alignment = getStyleProperty(item, styleContextStack, 'alignment', 'left');
401
+ item.font = font;
402
+ item.fontSize = fontSize;
403
+ item.fontFeatures = fontFeatures;
404
+ item.characterSpacing = characterSpacing;
405
+ item.color = color;
406
+ item.decoration = decoration;
407
+ item.decorationColor = decorationColor;
408
+ item.decorationStyle = decorationStyle;
409
+ item.background = background;
410
+ item.link = link;
411
+ item.linkToPage = linkToPage;
412
+ item.linkToDestination = linkToDestination;
413
+ item.noWrap = noWrap;
414
+ item.opacity = opacity;
415
+ item.sup = sup;
416
+ item.sub = sub;
417
+ });
418
+
419
+ return normalized;
420
+ }
421
+
422
+ function widthOfString(text, font, fontSize, characterSpacing, fontFeatures) {
423
+ return font.widthOfString(text, fontSize, fontFeatures) + ((characterSpacing || 0) * (text.length - 1));
424
+ }
425
+
426
+ function exceptTokenizer(word) {
427
+ var listExceptWord = [
428
+ '(ไทยแลนด์)',
429
+ '(ประเทศไทย)',
430
+ '(สำนักงานใหญ่)',
431
+ '(มหาชน)',
432
+ '(Thailand)',
433
+ '(Main Branch)',
434
+ '(Head office)',
435
+ '(กรุ๊ป)'
436
+ ];
437
+
438
+ return listExceptWord.indexOf(word) > -1;
439
+ }
440
+
441
+ function needsTokenizer(word) {
442
+ if (!word) {
443
+ return false;
444
+ }
445
+
446
+ return /[\u0E00-\u0E7F]/.test(word);
447
+ }
448
+
449
+ function primeFontCaches(styleContextStack) {
450
+ if (styleContextStack && typeof styleContextStack.getProperty === 'function') {
451
+ var stackFont = styleContextStack.getProperty('font');
452
+ if (stackFont) {
453
+ defaultFont = stackFont;
454
+ }
455
+ }
456
+
457
+ if (!defaultFont) {
458
+ defaultFont = 'Roboto';
459
+ }
460
+
461
+ if (!this.fontProvider || !this.fontProvider.fonts) {
462
+ return;
463
+ }
464
+
465
+ if (defaultFont && fontCacheName !== defaultFont) {
466
+ var defaultFontDef = this.fontProvider.fonts[defaultFont];
467
+ var primaryFont = safeOpenFont(defaultFontDef && defaultFontDef.normal);
468
+
469
+ if (primaryFont) {
470
+ fontCacheName = defaultFont;
471
+ fontCache = primaryFont;
472
+ } else {
473
+ fontCacheName = '';
474
+ fontCache = null;
475
+ }
476
+ }
477
+
478
+ for (var fontItem in this.fontProvider.fonts) {
479
+ if (!Object.prototype.hasOwnProperty.call(this.fontProvider.fonts, fontItem)) {
480
+ continue;
481
+ }
482
+
483
+ if (fontItem === fontCacheName) {
484
+ continue;
485
+ }
486
+
487
+ if (!fontSubstituteCache[fontItem]) {
488
+ var substitute = safeOpenFont(this.fontProvider.fonts[fontItem].normal);
489
+ if (substitute) {
490
+ fontSubstituteCache[fontItem] = { Name: fontItem, FontObj: substitute };
491
+ }
492
+ }
493
+ }
494
+ }
495
+
496
+ function getFontCompaitible(item) {
497
+ var text = item.text || '';
498
+
499
+ if (fontCacheName && fontCache && !hasMissingGlyphs(fontCache.glyphsForString(text))) {
500
+ return fontCacheName;
501
+ }
502
+
503
+ for (var key in fontSubstituteCache) {
504
+ if (!Object.prototype.hasOwnProperty.call(fontSubstituteCache, key)) {
505
+ continue;
506
+ }
507
+
508
+ var fontItem = fontSubstituteCache[key];
509
+ if (!fontItem || !fontItem.FontObj || fontItem.Name === fontCacheName) {
510
+ continue;
511
+ }
512
+
513
+ if (!hasMissingGlyphs(fontItem.FontObj.glyphsForString(text))) {
514
+ return fontItem.Name;
515
+ }
516
+ }
517
+
518
+ return defaultFont || 'Roboto';
519
+ }
520
+
521
+ function hasMissingGlyphs(glyphList) {
522
+ for (var i = 0; i < glyphList.length; i++) {
523
+ if (!glyphList[i] || glyphList[i].id <= 0) {
524
+ return true;
525
+ }
526
+ }
527
+ return false;
528
+ }
529
+
530
+ function safeOpenFont(path) {
531
+ if (!path) {
532
+ return null;
533
+ }
534
+
535
+ try {
536
+ return fontkit.openSync(path);
537
+ } catch (error) {
538
+ void error;
539
+ return null;
540
+ }
541
+ }
542
+
543
+ module.exports = TextTools;