pdfmake 0.3.1 → 0.3.3
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 +20 -0
- package/build/pdfmake.js +14447 -14350
- package/build/pdfmake.js.map +1 -1
- package/build/pdfmake.min.js +2 -2
- package/build/pdfmake.min.js.map +1 -1
- package/js/3rd-party/svg-to-pdfkit/source.js +1 -1
- package/js/DocMeasure.js +25 -12
- package/js/LayoutBuilder.js +3 -0
- package/js/StyleContextStack.js +26 -3
- package/js/TextDecorator.js +12 -3
- package/js/TextInlines.js +1 -0
- package/js/browser-extensions/OutputDocumentBrowser.js +2 -1
- package/js/helpers/node.js +36 -11
- package/js/helpers/variableType.js +1 -1
- package/package.json +9 -9
- package/src/3rd-party/svg-to-pdfkit/source.js +1 -1
- package/src/DocMeasure.js +30 -12
- package/src/LayoutBuilder.js +4 -0
- package/src/StyleContextStack.js +32 -3
- package/src/TextDecorator.js +17 -3
- package/src/TextInlines.js +1 -0
- package/src/browser-extensions/OutputDocumentBrowser.js +2 -1
- package/src/helpers/node.js +41 -15
- package/src/helpers/variableType.js +1 -1
- package/.typos.toml +0 -21
|
@@ -1542,7 +1542,7 @@ var SVGtoPDF = function (doc, svg, x, y, options) {
|
|
|
1542
1542
|
}
|
|
1543
1543
|
}
|
|
1544
1544
|
for (let i = 0; i < selector.classes.length; i++) {
|
|
1545
|
-
if (
|
|
1545
|
+
if (elem.classList.indexOf(selector.classes[i]) === -1) {
|
|
1546
1546
|
return false;
|
|
1547
1547
|
}
|
|
1548
1548
|
}
|
package/js/DocMeasure.js
CHANGED
|
@@ -86,8 +86,9 @@ class DocMeasure {
|
|
|
86
86
|
node._width = node._minWidth = node._maxWidth = node.cover.width;
|
|
87
87
|
node._height = node._minHeight = node._maxHeight = node.cover.height;
|
|
88
88
|
} else {
|
|
89
|
-
|
|
90
|
-
node.
|
|
89
|
+
let ratio = dimensions.width / dimensions.height;
|
|
90
|
+
node._width = node._minWidth = node._maxWidth = node.width || (node.height ? node.height * ratio : dimensions.width);
|
|
91
|
+
node._height = node.height || (node.width ? node.width / ratio : dimensions.height);
|
|
91
92
|
if ((0, _variableType.isNumber)(node.maxWidth) && node.maxWidth < node._width) {
|
|
92
93
|
node._width = node._minWidth = node._maxWidth = node.maxWidth;
|
|
93
94
|
node._height = node._width * dimensions.height / dimensions.width;
|
|
@@ -138,6 +139,15 @@ class DocMeasure {
|
|
|
138
139
|
this.measureImageWithDimensions(node, dimensions);
|
|
139
140
|
node.font = this.styleStack.getProperty('font');
|
|
140
141
|
|
|
142
|
+
// SVG requires a defined width and height
|
|
143
|
+
if (!(0, _variableType.isNumber)(node._width) && !(0, _variableType.isNumber)(node._height)) {
|
|
144
|
+
throw new Error('SVG is missing defined width and height.');
|
|
145
|
+
} else if (!(0, _variableType.isNumber)(node._width)) {
|
|
146
|
+
throw new Error('SVG is missing defined width.');
|
|
147
|
+
} else if (!(0, _variableType.isNumber)(node._height)) {
|
|
148
|
+
throw new Error('SVG is missing defined height.');
|
|
149
|
+
}
|
|
150
|
+
|
|
141
151
|
// scale SVG based on final dimension
|
|
142
152
|
node.svg = this.svgMeasure.writeDimensions(node.svg, {
|
|
143
153
|
width: node._width,
|
|
@@ -169,6 +179,11 @@ class DocMeasure {
|
|
|
169
179
|
let textStyle = node.toc.textStyle || {};
|
|
170
180
|
let numberStyle = node.toc.numberStyle || textStyle;
|
|
171
181
|
let textMargin = node.toc.textMargin || [0, 0, 0, 0];
|
|
182
|
+
if (node.toc.sortBy === 'title') {
|
|
183
|
+
node.toc._items.sort((a, b) => {
|
|
184
|
+
return a._textNodeRef.text.localeCompare(b._textNodeRef.text, node.toc.sortLocale);
|
|
185
|
+
});
|
|
186
|
+
}
|
|
172
187
|
for (let i = 0, l = node.toc._items.length; i < l; i++) {
|
|
173
188
|
let item = node.toc._items[i];
|
|
174
189
|
let lineStyle = item._textNodeRef.tocStyle || textStyle;
|
|
@@ -216,7 +231,7 @@ class DocMeasure {
|
|
|
216
231
|
gapSizeForList() {
|
|
217
232
|
return this.textInlines.sizeOfText('9. ', this.styleStack);
|
|
218
233
|
}
|
|
219
|
-
buildUnorderedMarker(styleStack, gapSize, type) {
|
|
234
|
+
buildUnorderedMarker(item, styleStack, gapSize, type) {
|
|
220
235
|
function buildDisc(gapSize, color) {
|
|
221
236
|
// TODO: ascender-based calculations
|
|
222
237
|
let radius = gapSize.fontSize / 6;
|
|
@@ -260,7 +275,7 @@ class DocMeasure {
|
|
|
260
275
|
};
|
|
261
276
|
}
|
|
262
277
|
let marker;
|
|
263
|
-
let color =
|
|
278
|
+
let color = _StyleContextStack.default.getStyleProperty(item, styleStack, 'markerColor', undefined) || styleStack.getProperty('color') || 'black';
|
|
264
279
|
switch (type) {
|
|
265
280
|
case 'circle':
|
|
266
281
|
marker = buildCircle(gapSize, color);
|
|
@@ -280,7 +295,7 @@ class DocMeasure {
|
|
|
280
295
|
marker._minHeight = marker._maxHeight = gapSize.height;
|
|
281
296
|
return marker;
|
|
282
297
|
}
|
|
283
|
-
buildOrderedMarker(counter, styleStack, type, separator) {
|
|
298
|
+
buildOrderedMarker(item, counter, styleStack, type, separator) {
|
|
284
299
|
function prepareAlpha(counter) {
|
|
285
300
|
function toAlpha(num) {
|
|
286
301
|
return (num >= 26 ? toAlpha((num / 26 >> 0) - 1) : '') + 'abcdefghijklmnopqrstuvwxyz'[num % 26 >> 0];
|
|
@@ -360,13 +375,11 @@ class DocMeasure {
|
|
|
360
375
|
counterText += `${separator} `;
|
|
361
376
|
}
|
|
362
377
|
}
|
|
378
|
+
let markerColor = _StyleContextStack.default.getStyleProperty(item, styleStack, 'markerColor', undefined) || styleStack.getProperty('color') || 'black';
|
|
363
379
|
let textArray = {
|
|
364
|
-
text: counterText
|
|
380
|
+
text: counterText,
|
|
381
|
+
color: markerColor
|
|
365
382
|
};
|
|
366
|
-
let markerColor = styleStack.getProperty('markerColor');
|
|
367
|
-
if (markerColor) {
|
|
368
|
-
textArray.color = markerColor;
|
|
369
|
-
}
|
|
370
383
|
return {
|
|
371
384
|
_inlines: this.textInlines.buildInlines(textArray, styleStack).items
|
|
372
385
|
};
|
|
@@ -381,7 +394,7 @@ class DocMeasure {
|
|
|
381
394
|
for (let i = 0, l = items.length; i < l; i++) {
|
|
382
395
|
let item = items[i] = this.measureNode(items[i]);
|
|
383
396
|
if (!item.ol && !item.ul) {
|
|
384
|
-
item.listMarker = this.buildUnorderedMarker(style, node._gapSize, item.listType || node.type);
|
|
397
|
+
item.listMarker = this.buildUnorderedMarker(item, style, node._gapSize, item.listType || node.type);
|
|
385
398
|
}
|
|
386
399
|
node._minWidth = Math.max(node._minWidth, items[i]._minWidth + node._gapSize.width);
|
|
387
400
|
node._maxWidth = Math.max(node._maxWidth, items[i]._maxWidth + node._gapSize.width);
|
|
@@ -405,7 +418,7 @@ class DocMeasure {
|
|
|
405
418
|
let item = items[i] = this.measureNode(items[i]);
|
|
406
419
|
if (!item.ol && !item.ul) {
|
|
407
420
|
let counterValue = (0, _variableType.isNumber)(item.counter) ? item.counter : counter;
|
|
408
|
-
item.listMarker = this.buildOrderedMarker(counterValue, style, item.listType || node.type, node.separator);
|
|
421
|
+
item.listMarker = this.buildOrderedMarker(item, counterValue, style, item.listType || node.type, node.separator);
|
|
409
422
|
if (item.listMarker._inlines) {
|
|
410
423
|
node._gapSize.width = Math.max(node._gapSize.width, item.listMarker._inlines[0].width);
|
|
411
424
|
}
|
package/js/LayoutBuilder.js
CHANGED
package/js/StyleContextStack.js
CHANGED
|
@@ -109,14 +109,37 @@ class StyleContextStack {
|
|
|
109
109
|
* @returns {?any} property value or null if not found
|
|
110
110
|
*/
|
|
111
111
|
getProperty(property) {
|
|
112
|
+
const getStylePropertyFromStyle = (styleName, property, visited = new Set()) => {
|
|
113
|
+
if (visited.has(styleName)) {
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
visited.add(styleName);
|
|
117
|
+
const style = this.styleDictionary[styleName];
|
|
118
|
+
if (!style) {
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
if ((0, _variableType.isValue)(style[property])) {
|
|
122
|
+
return style[property];
|
|
123
|
+
}
|
|
124
|
+
if (style.extends) {
|
|
125
|
+
let parents = Array.isArray(style.extends) ? style.extends : [style.extends];
|
|
126
|
+
for (let i = parents.length - 1; i >= 0; i--) {
|
|
127
|
+
let value = getStylePropertyFromStyle(parents[i], property, visited);
|
|
128
|
+
if ((0, _variableType.isValue)(value)) {
|
|
129
|
+
return value;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return undefined;
|
|
134
|
+
};
|
|
112
135
|
if (this.styleOverrides) {
|
|
113
136
|
for (let i = this.styleOverrides.length - 1; i >= 0; i--) {
|
|
114
137
|
let item = this.styleOverrides[i];
|
|
115
138
|
if ((0, _variableType.isString)(item)) {
|
|
116
139
|
// named-style-override
|
|
117
|
-
let
|
|
118
|
-
if (
|
|
119
|
-
return
|
|
140
|
+
let value = getStylePropertyFromStyle(item, property);
|
|
141
|
+
if ((0, _variableType.isValue)(value)) {
|
|
142
|
+
return value;
|
|
120
143
|
}
|
|
121
144
|
} else if ((0, _variableType.isValue)(item[property])) {
|
|
122
145
|
// style-overrides-object
|
package/js/TextDecorator.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
exports.__esModule = true;
|
|
4
4
|
exports.default = void 0;
|
|
5
|
+
var _variableType = require("./helpers/variableType");
|
|
5
6
|
const groupDecorations = line => {
|
|
6
7
|
let groups = [];
|
|
7
8
|
let currentGroup = null;
|
|
@@ -17,6 +18,7 @@ const groupDecorations = line => {
|
|
|
17
18
|
}
|
|
18
19
|
let color = inline.decorationColor || inline.color || 'black';
|
|
19
20
|
let style = inline.decorationStyle || 'solid';
|
|
21
|
+
let thickness = (0, _variableType.isNumber)(inline.decorationThickness) ? inline.decorationThickness : null;
|
|
20
22
|
for (let ii = 0, ll = decoration.length; ii < ll; ii++) {
|
|
21
23
|
let decorationItem = decoration[ii];
|
|
22
24
|
if (!currentGroup || decorationItem !== currentGroup.decoration || style !== currentGroup.decorationStyle || color !== currentGroup.decorationColor) {
|
|
@@ -25,6 +27,7 @@ const groupDecorations = line => {
|
|
|
25
27
|
decoration: decorationItem,
|
|
26
28
|
decorationColor: color,
|
|
27
29
|
decorationStyle: style,
|
|
30
|
+
decorationThickness: thickness,
|
|
28
31
|
inlines: [inline]
|
|
29
32
|
};
|
|
30
33
|
groups.push(currentGroup);
|
|
@@ -85,7 +88,7 @@ class TextDecorator {
|
|
|
85
88
|
let ascent = biggerInline.font.ascender / 1000 * biggerInline.fontSize;
|
|
86
89
|
let height = biggerInline.height;
|
|
87
90
|
let descent = height - ascent;
|
|
88
|
-
let lw = 0.5 + Math.floor(Math.max(biggerInline.fontSize - 8, 0) / 2) * 0.12;
|
|
91
|
+
let lw = (0, _variableType.isNumber)(group.decorationThickness) ? group.decorationThickness : 0.5 + Math.floor(Math.max(biggerInline.fontSize - 8, 0) / 2) * 0.12;
|
|
89
92
|
switch (group.decoration) {
|
|
90
93
|
case 'underline':
|
|
91
94
|
y += lineAscent + descent * 0.45;
|
|
@@ -99,9 +102,15 @@ class TextDecorator {
|
|
|
99
102
|
default:
|
|
100
103
|
throw new Error(`Unknown decoration : ${group.decoration}`);
|
|
101
104
|
}
|
|
105
|
+
if (group.inlines[0].sup) {
|
|
106
|
+
y -= group.inlines[0].fontSize * 0.75;
|
|
107
|
+
}
|
|
108
|
+
if (group.inlines[0].sub) {
|
|
109
|
+
y += group.inlines[0].fontSize * 0.35;
|
|
110
|
+
}
|
|
102
111
|
this.pdfDocument.save();
|
|
103
112
|
if (group.decorationStyle === 'double') {
|
|
104
|
-
let gap = Math.max(0.5, lw *
|
|
113
|
+
let gap = Math.max(0.5, lw, biggerInline.fontSize * 0.15);
|
|
105
114
|
this.pdfDocument.fillColor(group.decorationColor).rect(x + firstInline.x, y - lw / 2, totalWidth, lw / 2).fill().rect(x + firstInline.x, y + gap - lw / 2, totalWidth, lw / 2).fill();
|
|
106
115
|
} else if (group.decorationStyle === 'dashed') {
|
|
107
116
|
let nbDashes = Math.ceil(totalWidth / (3.96 + 2.84));
|
|
@@ -127,7 +136,7 @@ class TextDecorator {
|
|
|
127
136
|
let nbWaves = Math.ceil(totalWidth / (sh * 2)) + 1;
|
|
128
137
|
let rwx = x + firstInline.x - 1;
|
|
129
138
|
this.pdfDocument.rect(x + firstInline.x, y - sv, totalWidth, y + sv).clip();
|
|
130
|
-
this.pdfDocument.lineWidth(
|
|
139
|
+
this.pdfDocument.lineWidth(lw / 3);
|
|
131
140
|
this.pdfDocument.moveTo(rwx, y);
|
|
132
141
|
for (let i = 0; i < nbWaves; i++) {
|
|
133
142
|
this.pdfDocument.bezierCurveTo(rwx + sh, y - sv, rwx + sh * 2, y - sv, rwx + sh * 3, y).bezierCurveTo(rwx + sh * 4, y + sv, rwx + sh * 5, y + sv, rwx + sh * 6, y);
|
package/js/TextInlines.js
CHANGED
|
@@ -106,6 +106,7 @@ class TextInlines {
|
|
|
106
106
|
item.decoration = _StyleContextStack.default.getStyleProperty(item, styleContextStack, 'decoration', null);
|
|
107
107
|
item.decorationColor = _StyleContextStack.default.getStyleProperty(item, styleContextStack, 'decorationColor', null);
|
|
108
108
|
item.decorationStyle = _StyleContextStack.default.getStyleProperty(item, styleContextStack, 'decorationStyle', null);
|
|
109
|
+
item.decorationThickness = _StyleContextStack.default.getStyleProperty(item, styleContextStack, 'decorationThickness', null);
|
|
109
110
|
item.background = _StyleContextStack.default.getStyleProperty(item, styleContextStack, 'background', null);
|
|
110
111
|
item.link = _StyleContextStack.default.getStyleProperty(item, styleContextStack, 'link', null);
|
|
111
112
|
item.linkToPage = _StyleContextStack.default.getStyleProperty(item, styleContextStack, 'linkToPage', null);
|
package/js/helpers/node.js
CHANGED
|
@@ -47,22 +47,47 @@ function getNodeId(node) {
|
|
|
47
47
|
* @returns {?Array}
|
|
48
48
|
*/
|
|
49
49
|
function getNodeMargin(node, styleStack) {
|
|
50
|
-
function processSingleMargins(node, currentMargin) {
|
|
51
|
-
if (node.marginLeft || node.marginTop || node.marginRight || node.marginBottom) {
|
|
52
|
-
return [node.marginLeft
|
|
50
|
+
function processSingleMargins(node, currentMargin, defaultMargin = 0) {
|
|
51
|
+
if (node.marginLeft !== undefined || node.marginTop !== undefined || node.marginRight !== undefined || node.marginBottom !== undefined) {
|
|
52
|
+
return [node.marginLeft ?? currentMargin[0] ?? defaultMargin, node.marginTop ?? currentMargin[1] ?? defaultMargin, node.marginRight ?? currentMargin[2] ?? defaultMargin, node.marginBottom ?? currentMargin[3] ?? defaultMargin];
|
|
53
53
|
}
|
|
54
54
|
return currentMargin;
|
|
55
55
|
}
|
|
56
|
-
function flattenStyleArray(styleArray, styleStack) {
|
|
56
|
+
function flattenStyleArray(styleArray, styleStack, visited = new Set()) {
|
|
57
|
+
styleArray = Array.isArray(styleArray) ? styleArray : [styleArray];
|
|
58
|
+
|
|
59
|
+
// style is not valid array of strings
|
|
60
|
+
if (!styleArray.every(item => (0, _variableType.isString)(item))) {
|
|
61
|
+
return {};
|
|
62
|
+
}
|
|
57
63
|
let flattenedStyles = {};
|
|
58
|
-
for (let
|
|
59
|
-
let styleName = styleArray[
|
|
64
|
+
for (let index = 0; index < styleArray.length; index++) {
|
|
65
|
+
let styleName = styleArray[index];
|
|
60
66
|
let style = styleStack.styleDictionary[styleName];
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
67
|
+
|
|
68
|
+
// style not found
|
|
69
|
+
if (style === undefined) {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (visited.has(styleName)) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
visited.add(styleName);
|
|
76
|
+
if (style.extends !== undefined) {
|
|
77
|
+
flattenedStyles = {
|
|
78
|
+
...flattenStyleArray(style.extends, styleStack, visited),
|
|
79
|
+
...flattenedStyles
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
if (style.margin !== undefined) {
|
|
83
|
+
flattenedStyles = {
|
|
84
|
+
margin: convertMargin(style.margin)
|
|
85
|
+
};
|
|
86
|
+
continue;
|
|
65
87
|
}
|
|
88
|
+
flattenedStyles = {
|
|
89
|
+
margin: processSingleMargins(style, flattenedStyles.margin ?? {}, undefined)
|
|
90
|
+
};
|
|
66
91
|
}
|
|
67
92
|
return flattenedStyles;
|
|
68
93
|
}
|
|
@@ -88,7 +113,7 @@ function getNodeMargin(node, styleStack) {
|
|
|
88
113
|
}
|
|
89
114
|
}
|
|
90
115
|
margin = processSingleMargins(node, margin);
|
|
91
|
-
if (node.margin) {
|
|
116
|
+
if (node.margin !== undefined) {
|
|
92
117
|
margin = convertMargin(node.margin);
|
|
93
118
|
}
|
|
94
119
|
if (margin[0] === undefined && margin[1] === undefined && margin[2] === undefined && margin[3] === undefined) {
|
|
@@ -20,7 +20,7 @@ function isString(variable) {
|
|
|
20
20
|
* @returns {boolean}
|
|
21
21
|
*/
|
|
22
22
|
function isNumber(variable) {
|
|
23
|
-
return typeof variable === 'number' || variable instanceof Number;
|
|
23
|
+
return (typeof variable === 'number' || variable instanceof Number) && !Number.isNaN(variable);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pdfmake",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "Client/server side PDF printing in pure JavaScript",
|
|
5
5
|
"main": "js/index.js",
|
|
6
6
|
"esnext": "src/index.js",
|
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
"xmldoc": "^2.0.3"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
|
-
"@babel/cli": "^7.28.
|
|
18
|
-
"@babel/core": "^7.28.
|
|
19
|
-
"@babel/plugin-transform-modules-commonjs": "^7.
|
|
20
|
-
"@babel/preset-env": "^7.28.
|
|
17
|
+
"@babel/cli": "^7.28.6",
|
|
18
|
+
"@babel/core": "^7.28.6",
|
|
19
|
+
"@babel/plugin-transform-modules-commonjs": "^7.28.6",
|
|
20
|
+
"@babel/preset-env": "^7.28.6",
|
|
21
21
|
"@eslint/js": "^9.39.2",
|
|
22
22
|
"assert": "^2.1.0",
|
|
23
23
|
"babel-loader": "^10.0.0",
|
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
"buffer": "^6.0.3",
|
|
27
27
|
"core-js": "^3.47.0",
|
|
28
28
|
"eslint": "^9.39.2",
|
|
29
|
-
"eslint-plugin-jsdoc": "^
|
|
29
|
+
"eslint-plugin-jsdoc": "^62.1.0",
|
|
30
30
|
"expose-loader": "^5.0.1",
|
|
31
31
|
"file-saver": "^2.0.5",
|
|
32
|
-
"globals": "^
|
|
32
|
+
"globals": "^17.0.0",
|
|
33
33
|
"mocha": "^11.7.5",
|
|
34
34
|
"npm-run-all": "^4.1.5",
|
|
35
35
|
"process": "^0.11.10",
|
|
@@ -51,9 +51,9 @@
|
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
|
53
53
|
"test": "run-s build mocha lint",
|
|
54
|
-
"build": "run-s build:clean build:
|
|
54
|
+
"build": "run-s build:clean build:node build:browser build:standard-fonts build:fonts build:vfs",
|
|
55
55
|
"build:clean": "shx rm -rf js build",
|
|
56
|
-
"build:3rdparty": "shx cp node_modules/svg-to-pdfkit/source.js src/3rd-party/svg-to-pdfkit/source.js && shx cp node_modules/svg-to-pdfkit/LICENSE src/3rd-party/svg-to-pdfkit/LICENSE",
|
|
56
|
+
"build:3rdparty": "shx cp node_modules/svg-to-pdfkit/source.js src/3rd-party/svg-to-pdfkit/source.js && shx cp node_modules/svg-to-pdfkit/LICENSE src/3rd-party/svg-to-pdfkit/LICENSE && git apply src/3rd-party/svg-to-pdfkit/0001-fix-contains.patch",
|
|
57
57
|
"build:node": "babel src --out-dir js",
|
|
58
58
|
"build:browser": "webpack",
|
|
59
59
|
"build:vfs": "node build-vfs.js \"./examples/fonts\"",
|
|
@@ -731,7 +731,7 @@ var SVGtoPDF = function(doc, svg, x, y, options) {
|
|
|
731
731
|
if (selector.ids[i] !== elem.id) {return false;}
|
|
732
732
|
}
|
|
733
733
|
for (let i = 0; i < selector.classes.length; i++) {
|
|
734
|
-
if (
|
|
734
|
+
if (elem.classList.indexOf(selector.classes[i]) === -1) {return false;}
|
|
735
735
|
}
|
|
736
736
|
return true;
|
|
737
737
|
}
|
package/src/DocMeasure.js
CHANGED
|
@@ -95,8 +95,10 @@ class DocMeasure {
|
|
|
95
95
|
node._width = node._minWidth = node._maxWidth = node.cover.width;
|
|
96
96
|
node._height = node._minHeight = node._maxHeight = node.cover.height;
|
|
97
97
|
} else {
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
let ratio = dimensions.width / dimensions.height;
|
|
99
|
+
|
|
100
|
+
node._width = node._minWidth = node._maxWidth = node.width || (node.height ? (node.height * ratio) : dimensions.width);
|
|
101
|
+
node._height = node.height || (node.width ? node.width / ratio : dimensions.height);
|
|
100
102
|
|
|
101
103
|
if (isNumber(node.maxWidth) && node.maxWidth < node._width) {
|
|
102
104
|
node._width = node._minWidth = node._maxWidth = node.maxWidth;
|
|
@@ -154,6 +156,15 @@ class DocMeasure {
|
|
|
154
156
|
|
|
155
157
|
node.font = this.styleStack.getProperty('font');
|
|
156
158
|
|
|
159
|
+
// SVG requires a defined width and height
|
|
160
|
+
if (!isNumber(node._width) && !isNumber(node._height)) {
|
|
161
|
+
throw new Error('SVG is missing defined width and height.');
|
|
162
|
+
} else if (!isNumber(node._width)) {
|
|
163
|
+
throw new Error('SVG is missing defined width.');
|
|
164
|
+
} else if (!isNumber(node._height)) {
|
|
165
|
+
throw new Error('SVG is missing defined height.');
|
|
166
|
+
}
|
|
167
|
+
|
|
157
168
|
// scale SVG based on final dimension
|
|
158
169
|
node.svg = this.svgMeasure.writeDimensions(node.svg, { width: node._width, height: node._height });
|
|
159
170
|
|
|
@@ -190,6 +201,13 @@ class DocMeasure {
|
|
|
190
201
|
let textStyle = node.toc.textStyle || {};
|
|
191
202
|
let numberStyle = node.toc.numberStyle || textStyle;
|
|
192
203
|
let textMargin = node.toc.textMargin || [0, 0, 0, 0];
|
|
204
|
+
|
|
205
|
+
if (node.toc.sortBy === 'title') {
|
|
206
|
+
node.toc._items.sort((a, b) => {
|
|
207
|
+
return a._textNodeRef.text.localeCompare(b._textNodeRef.text, node.toc.sortLocale);
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
193
211
|
for (let i = 0, l = node.toc._items.length; i < l; i++) {
|
|
194
212
|
let item = node.toc._items[i];
|
|
195
213
|
let lineStyle = item._textNodeRef.tocStyle || textStyle;
|
|
@@ -237,7 +255,7 @@ class DocMeasure {
|
|
|
237
255
|
return this.textInlines.sizeOfText('9. ', this.styleStack);
|
|
238
256
|
}
|
|
239
257
|
|
|
240
|
-
buildUnorderedMarker(styleStack, gapSize, type) {
|
|
258
|
+
buildUnorderedMarker(item, styleStack, gapSize, type) {
|
|
241
259
|
function buildDisc(gapSize, color) {
|
|
242
260
|
// TODO: ascender-based calculations
|
|
243
261
|
let radius = gapSize.fontSize / 6;
|
|
@@ -284,7 +302,7 @@ class DocMeasure {
|
|
|
284
302
|
}
|
|
285
303
|
|
|
286
304
|
let marker;
|
|
287
|
-
let color =
|
|
305
|
+
let color = StyleContextStack.getStyleProperty(item, styleStack, 'markerColor', undefined) || styleStack.getProperty('color') || 'black';
|
|
288
306
|
|
|
289
307
|
switch (type) {
|
|
290
308
|
case 'circle':
|
|
@@ -311,7 +329,7 @@ class DocMeasure {
|
|
|
311
329
|
return marker;
|
|
312
330
|
}
|
|
313
331
|
|
|
314
|
-
buildOrderedMarker(counter, styleStack, type, separator) {
|
|
332
|
+
buildOrderedMarker(item, counter, styleStack, type, separator) {
|
|
315
333
|
function prepareAlpha(counter) {
|
|
316
334
|
function toAlpha(num) {
|
|
317
335
|
return (num >= 26 ? toAlpha((num / 26 >> 0) - 1) : '') + 'abcdefghijklmnopqrstuvwxyz'[num % 26 >> 0];
|
|
@@ -391,11 +409,11 @@ class DocMeasure {
|
|
|
391
409
|
}
|
|
392
410
|
}
|
|
393
411
|
|
|
394
|
-
let
|
|
395
|
-
let
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
}
|
|
412
|
+
let markerColor = StyleContextStack.getStyleProperty(item, styleStack, 'markerColor', undefined) || styleStack.getProperty('color') || 'black';
|
|
413
|
+
let textArray = {
|
|
414
|
+
text: counterText,
|
|
415
|
+
color: markerColor
|
|
416
|
+
};
|
|
399
417
|
|
|
400
418
|
return { _inlines: this.textInlines.buildInlines(textArray, styleStack).items };
|
|
401
419
|
}
|
|
@@ -412,7 +430,7 @@ class DocMeasure {
|
|
|
412
430
|
let item = items[i] = this.measureNode(items[i]);
|
|
413
431
|
|
|
414
432
|
if (!item.ol && !item.ul) {
|
|
415
|
-
item.listMarker = this.buildUnorderedMarker(style, node._gapSize, item.listType || node.type);
|
|
433
|
+
item.listMarker = this.buildUnorderedMarker(item, style, node._gapSize, item.listType || node.type);
|
|
416
434
|
}
|
|
417
435
|
|
|
418
436
|
node._minWidth = Math.max(node._minWidth, items[i]._minWidth + node._gapSize.width);
|
|
@@ -441,7 +459,7 @@ class DocMeasure {
|
|
|
441
459
|
|
|
442
460
|
if (!item.ol && !item.ul) {
|
|
443
461
|
let counterValue = isNumber(item.counter) ? item.counter : counter;
|
|
444
|
-
item.listMarker = this.buildOrderedMarker(counterValue, style, item.listType || node.type, node.separator);
|
|
462
|
+
item.listMarker = this.buildOrderedMarker(item, counterValue, style, item.listType || node.type, node.separator);
|
|
445
463
|
if (item.listMarker._inlines) {
|
|
446
464
|
node._gapSize.width = Math.max(node._gapSize.width, item.listMarker._inlines[0].width);
|
|
447
465
|
}
|
package/src/LayoutBuilder.js
CHANGED
package/src/StyleContextStack.js
CHANGED
|
@@ -114,14 +114,43 @@ class StyleContextStack {
|
|
|
114
114
|
* @returns {?any} property value or null if not found
|
|
115
115
|
*/
|
|
116
116
|
getProperty(property) {
|
|
117
|
+
|
|
118
|
+
const getStylePropertyFromStyle = (styleName, property, visited = new Set()) => {
|
|
119
|
+
if (visited.has(styleName)) {
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
visited.add(styleName);
|
|
123
|
+
|
|
124
|
+
const style = this.styleDictionary[styleName];
|
|
125
|
+
if (!style) {
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (isValue(style[property])) {
|
|
130
|
+
return style[property];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (style.extends) {
|
|
134
|
+
let parents = Array.isArray(style.extends) ? style.extends : [style.extends];
|
|
135
|
+
for (let i = parents.length - 1; i >= 0; i--) {
|
|
136
|
+
let value = getStylePropertyFromStyle(parents[i], property, visited);
|
|
137
|
+
if (isValue(value)) {
|
|
138
|
+
return value;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return undefined;
|
|
144
|
+
};
|
|
145
|
+
|
|
117
146
|
if (this.styleOverrides) {
|
|
118
147
|
for (let i = this.styleOverrides.length - 1; i >= 0; i--) {
|
|
119
148
|
let item = this.styleOverrides[i];
|
|
120
149
|
|
|
121
150
|
if (isString(item)) { // named-style-override
|
|
122
|
-
let
|
|
123
|
-
if (
|
|
124
|
-
return
|
|
151
|
+
let value = getStylePropertyFromStyle(item, property);
|
|
152
|
+
if (isValue(value)) {
|
|
153
|
+
return value;
|
|
125
154
|
}
|
|
126
155
|
} else if (isValue(item[property])) { // style-overrides-object
|
|
127
156
|
return item[property];
|
package/src/TextDecorator.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { isNumber } from './helpers/variableType';
|
|
2
|
+
|
|
1
3
|
const groupDecorations = line => {
|
|
2
4
|
let groups = [];
|
|
3
5
|
let currentGroup = null;
|
|
@@ -13,6 +15,7 @@ const groupDecorations = line => {
|
|
|
13
15
|
}
|
|
14
16
|
let color = inline.decorationColor || inline.color || 'black';
|
|
15
17
|
let style = inline.decorationStyle || 'solid';
|
|
18
|
+
let thickness = isNumber(inline.decorationThickness) ? inline.decorationThickness : null;
|
|
16
19
|
for (let ii = 0, ll = decoration.length; ii < ll; ii++) {
|
|
17
20
|
let decorationItem = decoration[ii];
|
|
18
21
|
if (!currentGroup || decorationItem !== currentGroup.decoration ||
|
|
@@ -23,6 +26,7 @@ const groupDecorations = line => {
|
|
|
23
26
|
decoration: decorationItem,
|
|
24
27
|
decorationColor: color,
|
|
25
28
|
decorationStyle: style,
|
|
29
|
+
decorationThickness: thickness,
|
|
26
30
|
inlines: [inline]
|
|
27
31
|
};
|
|
28
32
|
groups.push(currentGroup);
|
|
@@ -96,7 +100,9 @@ class TextDecorator {
|
|
|
96
100
|
let height = biggerInline.height;
|
|
97
101
|
let descent = height - ascent;
|
|
98
102
|
|
|
99
|
-
let lw =
|
|
103
|
+
let lw = isNumber(group.decorationThickness)
|
|
104
|
+
? group.decorationThickness
|
|
105
|
+
: 0.5 + Math.floor(Math.max(biggerInline.fontSize - 8, 0) / 2) * 0.12;
|
|
100
106
|
|
|
101
107
|
switch (group.decoration) {
|
|
102
108
|
case 'underline':
|
|
@@ -111,10 +117,18 @@ class TextDecorator {
|
|
|
111
117
|
default:
|
|
112
118
|
throw new Error(`Unknown decoration : ${group.decoration}`);
|
|
113
119
|
}
|
|
120
|
+
|
|
121
|
+
if (group.inlines[0].sup) {
|
|
122
|
+
y -= group.inlines[0].fontSize * 0.75;
|
|
123
|
+
}
|
|
124
|
+
if (group.inlines[0].sub) {
|
|
125
|
+
y += group.inlines[0].fontSize * 0.35;
|
|
126
|
+
}
|
|
127
|
+
|
|
114
128
|
this.pdfDocument.save();
|
|
115
129
|
|
|
116
130
|
if (group.decorationStyle === 'double') {
|
|
117
|
-
let gap = Math.max(0.5, lw *
|
|
131
|
+
let gap = Math.max(0.5, lw, biggerInline.fontSize * 0.15);
|
|
118
132
|
this.pdfDocument.fillColor(group.decorationColor)
|
|
119
133
|
.rect(x + firstInline.x, y - lw / 2, totalWidth, lw / 2).fill()
|
|
120
134
|
.rect(x + firstInline.x, y + gap - lw / 2, totalWidth, lw / 2).fill();
|
|
@@ -141,7 +155,7 @@ class TextDecorator {
|
|
|
141
155
|
let nbWaves = Math.ceil(totalWidth / (sh * 2)) + 1;
|
|
142
156
|
let rwx = x + firstInline.x - 1;
|
|
143
157
|
this.pdfDocument.rect(x + firstInline.x, y - sv, totalWidth, y + sv).clip();
|
|
144
|
-
this.pdfDocument.lineWidth(
|
|
158
|
+
this.pdfDocument.lineWidth(lw / 3);
|
|
145
159
|
this.pdfDocument.moveTo(rwx, y);
|
|
146
160
|
for (let i = 0; i < nbWaves; i++) {
|
|
147
161
|
this.pdfDocument.bezierCurveTo(rwx + sh, y - sv, rwx + sh * 2, y - sv, rwx + sh * 3, y)
|
package/src/TextInlines.js
CHANGED
|
@@ -117,6 +117,7 @@ class TextInlines {
|
|
|
117
117
|
item.decoration = StyleContextStack.getStyleProperty(item, styleContextStack, 'decoration', null);
|
|
118
118
|
item.decorationColor = StyleContextStack.getStyleProperty(item, styleContextStack, 'decorationColor', null);
|
|
119
119
|
item.decorationStyle = StyleContextStack.getStyleProperty(item, styleContextStack, 'decorationStyle', null);
|
|
120
|
+
item.decorationThickness = StyleContextStack.getStyleProperty(item, styleContextStack, 'decorationThickness', null);
|
|
120
121
|
item.background = StyleContextStack.getStyleProperty(item, styleContextStack, 'background', null);
|
|
121
122
|
item.link = StyleContextStack.getStyleProperty(item, styleContextStack, 'link', null);
|
|
122
123
|
item.linkToPage = StyleContextStack.getStyleProperty(item, styleContextStack, 'linkToPage', null);
|