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.
@@ -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 (!elem.classList.contains(selector.classes[i])) {
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
- node._width = node._minWidth = node._maxWidth = node.width || dimensions.width;
90
- node._height = node.height || dimensions.height * node._width / dimensions.width;
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 = styleStack.getProperty('markerColor') || styleStack.getProperty('color') || 'black';
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
  }
@@ -987,6 +987,9 @@ class LayoutBuilder {
987
987
  }
988
988
  }
989
989
  processToc(node) {
990
+ if (!node.toc._table && node.toc.hideEmpty === true) {
991
+ return;
992
+ }
990
993
  if (node.toc.title) {
991
994
  this.processNode(node.toc.title);
992
995
  }
@@ -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 style = this.styleDictionary[item];
118
- if (style && (0, _variableType.isValue)(style[property])) {
119
- return style[property];
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
@@ -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 * 2);
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(0.24);
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);
@@ -63,8 +63,9 @@ class OutputDocumentBrowser extends _OutputDocument.default {
63
63
  }, 500);
64
64
  }
65
65
  */
66
- } finally {
66
+ } catch (e) {
67
67
  win.close();
68
+ throw e;
68
69
  }
69
70
  }
70
71
 
@@ -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 || currentMargin[0] || 0, node.marginTop || currentMargin[1] || 0, node.marginRight || currentMargin[2] || 0, node.marginBottom || currentMargin[3] || 0];
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 i = styleArray.length - 1; i >= 0; i--) {
59
- let styleName = styleArray[i];
64
+ for (let index = 0; index < styleArray.length; index++) {
65
+ let styleName = styleArray[index];
60
66
  let style = styleStack.styleDictionary[styleName];
61
- for (let key in style) {
62
- if (style.hasOwnProperty(key)) {
63
- flattenedStyles[key] = style[key];
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.1",
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.3",
18
- "@babel/core": "^7.28.5",
19
- "@babel/plugin-transform-modules-commonjs": "^7.27.1",
20
- "@babel/preset-env": "^7.28.5",
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": "^61.5.0",
29
+ "eslint-plugin-jsdoc": "^62.1.0",
30
30
  "expose-loader": "^5.0.1",
31
31
  "file-saver": "^2.0.5",
32
- "globals": "^16.5.0",
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:3rdparty build:node build:browser build:standard-fonts build:fonts build:vfs",
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 (!elem.classList.contains(selector.classes[i])) {return false;}
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
- node._width = node._minWidth = node._maxWidth = node.width || dimensions.width;
99
- node._height = node.height || (dimensions.height * node._width / dimensions.width);
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 = styleStack.getProperty('markerColor') || styleStack.getProperty('color') || 'black';
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 textArray = { text: counterText };
395
- let markerColor = styleStack.getProperty('markerColor');
396
- if (markerColor) {
397
- textArray.color = markerColor;
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
  }
@@ -1112,6 +1112,10 @@ class LayoutBuilder {
1112
1112
  }
1113
1113
 
1114
1114
  processToc(node) {
1115
+ if (!node.toc._table && node.toc.hideEmpty === true) {
1116
+ return;
1117
+ }
1118
+
1115
1119
  if (node.toc.title) {
1116
1120
  this.processNode(node.toc.title);
1117
1121
  }
@@ -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 style = this.styleDictionary[item];
123
- if (style && isValue(style[property])) {
124
- return style[property];
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];
@@ -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 = 0.5 + Math.floor(Math.max(biggerInline.fontSize - 8, 0) / 2) * 0.12;
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 * 2);
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(0.24);
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)
@@ -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);
@@ -60,8 +60,9 @@ class OutputDocumentBrowser extends OutputDocument {
60
60
  }, 500);
61
61
  }
62
62
  */
63
- } finally {
63
+ } catch (e) {
64
64
  win.close();
65
+ throw e;
65
66
  }
66
67
  }
67
68