@digicole/pdfmake-rtl 2.1.0 → 2.1.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.
- package/CHANGELOG.md +118 -83
- package/README.md +11 -10
- package/build/pdfmake.js +71 -42
- package/build/pdfmake.js.map +1 -1
- package/build/pdfmake.min.js +2 -2
- package/build/pdfmake.min.js.map +1 -1
- package/build/vfs_fonts.js +11 -11
- package/js/3rd-party/svg-to-pdfkit/source.js +3823 -0
- package/js/3rd-party/svg-to-pdfkit.js +7 -0
- package/js/DocMeasure.js +713 -0
- package/js/DocPreprocessor.js +275 -0
- package/js/DocumentContext.js +310 -0
- package/js/ElementWriter.js +687 -0
- package/js/LayoutBuilder.js +1240 -0
- package/js/Line.js +113 -0
- package/js/OutputDocument.js +64 -0
- package/js/OutputDocumentServer.js +29 -0
- package/js/PDFDocument.js +144 -0
- package/js/PageElementWriter.js +161 -0
- package/js/PageSize.js +74 -0
- package/js/Printer.js +351 -0
- package/js/Renderer.js +417 -0
- package/js/SVGMeasure.js +92 -0
- package/js/StyleContextStack.js +191 -0
- package/js/TableProcessor.js +575 -0
- package/js/TextBreaker.js +166 -0
- package/js/TextDecorator.js +152 -0
- package/js/TextInlines.js +244 -0
- package/js/URLResolver.js +43 -0
- package/js/base.js +59 -0
- package/js/browser-extensions/OutputDocumentBrowser.js +82 -0
- package/js/browser-extensions/fonts/Cairo.js +38 -0
- package/js/browser-extensions/fonts/Roboto.js +38 -0
- package/js/browser-extensions/index.js +59 -0
- package/js/browser-extensions/pdfMake.js +3 -0
- package/js/browser-extensions/standard-fonts/Courier.js +38 -0
- package/js/browser-extensions/standard-fonts/Helvetica.js +38 -0
- package/js/browser-extensions/standard-fonts/Symbol.js +23 -0
- package/js/browser-extensions/standard-fonts/Times.js +38 -0
- package/js/browser-extensions/standard-fonts/ZapfDingbats.js +23 -0
- package/js/browser-extensions/virtual-fs-cjs.js +3 -0
- package/js/columnCalculator.js +148 -0
- package/js/helpers/node.js +123 -0
- package/js/helpers/tools.js +46 -0
- package/js/helpers/variableType.js +59 -0
- package/js/index.js +15 -0
- package/js/qrEnc.js +721 -0
- package/js/rtlUtils.js +519 -0
- package/js/standardPageSizes.js +56 -0
- package/js/tableLayouts.js +98 -0
- package/js/virtual-fs.js +60 -0
- package/package.json +1 -1
- package/src/{docMeasure.js → DocMeasure.js} +8 -8
- package/src/{elementWriter.js → ElementWriter.js} +3 -3
- package/src/{layoutBuilder.js → LayoutBuilder.js} +1406 -1393
- package/src/{tableProcessor.js → TableProcessor.js} +633 -620
- package/src/rtlUtils.js +503 -500
- /package/src/{docPreprocessor.js → DocPreprocessor.js} +0 -0
- /package/src/{documentContext.js → DocumentContext.js} +0 -0
- /package/src/{line.js → Line.js} +0 -0
- /package/src/{pageElementWriter.js → PageElementWriter.js} +0 -0
- /package/src/{printer.js → Printer.js} +0 -0
- /package/src/{svgMeasure.js → SVGMeasure.js} +0 -0
- /package/src/{styleContextStack.js → StyleContextStack.js} +0 -0
- /package/src/{textDecorator.js → TextDecorator.js} +0 -0
package/js/DocMeasure.js
ADDED
|
@@ -0,0 +1,713 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.default = void 0;
|
|
5
|
+
var _TextInlines = _interopRequireDefault(require("./TextInlines.js"));
|
|
6
|
+
var _StyleContextStack = _interopRequireDefault(require("./StyleContextStack.js"));
|
|
7
|
+
var _columnCalculator = _interopRequireDefault(require("./columnCalculator.js"));
|
|
8
|
+
var _tableLayouts = require("./tableLayouts.js");
|
|
9
|
+
var _variableType = require("./helpers/variableType.js");
|
|
10
|
+
var _node = require("./helpers/node.js");
|
|
11
|
+
var _tools = require("./helpers/tools.js");
|
|
12
|
+
var _qrEnc = _interopRequireDefault(require("./qrEnc.js"));
|
|
13
|
+
var _rtlUtils = require("./rtlUtils.js");
|
|
14
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
15
|
+
class DocMeasure {
|
|
16
|
+
constructor(pdfDocument, styleDictionary, defaultStyle, svgMeasure, tableLayouts) {
|
|
17
|
+
this.pdfDocument = pdfDocument;
|
|
18
|
+
this.textInlines = new _TextInlines.default(pdfDocument);
|
|
19
|
+
this.styleStack = new _StyleContextStack.default(styleDictionary, defaultStyle);
|
|
20
|
+
this.svgMeasure = svgMeasure;
|
|
21
|
+
this.tableLayouts = tableLayouts;
|
|
22
|
+
this.autoImageIndex = 1;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Measures all nodes and sets min/max-width properties required for the second
|
|
27
|
+
* layout-pass.
|
|
28
|
+
*
|
|
29
|
+
* @param {object} docStructure document-definition-object
|
|
30
|
+
* @returns {object} document-measurement-object
|
|
31
|
+
*/
|
|
32
|
+
measureDocument(docStructure) {
|
|
33
|
+
return this.measureNode(docStructure);
|
|
34
|
+
}
|
|
35
|
+
measureBlock(node) {
|
|
36
|
+
return this.measureNode(node);
|
|
37
|
+
}
|
|
38
|
+
measureNode(node) {
|
|
39
|
+
return this.styleStack.auto(node, () => {
|
|
40
|
+
// TODO: refactor + rethink whether this is the proper way to handle margins
|
|
41
|
+
node._margin = (0, _node.getNodeMargin)(node, this.styleStack);
|
|
42
|
+
if (node.section) {
|
|
43
|
+
return extendMargins(this.measureSection(node));
|
|
44
|
+
} else if (node.columns) {
|
|
45
|
+
return extendMargins(this.measureColumns(node));
|
|
46
|
+
} else if (node.stack) {
|
|
47
|
+
return extendMargins(this.measureVerticalContainer(node));
|
|
48
|
+
} else if (node.ul) {
|
|
49
|
+
return extendMargins(this.measureUnorderedList(node));
|
|
50
|
+
} else if (node.ol) {
|
|
51
|
+
return extendMargins(this.measureOrderedList(node));
|
|
52
|
+
} else if (node.table) {
|
|
53
|
+
return extendMargins(this.measureTable(node));
|
|
54
|
+
} else if (node.text !== undefined) {
|
|
55
|
+
return extendMargins(this.measureLeaf(node));
|
|
56
|
+
} else if (node.toc) {
|
|
57
|
+
return extendMargins(this.measureToc(node));
|
|
58
|
+
} else if (node.image) {
|
|
59
|
+
return extendMargins(this.measureImage(node));
|
|
60
|
+
} else if (node.svg) {
|
|
61
|
+
return extendMargins(this.measureSVG(node));
|
|
62
|
+
} else if (node.canvas) {
|
|
63
|
+
return extendMargins(this.measureCanvas(node));
|
|
64
|
+
} else if (node.qr) {
|
|
65
|
+
return extendMargins(this.measureQr(node));
|
|
66
|
+
} else if (node.attachment) {
|
|
67
|
+
return extendMargins(this.measureAttachment(node));
|
|
68
|
+
} else {
|
|
69
|
+
throw new Error(`Unrecognized document structure: ${(0, _node.stringifyNode)(node)}`);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
function extendMargins(node) {
|
|
73
|
+
let margin = node._margin;
|
|
74
|
+
if (margin) {
|
|
75
|
+
node._minWidth += margin[0] + margin[2];
|
|
76
|
+
node._maxWidth += margin[0] + margin[2];
|
|
77
|
+
}
|
|
78
|
+
return node;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
measureImageWithDimensions(node, dimensions) {
|
|
82
|
+
if (node.fit) {
|
|
83
|
+
let factor = dimensions.width / dimensions.height > node.fit[0] / node.fit[1] ? node.fit[0] / dimensions.width : node.fit[1] / dimensions.height;
|
|
84
|
+
node._width = node._minWidth = node._maxWidth = dimensions.width * factor;
|
|
85
|
+
node._height = dimensions.height * factor;
|
|
86
|
+
} else if (node.cover) {
|
|
87
|
+
node._width = node._minWidth = node._maxWidth = node.cover.width;
|
|
88
|
+
node._height = node._minHeight = node._maxHeight = node.cover.height;
|
|
89
|
+
} else {
|
|
90
|
+
let ratio = dimensions.width / dimensions.height;
|
|
91
|
+
node._width = node._minWidth = node._maxWidth = node.width || (node.height ? node.height * ratio : dimensions.width);
|
|
92
|
+
node._height = node.height || (node.width ? node.width / ratio : dimensions.height);
|
|
93
|
+
if ((0, _variableType.isNumber)(node.maxWidth) && node.maxWidth < node._width) {
|
|
94
|
+
node._width = node._minWidth = node._maxWidth = node.maxWidth;
|
|
95
|
+
node._height = node._width * dimensions.height / dimensions.width;
|
|
96
|
+
}
|
|
97
|
+
if ((0, _variableType.isNumber)(node.maxHeight) && node.maxHeight < node._height) {
|
|
98
|
+
node._height = node.maxHeight;
|
|
99
|
+
node._width = node._minWidth = node._maxWidth = node._height * dimensions.width / dimensions.height;
|
|
100
|
+
}
|
|
101
|
+
if ((0, _variableType.isNumber)(node.minWidth) && node.minWidth > node._width) {
|
|
102
|
+
node._width = node._minWidth = node._maxWidth = node.minWidth;
|
|
103
|
+
node._height = node._width * dimensions.height / dimensions.width;
|
|
104
|
+
}
|
|
105
|
+
if ((0, _variableType.isNumber)(node.minHeight) && node.minHeight > node._height) {
|
|
106
|
+
node._height = node.minHeight;
|
|
107
|
+
node._width = node._minWidth = node._maxWidth = node._height * dimensions.width / dimensions.height;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
node._alignment = this.styleStack.getProperty('alignment');
|
|
111
|
+
}
|
|
112
|
+
convertIfBase64Image(node) {
|
|
113
|
+
if (/^data:image\/(jpeg|jpg|png);base64,/.test(node.image)) {
|
|
114
|
+
// base64 image
|
|
115
|
+
let label = `$$pdfmake$$${this.autoImageIndex++}`;
|
|
116
|
+
this.pdfDocument.images[label] = node.image;
|
|
117
|
+
node.image = label;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
measureImage(node) {
|
|
121
|
+
this.convertIfBase64Image(node);
|
|
122
|
+
let image = this.pdfDocument.provideImage(node.image);
|
|
123
|
+
let imageSize = {
|
|
124
|
+
width: image.width,
|
|
125
|
+
height: image.height
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
// If EXIF orientation calls for it, swap width and height
|
|
129
|
+
if (image.orientation > 4) {
|
|
130
|
+
imageSize = {
|
|
131
|
+
width: image.height,
|
|
132
|
+
height: image.width
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
this.measureImageWithDimensions(node, imageSize);
|
|
136
|
+
return node;
|
|
137
|
+
}
|
|
138
|
+
measureSVG(node) {
|
|
139
|
+
let dimensions = this.svgMeasure.measureSVG(node.svg);
|
|
140
|
+
this.measureImageWithDimensions(node, dimensions);
|
|
141
|
+
node.font = this.styleStack.getProperty('font');
|
|
142
|
+
|
|
143
|
+
// SVG requires a defined width and height
|
|
144
|
+
if (!(0, _variableType.isNumber)(node._width) && !(0, _variableType.isNumber)(node._height)) {
|
|
145
|
+
throw new Error('SVG is missing defined width and height.');
|
|
146
|
+
} else if (!(0, _variableType.isNumber)(node._width)) {
|
|
147
|
+
throw new Error('SVG is missing defined width.');
|
|
148
|
+
} else if (!(0, _variableType.isNumber)(node._height)) {
|
|
149
|
+
throw new Error('SVG is missing defined height.');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// scale SVG based on final dimension
|
|
153
|
+
node.svg = this.svgMeasure.writeDimensions(node.svg, {
|
|
154
|
+
width: node._width,
|
|
155
|
+
height: node._height
|
|
156
|
+
});
|
|
157
|
+
return node;
|
|
158
|
+
}
|
|
159
|
+
measureLeaf(node) {
|
|
160
|
+
if (node._textRef && node._textRef._textNodeRef.text) {
|
|
161
|
+
node.text = node._textRef._textNodeRef.text;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Make sure style properties of the node itself are considered when building inlines.
|
|
165
|
+
// We could also just pass [node] to buildInlines, but that fails for bullet points.
|
|
166
|
+
let styleStack = this.styleStack.clone();
|
|
167
|
+
styleStack.push(node);
|
|
168
|
+
let data = this.textInlines.buildInlines(node.text, styleStack);
|
|
169
|
+
node._inlines = data.items;
|
|
170
|
+
node._minWidth = data.minWidth;
|
|
171
|
+
node._maxWidth = data.maxWidth;
|
|
172
|
+
return node;
|
|
173
|
+
}
|
|
174
|
+
measureToc(node) {
|
|
175
|
+
if (node.toc.title) {
|
|
176
|
+
node.toc.title = this.measureNode(node.toc.title);
|
|
177
|
+
}
|
|
178
|
+
if (node.toc._items.length > 0) {
|
|
179
|
+
let body = [];
|
|
180
|
+
let textStyle = node.toc.textStyle || {};
|
|
181
|
+
let numberStyle = node.toc.numberStyle || textStyle;
|
|
182
|
+
let textMargin = node.toc.textMargin || [0, 0, 0, 0];
|
|
183
|
+
if (node.toc.sortBy === 'title') {
|
|
184
|
+
node.toc._items.sort((a, b) => {
|
|
185
|
+
return a._textNodeRef.text.localeCompare(b._textNodeRef.text, node.toc.sortLocale);
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
for (let i = 0, l = node.toc._items.length; i < l; i++) {
|
|
189
|
+
let item = node.toc._items[i];
|
|
190
|
+
let lineStyle = item._textNodeRef.tocStyle || textStyle;
|
|
191
|
+
let lineMargin = item._textNodeRef.tocMargin || textMargin;
|
|
192
|
+
let lineNumberStyle = item._textNodeRef.tocNumberStyle || numberStyle;
|
|
193
|
+
let destination = (0, _node.getNodeId)(item._nodeRef);
|
|
194
|
+
body.push([{
|
|
195
|
+
text: item._textNodeRef.text,
|
|
196
|
+
linkToDestination: destination,
|
|
197
|
+
alignment: 'left',
|
|
198
|
+
style: lineStyle,
|
|
199
|
+
margin: lineMargin
|
|
200
|
+
}, {
|
|
201
|
+
text: '00000',
|
|
202
|
+
linkToDestination: destination,
|
|
203
|
+
alignment: 'right',
|
|
204
|
+
_tocItemRef: item._nodeRef,
|
|
205
|
+
style: lineNumberStyle,
|
|
206
|
+
margin: [0, lineMargin[1], 0, lineMargin[3]]
|
|
207
|
+
}]);
|
|
208
|
+
}
|
|
209
|
+
node.toc._table = {
|
|
210
|
+
table: {
|
|
211
|
+
dontBreakRows: true,
|
|
212
|
+
widths: ['*', 'auto'],
|
|
213
|
+
body: body
|
|
214
|
+
},
|
|
215
|
+
layout: 'noBorders'
|
|
216
|
+
};
|
|
217
|
+
node.toc._table = this.measureNode(node.toc._table);
|
|
218
|
+
}
|
|
219
|
+
return node;
|
|
220
|
+
}
|
|
221
|
+
measureVerticalContainer(node) {
|
|
222
|
+
let items = node.stack;
|
|
223
|
+
node._minWidth = 0;
|
|
224
|
+
node._maxWidth = 0;
|
|
225
|
+
for (let i = 0, l = items.length; i < l; i++) {
|
|
226
|
+
items[i] = this.measureNode(items[i]);
|
|
227
|
+
node._minWidth = Math.max(node._minWidth, items[i]._minWidth);
|
|
228
|
+
node._maxWidth = Math.max(node._maxWidth, items[i]._maxWidth);
|
|
229
|
+
}
|
|
230
|
+
return node;
|
|
231
|
+
}
|
|
232
|
+
gapSizeForList() {
|
|
233
|
+
return this.textInlines.sizeOfText('9. ', this.styleStack);
|
|
234
|
+
}
|
|
235
|
+
buildUnorderedMarker(item, styleStack, gapSize, type) {
|
|
236
|
+
function buildDisc(gapSize, color) {
|
|
237
|
+
// TODO: ascender-based calculations
|
|
238
|
+
let radius = gapSize.fontSize / 6;
|
|
239
|
+
return {
|
|
240
|
+
canvas: [{
|
|
241
|
+
x: radius,
|
|
242
|
+
y: gapSize.height / gapSize.lineHeight + gapSize.descender - gapSize.fontSize / 3,
|
|
243
|
+
r1: radius,
|
|
244
|
+
r2: radius,
|
|
245
|
+
type: 'ellipse',
|
|
246
|
+
color: color
|
|
247
|
+
}]
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
function buildSquare(gapSize, color) {
|
|
251
|
+
// TODO: ascender-based calculations
|
|
252
|
+
let size = gapSize.fontSize / 3;
|
|
253
|
+
return {
|
|
254
|
+
canvas: [{
|
|
255
|
+
x: 0,
|
|
256
|
+
y: gapSize.height / gapSize.lineHeight + gapSize.descender - gapSize.fontSize / 3 - size / 2,
|
|
257
|
+
h: size,
|
|
258
|
+
w: size,
|
|
259
|
+
type: 'rect',
|
|
260
|
+
color: color
|
|
261
|
+
}]
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
function buildCircle(gapSize, color) {
|
|
265
|
+
// TODO: ascender-based calculations
|
|
266
|
+
let radius = gapSize.fontSize / 6;
|
|
267
|
+
return {
|
|
268
|
+
canvas: [{
|
|
269
|
+
x: radius,
|
|
270
|
+
y: gapSize.height / gapSize.lineHeight + gapSize.descender - gapSize.fontSize / 3,
|
|
271
|
+
r1: radius,
|
|
272
|
+
r2: radius,
|
|
273
|
+
type: 'ellipse',
|
|
274
|
+
lineColor: color
|
|
275
|
+
}]
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
let marker;
|
|
279
|
+
let color = _StyleContextStack.default.getStyleProperty(item, styleStack, 'markerColor', undefined) || styleStack.getProperty('color') || 'black';
|
|
280
|
+
switch (type) {
|
|
281
|
+
case 'circle':
|
|
282
|
+
marker = buildCircle(gapSize, color);
|
|
283
|
+
break;
|
|
284
|
+
case 'square':
|
|
285
|
+
marker = buildSquare(gapSize, color);
|
|
286
|
+
break;
|
|
287
|
+
case 'none':
|
|
288
|
+
marker = {};
|
|
289
|
+
break;
|
|
290
|
+
case 'disc':
|
|
291
|
+
default:
|
|
292
|
+
marker = buildDisc(gapSize, color);
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
295
|
+
marker._minWidth = marker._maxWidth = gapSize.width;
|
|
296
|
+
marker._minHeight = marker._maxHeight = gapSize.height;
|
|
297
|
+
return marker;
|
|
298
|
+
}
|
|
299
|
+
buildOrderedMarker(item, counter, styleStack, type, separator, isRTL) {
|
|
300
|
+
function prepareAlpha(counter) {
|
|
301
|
+
function toAlpha(num) {
|
|
302
|
+
return (num >= 26 ? toAlpha((num / 26 >> 0) - 1) : '') + 'abcdefghijklmnopqrstuvwxyz'[num % 26 >> 0];
|
|
303
|
+
}
|
|
304
|
+
if (counter < 1) {
|
|
305
|
+
return counter.toString();
|
|
306
|
+
}
|
|
307
|
+
return toAlpha(counter - 1);
|
|
308
|
+
}
|
|
309
|
+
function prepareRoman(counter) {
|
|
310
|
+
if (counter < 1 || counter > 4999) {
|
|
311
|
+
return counter.toString();
|
|
312
|
+
}
|
|
313
|
+
let num = counter;
|
|
314
|
+
let lookup = {
|
|
315
|
+
M: 1000,
|
|
316
|
+
CM: 900,
|
|
317
|
+
D: 500,
|
|
318
|
+
CD: 400,
|
|
319
|
+
C: 100,
|
|
320
|
+
XC: 90,
|
|
321
|
+
L: 50,
|
|
322
|
+
XL: 40,
|
|
323
|
+
X: 10,
|
|
324
|
+
IX: 9,
|
|
325
|
+
V: 5,
|
|
326
|
+
IV: 4,
|
|
327
|
+
I: 1
|
|
328
|
+
};
|
|
329
|
+
let roman = '';
|
|
330
|
+
for (let i in lookup) {
|
|
331
|
+
while (num >= lookup[i]) {
|
|
332
|
+
roman += i;
|
|
333
|
+
num -= lookup[i];
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return roman;
|
|
337
|
+
}
|
|
338
|
+
function prepareDecimal(counter) {
|
|
339
|
+
return counter.toString();
|
|
340
|
+
}
|
|
341
|
+
let counterText;
|
|
342
|
+
switch (type) {
|
|
343
|
+
case 'none':
|
|
344
|
+
counterText = null;
|
|
345
|
+
break;
|
|
346
|
+
case 'upper-alpha':
|
|
347
|
+
counterText = prepareAlpha(counter).toUpperCase();
|
|
348
|
+
break;
|
|
349
|
+
case 'lower-alpha':
|
|
350
|
+
counterText = prepareAlpha(counter);
|
|
351
|
+
break;
|
|
352
|
+
case 'upper-roman':
|
|
353
|
+
counterText = prepareRoman(counter);
|
|
354
|
+
break;
|
|
355
|
+
case 'lower-roman':
|
|
356
|
+
counterText = prepareRoman(counter).toLowerCase();
|
|
357
|
+
break;
|
|
358
|
+
case 'decimal':
|
|
359
|
+
default:
|
|
360
|
+
counterText = prepareDecimal(counter);
|
|
361
|
+
break;
|
|
362
|
+
}
|
|
363
|
+
if (counterText === null) {
|
|
364
|
+
return {};
|
|
365
|
+
}
|
|
366
|
+
if (separator) {
|
|
367
|
+
if (isRTL) {
|
|
368
|
+
// RTL: place separator before the number so it renders as .1 (right-to-left: 1. )
|
|
369
|
+
if (Array.isArray(separator)) {
|
|
370
|
+
if (separator[1]) {
|
|
371
|
+
counterText = separator[1] + counterText;
|
|
372
|
+
}
|
|
373
|
+
if (separator[0]) {
|
|
374
|
+
counterText += separator[0];
|
|
375
|
+
}
|
|
376
|
+
counterText = ' ' + counterText;
|
|
377
|
+
} else {
|
|
378
|
+
counterText = ` ${separator}${counterText}`;
|
|
379
|
+
}
|
|
380
|
+
} else {
|
|
381
|
+
if (Array.isArray(separator)) {
|
|
382
|
+
if (separator[0]) {
|
|
383
|
+
counterText = separator[0] + counterText;
|
|
384
|
+
}
|
|
385
|
+
if (separator[1]) {
|
|
386
|
+
counterText += separator[1];
|
|
387
|
+
}
|
|
388
|
+
counterText += ' ';
|
|
389
|
+
} else {
|
|
390
|
+
counterText += `${separator} `;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
let markerColor = _StyleContextStack.default.getStyleProperty(item, styleStack, 'markerColor', undefined) || styleStack.getProperty('color') || 'black';
|
|
395
|
+
|
|
396
|
+
// Resolve font: item font > style stack font > defaultStyle font > auto-detect (Cairo for RTL, Roboto for LTR)
|
|
397
|
+
let markerFont = _StyleContextStack.default.getStyleProperty(item, styleStack, 'font', null);
|
|
398
|
+
if (!markerFont) {
|
|
399
|
+
markerFont = isRTL ? 'Cairo' : undefined;
|
|
400
|
+
}
|
|
401
|
+
let textArray = {
|
|
402
|
+
text: counterText,
|
|
403
|
+
color: markerColor
|
|
404
|
+
};
|
|
405
|
+
if (markerFont) {
|
|
406
|
+
textArray.font = markerFont;
|
|
407
|
+
}
|
|
408
|
+
return {
|
|
409
|
+
_inlines: this.textInlines.buildInlines(textArray, styleStack).items
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
measureUnorderedList(node) {
|
|
413
|
+
let style = this.styleStack.clone();
|
|
414
|
+
let items = node.ul;
|
|
415
|
+
node.type = node.type || 'disc';
|
|
416
|
+
node._gapSize = this.gapSizeForList();
|
|
417
|
+
node._minWidth = 0;
|
|
418
|
+
node._maxWidth = 0;
|
|
419
|
+
for (let i = 0, l = items.length; i < l; i++) {
|
|
420
|
+
let item = items[i] = this.measureNode(items[i]);
|
|
421
|
+
if (!item.ol && !item.ul) {
|
|
422
|
+
item.listMarker = this.buildUnorderedMarker(item, style, node._gapSize, item.listType || node.type);
|
|
423
|
+
}
|
|
424
|
+
node._minWidth = Math.max(node._minWidth, items[i]._minWidth + node._gapSize.width);
|
|
425
|
+
node._maxWidth = Math.max(node._maxWidth, items[i]._maxWidth + node._gapSize.width);
|
|
426
|
+
}
|
|
427
|
+
return node;
|
|
428
|
+
}
|
|
429
|
+
measureOrderedList(node) {
|
|
430
|
+
let style = this.styleStack.clone();
|
|
431
|
+
let items = node.ol;
|
|
432
|
+
node.type = node.type || 'decimal';
|
|
433
|
+
node.separator = node.separator || '.';
|
|
434
|
+
node.reversed = node.reversed || false;
|
|
435
|
+
if (!(0, _variableType.isNumber)(node.start)) {
|
|
436
|
+
node.start = node.reversed ? items.length : 1;
|
|
437
|
+
}
|
|
438
|
+
node._gapSize = this.gapSizeForList();
|
|
439
|
+
node._minWidth = 0;
|
|
440
|
+
node._maxWidth = 0;
|
|
441
|
+
|
|
442
|
+
// Detect if this is an RTL list
|
|
443
|
+
let isRTL = node.rtl || this._isListRTL(items);
|
|
444
|
+
let counter = node.start;
|
|
445
|
+
for (let i = 0, l = items.length; i < l; i++) {
|
|
446
|
+
let item = items[i] = this.measureNode(items[i]);
|
|
447
|
+
if (!item.ol && !item.ul) {
|
|
448
|
+
let counterValue = (0, _variableType.isNumber)(item.counter) ? item.counter : counter;
|
|
449
|
+
item.listMarker = this.buildOrderedMarker(item, counterValue, style, item.listType || node.type, node.separator, isRTL);
|
|
450
|
+
if (item.listMarker._inlines) {
|
|
451
|
+
node._gapSize.width = Math.max(node._gapSize.width, item.listMarker._inlines[0].width);
|
|
452
|
+
}
|
|
453
|
+
if (node.reversed) {
|
|
454
|
+
counter--;
|
|
455
|
+
} else {
|
|
456
|
+
counter++;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
node._minWidth = Math.max(node._minWidth, items[i]._minWidth);
|
|
460
|
+
node._maxWidth = Math.max(node._maxWidth, items[i]._maxWidth);
|
|
461
|
+
}
|
|
462
|
+
node._minWidth += node._gapSize.width;
|
|
463
|
+
node._maxWidth += node._gapSize.width;
|
|
464
|
+
for (let i = 0, l = items.length; i < l; i++) {
|
|
465
|
+
let item = items[i];
|
|
466
|
+
if (!item.ol && !item.ul) {
|
|
467
|
+
item.listMarker._minWidth = item.listMarker._maxWidth = node._gapSize.width;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
return node;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Check if a list contains predominantly RTL content
|
|
475
|
+
* @param {Array} items - List items
|
|
476
|
+
* @returns {boolean}
|
|
477
|
+
*/
|
|
478
|
+
_isListRTL(items) {
|
|
479
|
+
if (!items || !Array.isArray(items)) return false;
|
|
480
|
+
let rtlCount = 0;
|
|
481
|
+
let total = 0;
|
|
482
|
+
for (let i = 0; i < items.length; i++) {
|
|
483
|
+
let item = items[i];
|
|
484
|
+
let text = '';
|
|
485
|
+
if (typeof item === 'string') {
|
|
486
|
+
text = item;
|
|
487
|
+
} else if (item && item.text) {
|
|
488
|
+
text = typeof item.text === 'string' ? item.text : Array.isArray(item.text) ? item.text.map(t => typeof t === 'string' ? t : t && t.text || '').join('') : '';
|
|
489
|
+
}
|
|
490
|
+
if (text) {
|
|
491
|
+
total++;
|
|
492
|
+
if ((0, _rtlUtils.containsRTL)(text)) {
|
|
493
|
+
rtlCount++;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
return total > 0 && rtlCount / total >= 0.3;
|
|
498
|
+
}
|
|
499
|
+
measureSection(node) {
|
|
500
|
+
// TODO: properties
|
|
501
|
+
|
|
502
|
+
node.section = this.measureNode(node.section);
|
|
503
|
+
return node;
|
|
504
|
+
}
|
|
505
|
+
measureColumns(node) {
|
|
506
|
+
let columns = node.columns;
|
|
507
|
+
node._gap = this.styleStack.getProperty('columnGap') || 0;
|
|
508
|
+
for (let i = 0, l = columns.length; i < l; i++) {
|
|
509
|
+
columns[i] = this.measureNode(columns[i]);
|
|
510
|
+
}
|
|
511
|
+
let measures = _columnCalculator.default.measureMinMax(columns);
|
|
512
|
+
let numGaps = columns.length > 0 ? columns.length - 1 : 0;
|
|
513
|
+
node._minWidth = measures.min + node._gap * numGaps;
|
|
514
|
+
node._maxWidth = measures.max + node._gap * numGaps;
|
|
515
|
+
return node;
|
|
516
|
+
}
|
|
517
|
+
measureTable(node) {
|
|
518
|
+
extendTableWidths(node);
|
|
519
|
+
node._layout = getLayout(this.tableLayouts);
|
|
520
|
+
node._offsets = getOffsets(node._layout);
|
|
521
|
+
let colSpans = [];
|
|
522
|
+
let col;
|
|
523
|
+
let row;
|
|
524
|
+
let cols;
|
|
525
|
+
let rows;
|
|
526
|
+
for (col = 0, cols = node.table.body[0].length; col < cols; col++) {
|
|
527
|
+
let c = node.table.widths[col];
|
|
528
|
+
c._minWidth = 0;
|
|
529
|
+
c._maxWidth = 0;
|
|
530
|
+
for (row = 0, rows = node.table.body.length; row < rows; row++) {
|
|
531
|
+
let rowData = node.table.body[row];
|
|
532
|
+
let data = rowData[col];
|
|
533
|
+
if (data === undefined) {
|
|
534
|
+
throw new Error(`Malformed table row, a cell is undefined.\nRow index: ${row}\nColumn index: ${col}\nRow data: ${(0, _node.stringifyNode)(rowData)}`);
|
|
535
|
+
}
|
|
536
|
+
if (data === null) {
|
|
537
|
+
// transform to object
|
|
538
|
+
data = '';
|
|
539
|
+
}
|
|
540
|
+
if (!data._span) {
|
|
541
|
+
data = rowData[col] = this.styleStack.auto(data, measureCb(this, data));
|
|
542
|
+
if (data.colSpan && data.colSpan > 1) {
|
|
543
|
+
markSpans(rowData, col, data.colSpan);
|
|
544
|
+
colSpans.push({
|
|
545
|
+
col: col,
|
|
546
|
+
span: data.colSpan,
|
|
547
|
+
minWidth: data._minWidth,
|
|
548
|
+
maxWidth: data._maxWidth
|
|
549
|
+
});
|
|
550
|
+
} else {
|
|
551
|
+
c._minWidth = Math.max(c._minWidth, data._minWidth);
|
|
552
|
+
c._maxWidth = Math.max(c._maxWidth, data._maxWidth);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
if (data.rowSpan && data.rowSpan > 1) {
|
|
556
|
+
markVSpans(node.table, row, col, data.rowSpan);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
extendWidthsForColSpans();
|
|
561
|
+
let measures = _columnCalculator.default.measureMinMax(node.table.widths);
|
|
562
|
+
node._minWidth = measures.min + node._offsets.total;
|
|
563
|
+
node._maxWidth = measures.max + node._offsets.total;
|
|
564
|
+
return node;
|
|
565
|
+
function measureCb(_this, data) {
|
|
566
|
+
return () => {
|
|
567
|
+
if ((0, _variableType.isObject)(data)) {
|
|
568
|
+
data.fillColor = _this.styleStack.getProperty('fillColor');
|
|
569
|
+
data.fillOpacity = _this.styleStack.getProperty('fillOpacity');
|
|
570
|
+
}
|
|
571
|
+
return _this.measureNode(data);
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
function getLayout(tableLayouts) {
|
|
575
|
+
let layout = node.layout;
|
|
576
|
+
if ((0, _variableType.isString)(layout)) {
|
|
577
|
+
layout = tableLayouts[layout];
|
|
578
|
+
}
|
|
579
|
+
return (0, _tools.pack)(_tableLayouts.defaultTableLayout, layout);
|
|
580
|
+
}
|
|
581
|
+
function getOffsets(layout) {
|
|
582
|
+
let offsets = [];
|
|
583
|
+
let totalOffset = 0;
|
|
584
|
+
let prevRightPadding = 0;
|
|
585
|
+
for (let i = 0, l = node.table.widths.length; i < l; i++) {
|
|
586
|
+
let lOffset = prevRightPadding + layout.vLineWidth(i, node) + layout.paddingLeft(i, node);
|
|
587
|
+
offsets.push(lOffset);
|
|
588
|
+
totalOffset += lOffset;
|
|
589
|
+
prevRightPadding = layout.paddingRight(i, node);
|
|
590
|
+
}
|
|
591
|
+
totalOffset += prevRightPadding + layout.vLineWidth(node.table.widths.length, node);
|
|
592
|
+
return {
|
|
593
|
+
total: totalOffset,
|
|
594
|
+
offsets: offsets
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
function extendWidthsForColSpans() {
|
|
598
|
+
let q;
|
|
599
|
+
let j;
|
|
600
|
+
for (let i = 0, l = colSpans.length; i < l; i++) {
|
|
601
|
+
let span = colSpans[i];
|
|
602
|
+
let currentMinMax = getMinMax(span.col, span.span, node._offsets);
|
|
603
|
+
let minDifference = span.minWidth - currentMinMax.minWidth;
|
|
604
|
+
let maxDifference = span.maxWidth - currentMinMax.maxWidth;
|
|
605
|
+
if (minDifference > 0) {
|
|
606
|
+
q = minDifference / span.span;
|
|
607
|
+
for (j = 0; j < span.span; j++) {
|
|
608
|
+
node.table.widths[span.col + j]._minWidth += q;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
if (maxDifference > 0) {
|
|
612
|
+
q = maxDifference / span.span;
|
|
613
|
+
for (j = 0; j < span.span; j++) {
|
|
614
|
+
node.table.widths[span.col + j]._maxWidth += q;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
function getMinMax(col, span, offsets) {
|
|
620
|
+
let result = {
|
|
621
|
+
minWidth: 0,
|
|
622
|
+
maxWidth: 0
|
|
623
|
+
};
|
|
624
|
+
for (let i = 0; i < span; i++) {
|
|
625
|
+
result.minWidth += node.table.widths[col + i]._minWidth + (i ? offsets.offsets[col + i] : 0);
|
|
626
|
+
result.maxWidth += node.table.widths[col + i]._maxWidth + (i ? offsets.offsets[col + i] : 0);
|
|
627
|
+
}
|
|
628
|
+
return result;
|
|
629
|
+
}
|
|
630
|
+
function markSpans(rowData, col, span) {
|
|
631
|
+
for (let i = 1; i < span; i++) {
|
|
632
|
+
rowData[col + i] = {
|
|
633
|
+
_span: true,
|
|
634
|
+
_minWidth: 0,
|
|
635
|
+
_maxWidth: 0,
|
|
636
|
+
rowSpan: rowData[col].rowSpan
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
function markVSpans(table, row, col, span) {
|
|
641
|
+
for (let i = 1; i < span; i++) {
|
|
642
|
+
table.body[row + i][col] = {
|
|
643
|
+
_span: true,
|
|
644
|
+
_minWidth: 0,
|
|
645
|
+
_maxWidth: 0,
|
|
646
|
+
fillColor: table.body[row][col].fillColor,
|
|
647
|
+
fillOpacity: table.body[row][col].fillOpacity
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
function extendTableWidths(node) {
|
|
652
|
+
if (!node.table.widths) {
|
|
653
|
+
node.table.widths = 'auto';
|
|
654
|
+
}
|
|
655
|
+
if ((0, _variableType.isString)(node.table.widths)) {
|
|
656
|
+
node.table.widths = [node.table.widths];
|
|
657
|
+
while (node.table.widths.length < node.table.body[0].length) {
|
|
658
|
+
node.table.widths.push(node.table.widths[node.table.widths.length - 1]);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
for (let i = 0, l = node.table.widths.length; i < l; i++) {
|
|
662
|
+
let w = node.table.widths[i];
|
|
663
|
+
if ((0, _variableType.isNumber)(w) || (0, _variableType.isString)(w)) {
|
|
664
|
+
node.table.widths[i] = {
|
|
665
|
+
width: w
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
measureCanvas(node) {
|
|
672
|
+
let w = 0;
|
|
673
|
+
let h = 0;
|
|
674
|
+
for (let i = 0, l = node.canvas.length; i < l; i++) {
|
|
675
|
+
let vector = node.canvas[i];
|
|
676
|
+
switch (vector.type) {
|
|
677
|
+
case 'ellipse':
|
|
678
|
+
w = Math.max(w, vector.x + vector.r1);
|
|
679
|
+
h = Math.max(h, vector.y + vector.r2);
|
|
680
|
+
break;
|
|
681
|
+
case 'rect':
|
|
682
|
+
w = Math.max(w, vector.x + vector.w);
|
|
683
|
+
h = Math.max(h, vector.y + vector.h);
|
|
684
|
+
break;
|
|
685
|
+
case 'line':
|
|
686
|
+
w = Math.max(w, vector.x1, vector.x2);
|
|
687
|
+
h = Math.max(h, vector.y1, vector.y2);
|
|
688
|
+
break;
|
|
689
|
+
case 'polyline':
|
|
690
|
+
for (let i2 = 0, l2 = vector.points.length; i2 < l2; i2++) {
|
|
691
|
+
w = Math.max(w, vector.points[i2].x);
|
|
692
|
+
h = Math.max(h, vector.points[i2].y);
|
|
693
|
+
}
|
|
694
|
+
break;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
node._minWidth = node._maxWidth = w;
|
|
698
|
+
node._minHeight = node._maxHeight = h;
|
|
699
|
+
node._alignment = this.styleStack.getProperty('alignment');
|
|
700
|
+
return node;
|
|
701
|
+
}
|
|
702
|
+
measureQr(node) {
|
|
703
|
+
node = _qrEnc.default.measure(node);
|
|
704
|
+
node._alignment = this.styleStack.getProperty('alignment');
|
|
705
|
+
return node;
|
|
706
|
+
}
|
|
707
|
+
measureAttachment(node) {
|
|
708
|
+
node._width = node.width || 7;
|
|
709
|
+
node._height = node.height || 18;
|
|
710
|
+
return node;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
var _default = exports.default = DocMeasure;
|