pdfmake 0.3.0-beta.8 → 0.3.0

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.
Files changed (87) hide show
  1. package/CHANGELOG.md +7 -40
  2. package/LICENSE +1 -1
  3. package/README.md +78 -85
  4. package/build/pdfmake.js +60308 -68400
  5. package/build/pdfmake.js.map +1 -1
  6. package/build/pdfmake.min.js +2 -2
  7. package/build/pdfmake.min.js.map +1 -1
  8. package/build/vfs_fonts.js +4 -4
  9. package/fonts/Roboto/Roboto-Italic.ttf +0 -0
  10. package/fonts/Roboto/Roboto-Medium.ttf +0 -0
  11. package/fonts/Roboto/Roboto-MediumItalic.ttf +0 -0
  12. package/fonts/Roboto/Roboto-Regular.ttf +0 -0
  13. package/js/3rd-party/svg-to-pdfkit/source.js +3626 -0
  14. package/js/3rd-party/svg-to-pdfkit.js +7 -0
  15. package/js/DocMeasure.js +645 -0
  16. package/js/DocPreprocessor.js +253 -0
  17. package/js/DocumentContext.js +305 -0
  18. package/js/ElementWriter.js +354 -0
  19. package/js/LayoutBuilder.js +1105 -0
  20. package/js/Line.js +105 -0
  21. package/js/OutputDocument.js +64 -0
  22. package/js/OutputDocumentServer.js +22 -0
  23. package/js/PDFDocument.js +144 -0
  24. package/js/PageElementWriter.js +155 -0
  25. package/js/PageSize.js +74 -0
  26. package/js/Printer.js +291 -0
  27. package/js/Renderer.js +383 -0
  28. package/js/SVGMeasure.js +69 -0
  29. package/js/StyleContextStack.js +168 -0
  30. package/js/TableProcessor.js +548 -0
  31. package/js/TextBreaker.js +166 -0
  32. package/js/TextDecorator.js +143 -0
  33. package/js/TextInlines.js +206 -0
  34. package/js/URLResolver.js +43 -0
  35. package/js/base.js +52 -0
  36. package/js/browser-extensions/OutputDocumentBrowser.js +81 -0
  37. package/js/browser-extensions/fonts/Roboto.js +38 -0
  38. package/js/browser-extensions/index.js +53 -0
  39. package/js/browser-extensions/pdfMake.js +3 -0
  40. package/js/browser-extensions/standard-fonts/Courier.js +38 -0
  41. package/js/browser-extensions/standard-fonts/Helvetica.js +38 -0
  42. package/js/browser-extensions/standard-fonts/Symbol.js +23 -0
  43. package/js/browser-extensions/standard-fonts/Times.js +38 -0
  44. package/js/browser-extensions/standard-fonts/ZapfDingbats.js +23 -0
  45. package/js/browser-extensions/virtual-fs-cjs.js +3 -0
  46. package/js/columnCalculator.js +148 -0
  47. package/js/helpers/node.js +98 -0
  48. package/js/helpers/tools.js +46 -0
  49. package/js/helpers/variableType.js +59 -0
  50. package/js/index.js +15 -0
  51. package/js/qrEnc.js +721 -0
  52. package/js/standardPageSizes.js +56 -0
  53. package/js/tableLayouts.js +98 -0
  54. package/js/virtual-fs.js +60 -0
  55. package/package.json +25 -24
  56. package/src/DocMeasure.js +28 -7
  57. package/src/DocPreprocessor.js +25 -6
  58. package/src/DocumentContext.js +62 -33
  59. package/src/ElementWriter.js +30 -7
  60. package/src/LayoutBuilder.js +557 -120
  61. package/src/OutputDocument.js +23 -37
  62. package/src/OutputDocumentServer.js +6 -11
  63. package/src/PDFDocument.js +1 -1
  64. package/src/PageElementWriter.js +21 -2
  65. package/src/Printer.js +134 -131
  66. package/src/Renderer.js +13 -15
  67. package/src/SVGMeasure.js +2 -2
  68. package/src/StyleContextStack.js +7 -44
  69. package/src/TableProcessor.js +62 -22
  70. package/src/TextBreaker.js +24 -5
  71. package/src/TextInlines.js +1 -1
  72. package/src/URLResolver.js +24 -58
  73. package/src/base.js +1 -1
  74. package/src/browser-extensions/OutputDocumentBrowser.js +33 -71
  75. package/src/browser-extensions/index.js +3 -3
  76. package/src/browser-extensions/pdfMake.js +0 -14
  77. package/src/browser-extensions/standard-fonts/Courier.js +4 -4
  78. package/src/browser-extensions/standard-fonts/Helvetica.js +4 -4
  79. package/src/browser-extensions/standard-fonts/Symbol.js +1 -1
  80. package/src/browser-extensions/standard-fonts/Times.js +4 -4
  81. package/src/browser-extensions/standard-fonts/ZapfDingbats.js +1 -1
  82. package/src/columnCalculator.js +24 -3
  83. package/src/helpers/tools.js +5 -0
  84. package/src/helpers/variableType.js +11 -0
  85. package/src/index.js +1 -1
  86. package/standard-fonts/Helvetica.js +0 -1
  87. package/src/browser-extensions/URLBrowserResolver.js +0 -84
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.default = void 0;
5
+ var _default = exports.default = {
6
+ '4A0': [4767.87, 6740.79],
7
+ '2A0': [3370.39, 4767.87],
8
+ A0: [2383.94, 3370.39],
9
+ A1: [1683.78, 2383.94],
10
+ A2: [1190.55, 1683.78],
11
+ A3: [841.89, 1190.55],
12
+ A4: [595.28, 841.89],
13
+ A5: [419.53, 595.28],
14
+ A6: [297.64, 419.53],
15
+ A7: [209.76, 297.64],
16
+ A8: [147.40, 209.76],
17
+ A9: [104.88, 147.40],
18
+ A10: [73.70, 104.88],
19
+ B0: [2834.65, 4008.19],
20
+ B1: [2004.09, 2834.65],
21
+ B2: [1417.32, 2004.09],
22
+ B3: [1000.63, 1417.32],
23
+ B4: [708.66, 1000.63],
24
+ B5: [498.90, 708.66],
25
+ B6: [354.33, 498.90],
26
+ B7: [249.45, 354.33],
27
+ B8: [175.75, 249.45],
28
+ B9: [124.72, 175.75],
29
+ B10: [87.87, 124.72],
30
+ C0: [2599.37, 3676.54],
31
+ C1: [1836.85, 2599.37],
32
+ C2: [1298.27, 1836.85],
33
+ C3: [918.43, 1298.27],
34
+ C4: [649.13, 918.43],
35
+ C5: [459.21, 649.13],
36
+ C6: [323.15, 459.21],
37
+ C7: [229.61, 323.15],
38
+ C8: [161.57, 229.61],
39
+ C9: [113.39, 161.57],
40
+ C10: [79.37, 113.39],
41
+ RA0: [2437.80, 3458.27],
42
+ RA1: [1729.13, 2437.80],
43
+ RA2: [1218.90, 1729.13],
44
+ RA3: [864.57, 1218.90],
45
+ RA4: [609.45, 864.57],
46
+ SRA0: [2551.18, 3628.35],
47
+ SRA1: [1814.17, 2551.18],
48
+ SRA2: [1275.59, 1814.17],
49
+ SRA3: [907.09, 1275.59],
50
+ SRA4: [637.80, 907.09],
51
+ EXECUTIVE: [521.86, 756.00],
52
+ FOLIO: [612.00, 936.00],
53
+ LEGAL: [612.00, 1008.00],
54
+ LETTER: [612.00, 792.00],
55
+ TABLOID: [792.00, 1224.00]
56
+ };
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.tableLayouts = exports.defaultTableLayout = void 0;
5
+ /*eslint no-unused-vars: ["error", {"args": "none"}]*/
6
+
7
+ const tableLayouts = exports.tableLayouts = {
8
+ noBorders: {
9
+ hLineWidth(i) {
10
+ return 0;
11
+ },
12
+ vLineWidth(i) {
13
+ return 0;
14
+ },
15
+ paddingLeft(i) {
16
+ return i && 4 || 0;
17
+ },
18
+ paddingRight(i, node) {
19
+ return i < node.table.widths.length - 1 ? 4 : 0;
20
+ }
21
+ },
22
+ headerLineOnly: {
23
+ hLineWidth(i, node) {
24
+ if (i === 0 || i === node.table.body.length) {
25
+ return 0;
26
+ }
27
+ return i === node.table.headerRows ? 2 : 0;
28
+ },
29
+ vLineWidth(i) {
30
+ return 0;
31
+ },
32
+ paddingLeft(i) {
33
+ return i === 0 ? 0 : 8;
34
+ },
35
+ paddingRight(i, node) {
36
+ return i === node.table.widths.length - 1 ? 0 : 8;
37
+ }
38
+ },
39
+ lightHorizontalLines: {
40
+ hLineWidth(i, node) {
41
+ if (i === 0 || i === node.table.body.length) {
42
+ return 0;
43
+ }
44
+ return i === node.table.headerRows ? 2 : 1;
45
+ },
46
+ vLineWidth(i) {
47
+ return 0;
48
+ },
49
+ hLineColor(i) {
50
+ return i === 1 ? 'black' : '#aaa';
51
+ },
52
+ paddingLeft(i) {
53
+ return i === 0 ? 0 : 8;
54
+ },
55
+ paddingRight(i, node) {
56
+ return i === node.table.widths.length - 1 ? 0 : 8;
57
+ }
58
+ }
59
+ };
60
+ const defaultTableLayout = exports.defaultTableLayout = {
61
+ hLineWidth(i, node) {
62
+ return 1;
63
+ },
64
+ vLineWidth(i, node) {
65
+ return 1;
66
+ },
67
+ hLineColor(i, node) {
68
+ return 'black';
69
+ },
70
+ vLineColor(i, node) {
71
+ return 'black';
72
+ },
73
+ hLineStyle(i, node) {
74
+ return null;
75
+ },
76
+ vLineStyle(i, node) {
77
+ return null;
78
+ },
79
+ paddingLeft(i, node) {
80
+ return 4;
81
+ },
82
+ paddingRight(i, node) {
83
+ return 4;
84
+ },
85
+ paddingTop(i, node) {
86
+ return 2;
87
+ },
88
+ paddingBottom(i, node) {
89
+ return 2;
90
+ },
91
+ fillColor(i, node) {
92
+ return null;
93
+ },
94
+ fillOpacity(i, node) {
95
+ return 1;
96
+ },
97
+ defaultBorder: true
98
+ };
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.default = void 0;
5
+ const normalizeFilename = filename => {
6
+ if (filename.indexOf(__dirname) === 0) {
7
+ filename = filename.substring(__dirname.length);
8
+ }
9
+ if (filename.indexOf('/') === 0) {
10
+ filename = filename.substring(1);
11
+ }
12
+ return filename;
13
+ };
14
+ class VirtualFileSystem {
15
+ constructor() {
16
+ this.storage = {};
17
+ }
18
+
19
+ /**
20
+ * @param {string} filename
21
+ * @returns {boolean}
22
+ */
23
+ existsSync(filename) {
24
+ const normalizedFilename = normalizeFilename(filename);
25
+ return typeof this.storage[normalizedFilename] !== 'undefined';
26
+ }
27
+
28
+ /**
29
+ * @param {string} filename
30
+ * @param {?string|?object} options
31
+ * @returns {string|Buffer}
32
+ */
33
+ readFileSync(filename, options) {
34
+ const normalizedFilename = normalizeFilename(filename);
35
+ const encoding = typeof options === 'object' ? options.encoding : options;
36
+ if (!this.existsSync(normalizedFilename)) {
37
+ throw new Error(`File '${normalizedFilename}' not found in virtual file system`);
38
+ }
39
+ const buffer = this.storage[normalizedFilename];
40
+ if (encoding) {
41
+ return buffer.toString(encoding);
42
+ }
43
+ return buffer;
44
+ }
45
+
46
+ /**
47
+ * @param {string} filename
48
+ * @param {string|Buffer} content
49
+ * @param {?string|?object} options
50
+ */
51
+ writeFileSync(filename, content, options) {
52
+ const normalizedFilename = normalizeFilename(filename);
53
+ const encoding = typeof options === 'object' ? options.encoding : options;
54
+ if (!content && !options) {
55
+ throw new Error('No content');
56
+ }
57
+ this.storage[normalizedFilename] = encoding || typeof content === 'string' ? new Buffer(content, encoding) : content;
58
+ }
59
+ }
60
+ var _default = exports.default = new VirtualFileSystem();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pdfmake",
3
- "version": "0.3.0-beta.8",
3
+ "version": "0.3.0",
4
4
  "description": "Client/server side PDF printing in pure JavaScript",
5
5
  "main": "js/index.js",
6
6
  "esnext": "src/index.js",
@@ -9,44 +9,45 @@
9
9
  "test": "tests"
10
10
  },
11
11
  "dependencies": {
12
- "@foliojs-fork/linebreak": "^1.1.1",
13
- "@foliojs-fork/pdfkit": "^0.14.0",
14
- "iconv-lite": "^0.6.3",
15
- "xmldoc": "^1.3.0"
12
+ "linebreak": "^1.1.0",
13
+ "pdfkit": "^0.17.2",
14
+ "xmldoc": "^2.0.3"
16
15
  },
17
16
  "devDependencies": {
18
- "@babel/cli": "^7.23.4",
19
- "@babel/core": "^7.23.6",
20
- "@babel/plugin-transform-modules-commonjs": "^7.23.3",
21
- "@babel/preset-env": "^7.23.6",
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",
21
+ "@eslint/js": "^9.39.2",
22
22
  "assert": "^2.1.0",
23
- "babel-loader": "^9.1.3",
23
+ "babel-loader": "^10.0.0",
24
24
  "brfs": "^2.0.2",
25
25
  "browserify-zlib": "^0.2.0",
26
- "buffer": "6.0.3",
27
- "core-js": "3.19.0",
28
- "eslint": "^8.55.0",
29
- "eslint-plugin-jsdoc": "^46.9.1",
30
- "expose-loader": "^4.1.0",
26
+ "buffer": "^6.0.3",
27
+ "core-js": "^3.47.0",
28
+ "eslint": "^9.39.2",
29
+ "eslint-plugin-jsdoc": "^61.5.0",
30
+ "expose-loader": "^5.0.1",
31
31
  "file-saver": "^2.0.5",
32
- "mocha": "^10.2.0",
32
+ "globals": "^16.5.0",
33
+ "mocha": "^11.7.5",
33
34
  "npm-run-all": "^4.1.5",
34
35
  "process": "^0.11.10",
35
- "rewire": "^7.0.0",
36
- "shx": "^0.3.4",
37
- "sinon": "^17.0.1",
38
- "source-map-loader": "^4.0.1",
36
+ "rewire": "^9.0.1",
37
+ "shx": "^0.4.0",
38
+ "sinon": "^21.0.1",
39
+ "source-map-loader": "^5.0.0",
39
40
  "stream-browserify": "^3.0.0",
40
41
  "string-replace-webpack-plugin": "^0.1.3",
41
42
  "svg-to-pdfkit": "^0.1.8",
42
- "terser-webpack-plugin": "^5.3.9",
43
+ "terser-webpack-plugin": "^5.3.16",
43
44
  "transform-loader": "^0.2.4",
44
45
  "util": "^0.12.5",
45
- "webpack": "^5.89.0",
46
- "webpack-cli": "^5.1.4"
46
+ "webpack": "^5.104.1",
47
+ "webpack-cli": "^6.0.1"
47
48
  },
48
49
  "engines": {
49
- "node": ">=16"
50
+ "node": ">=20"
50
51
  },
51
52
  "scripts": {
52
53
  "test": "run-s build mocha lint",
package/src/DocMeasure.js CHANGED
@@ -34,12 +34,18 @@ class DocMeasure {
34
34
  return this.measureNode(docStructure);
35
35
  }
36
36
 
37
+ measureBlock(node) {
38
+ return this.measureNode(node);
39
+ }
40
+
37
41
  measureNode(node) {
38
42
  return this.styleStack.auto(node, () => {
39
43
  // TODO: refactor + rethink whether this is the proper way to handle margins
40
44
  node._margin = getNodeMargin(node, this.styleStack);
41
45
 
42
- if (node.columns) {
46
+ if (node.section) {
47
+ return extendMargins(this.measureSection(node));
48
+ } else if (node.columns) {
43
49
  return extendMargins(this.measureColumns(node));
44
50
  } else if (node.stack) {
45
51
  return extendMargins(this.measureVerticalContainer(node));
@@ -128,8 +134,14 @@ class DocMeasure {
128
134
  this.convertIfBase64Image(node);
129
135
 
130
136
  let image = this.pdfDocument.provideImage(node.image);
137
+
131
138
  let imageSize = { width: image.width, height: image.height };
132
139
 
140
+ // If EXIF orientation calls for it, swap width and height
141
+ if (image.orientation > 4) {
142
+ imageSize = { width: image.height, height: image.width };
143
+ }
144
+
133
145
  this.measureImageWithDimensions(node, imageSize);
134
146
 
135
147
  return node;
@@ -433,16 +445,17 @@ class DocMeasure {
433
445
  if (item.listMarker._inlines) {
434
446
  node._gapSize.width = Math.max(node._gapSize.width, item.listMarker._inlines[0].width);
435
447
  }
436
- } // TODO: else - nested lists numbering
448
+
449
+ if (node.reversed) {
450
+ counter--;
451
+ } else {
452
+ counter++;
453
+ }
454
+ }
437
455
 
438
456
  node._minWidth = Math.max(node._minWidth, items[i]._minWidth);
439
457
  node._maxWidth = Math.max(node._maxWidth, items[i]._maxWidth);
440
458
 
441
- if (node.reversed) {
442
- counter--;
443
- } else {
444
- counter++;
445
- }
446
459
  }
447
460
 
448
461
  node._minWidth += node._gapSize.width;
@@ -458,6 +471,14 @@ class DocMeasure {
458
471
  return node;
459
472
  }
460
473
 
474
+ measureSection(node) {
475
+ // TODO: properties
476
+
477
+ node.section = this.measureNode(node.section);
478
+
479
+ return node;
480
+ }
481
+
461
482
  measureColumns(node) {
462
483
  let columns = node.columns;
463
484
  node._gap = this.styleStack.getProperty('columnGap') || 0;
@@ -20,10 +20,17 @@ class DocPreprocessor {
20
20
  this.parentNode = null;
21
21
  this.tocs = [];
22
22
  this.nodeReferences = [];
23
- return this.preprocessNode(docStructure);
23
+ return this.preprocessNode(docStructure, true);
24
24
  }
25
25
 
26
- preprocessNode(node) {
26
+ preprocessBlock(node) {
27
+ this.parentNode = null;
28
+ this.tocs = [];
29
+ this.nodeReferences = [];
30
+ return this.preprocessNode(node);
31
+ }
32
+
33
+ preprocessNode(node, isSectionAllowed = false) {
27
34
  // expand shortcuts and casting values
28
35
  if (Array.isArray(node)) {
29
36
  node = { stack: node };
@@ -33,10 +40,16 @@ class DocPreprocessor {
33
40
  node.text = convertValueToString(node.text);
34
41
  }
35
42
 
36
- if (node.columns) {
43
+ if (node.section) {
44
+ if (!isSectionAllowed) {
45
+ throw new Error(`Incorrect document structure, section node is only allowed at the root level of document structure: ${stringifyNode(node)}`);
46
+ }
47
+
48
+ return this.preprocessSection(node);
49
+ } else if (node.columns) {
37
50
  return this.preprocessColumns(node);
38
51
  } else if (node.stack) {
39
- return this.preprocessVerticalContainer(node);
52
+ return this.preprocessVerticalContainer(node, isSectionAllowed);
40
53
  } else if (node.ul) {
41
54
  return this.preprocessList(node);
42
55
  } else if (node.ol) {
@@ -64,6 +77,12 @@ class DocPreprocessor {
64
77
  }
65
78
  }
66
79
 
80
+ preprocessSection(node) {
81
+ node.section = this.preprocessNode(node.section);
82
+
83
+ return node;
84
+ }
85
+
67
86
  preprocessColumns(node) {
68
87
  let columns = node.columns;
69
88
 
@@ -74,11 +93,11 @@ class DocPreprocessor {
74
93
  return node;
75
94
  }
76
95
 
77
- preprocessVerticalContainer(node) {
96
+ preprocessVerticalContainer(node, isSectionAllowed) {
78
97
  let items = node.stack;
79
98
 
80
99
  for (let i = 0, l = items.length; i < l; i++) {
81
- items[i] = this.preprocessNode(items[i]);
100
+ items[i] = this.preprocessNode(items[i], isSectionAllowed);
82
101
  }
83
102
 
84
103
  return node;
@@ -6,31 +6,27 @@ import { EventEmitter } from 'events';
6
6
  * It facilitates column divisions and vertical sync
7
7
  */
8
8
  class DocumentContext extends EventEmitter {
9
- constructor(pageSize, pageMargins) {
9
+ constructor() {
10
10
  super();
11
11
  this.pages = [];
12
-
13
- this.pageMargins = pageMargins;
14
-
15
- this.x = pageMargins.left;
16
- this.availableWidth = pageSize.width - pageMargins.left - pageMargins.right;
17
- this.availableHeight = 0;
12
+ this.pageMargins = undefined;
13
+ this.x = undefined;
14
+ this.availableWidth = undefined;
15
+ this.availableHeight = undefined;
18
16
  this.page = -1;
19
17
 
20
18
  this.snapshots = [];
21
- this.endingCell = null;
22
19
  this.backgroundLength = [];
23
-
24
- this.addPage(pageSize);
25
20
  }
26
21
 
27
- beginColumnGroup() {
22
+ beginColumnGroup(marginXTopParent, bottomByPage = {}) {
28
23
  this.snapshots.push({
29
24
  x: this.x,
30
25
  y: this.y,
31
26
  availableHeight: this.availableHeight,
32
27
  availableWidth: this.availableWidth,
33
28
  page: this.page,
29
+ bottomByPage: bottomByPage ? bottomByPage : {},
34
30
  bottomMost: {
35
31
  x: this.x,
36
32
  y: this.y,
@@ -38,19 +34,34 @@ class DocumentContext extends EventEmitter {
38
34
  availableWidth: this.availableWidth,
39
35
  page: this.page
40
36
  },
41
- endingCell: this.endingCell,
42
37
  lastColumnWidth: this.lastColumnWidth
43
38
  });
44
39
 
45
40
  this.lastColumnWidth = 0;
41
+ if (marginXTopParent) {
42
+ this.marginXTopParent = marginXTopParent;
43
+ }
44
+ }
45
+
46
+ updateBottomByPage() {
47
+ const lastSnapshot = this.snapshots[this.snapshots.length - 1];
48
+ const lastPage = this.page;
49
+ let previousBottom = -Number.MIN_VALUE;
50
+ if (lastSnapshot.bottomByPage[lastPage]) {
51
+ previousBottom = lastSnapshot.bottomByPage[lastPage];
52
+ }
53
+ lastSnapshot.bottomByPage[lastPage] = Math.max(previousBottom, this.y);
54
+ }
55
+
56
+ resetMarginXTopParent() {
57
+ this.marginXTopParent = null;
46
58
  }
47
59
 
48
60
  beginColumn(width, offset, endingCell) {
49
61
  let saved = this.snapshots[this.snapshots.length - 1];
50
62
 
51
- this.calculateBottomMost(saved);
63
+ this.calculateBottomMost(saved, endingCell);
52
64
 
53
- this.endingCell = endingCell;
54
65
  this.page = saved.page;
55
66
  this.x = this.x + this.lastColumnWidth + (offset || 0);
56
67
  this.y = saved.y;
@@ -60,19 +71,18 @@ class DocumentContext extends EventEmitter {
60
71
  this.lastColumnWidth = width;
61
72
  }
62
73
 
63
- calculateBottomMost(destContext) {
64
- if (this.endingCell) {
65
- this.saveContextInEndingCell(this.endingCell);
66
- this.endingCell = null;
74
+ calculateBottomMost(destContext, endingCell) {
75
+ if (endingCell) {
76
+ this.saveContextInEndingCell(endingCell);
67
77
  } else {
68
78
  destContext.bottomMost = bottomMostContext(this, destContext.bottomMost);
69
79
  }
70
80
  }
71
81
 
72
- markEnding(endingCell) {
82
+ markEnding(endingCell, originalXOffset, discountY) {
73
83
  this.page = endingCell._columnEndingContext.page;
74
- this.x = endingCell._columnEndingContext.x;
75
- this.y = endingCell._columnEndingContext.y;
84
+ this.x = endingCell._columnEndingContext.x + originalXOffset;
85
+ this.y = endingCell._columnEndingContext.y - discountY;
76
86
  this.availableWidth = endingCell._columnEndingContext.availableWidth;
77
87
  this.availableHeight = endingCell._columnEndingContext.availableHeight;
78
88
  this.lastColumnWidth = endingCell._columnEndingContext.lastColumnWidth;
@@ -89,12 +99,11 @@ class DocumentContext extends EventEmitter {
89
99
  };
90
100
  }
91
101
 
92
- completeColumnGroup(height) {
102
+ completeColumnGroup(height, endingCell) {
93
103
  let saved = this.snapshots.pop();
94
104
 
95
- this.calculateBottomMost(saved);
105
+ this.calculateBottomMost(saved, endingCell);
96
106
 
97
- this.endingCell = null;
98
107
  this.x = saved.x;
99
108
 
100
109
  let y = saved.bottomMost.y;
@@ -116,6 +125,7 @@ class DocumentContext extends EventEmitter {
116
125
  this.availableHeight -= (y - saved.bottomMost.y);
117
126
  }
118
127
  this.lastColumnWidth = saved.lastColumnWidth;
128
+ return saved.bottomByPage;
119
129
  }
120
130
 
121
131
  addMargin(left, right) {
@@ -133,14 +143,19 @@ class DocumentContext extends EventEmitter {
133
143
  initializePage() {
134
144
  this.y = this.pageMargins.top;
135
145
  this.availableHeight = this.getCurrentPage().pageSize.height - this.pageMargins.top - this.pageMargins.bottom;
136
- this.pageSnapshot().availableWidth = this.getCurrentPage().pageSize.width - this.pageMargins.left - this.pageMargins.right;
146
+ const { pageCtx, isSnapshot } = this.pageSnapshot();
147
+ pageCtx.availableWidth = this.getCurrentPage().pageSize.width - this.pageMargins.left - this.pageMargins.right;
148
+ if (isSnapshot && this.marginXTopParent) {
149
+ pageCtx.availableWidth -= this.marginXTopParent[0];
150
+ pageCtx.availableWidth -= this.marginXTopParent[1];
151
+ }
137
152
  }
138
153
 
139
154
  pageSnapshot() {
140
155
  if (this.snapshots[0]) {
141
- return this.snapshots[0];
156
+ return { pageCtx: this.snapshots[0], isSnapshot: true };
142
157
  } else {
143
- return this;
158
+ return { pageCtx: this, isSnapshot: false };
144
159
  }
145
160
  }
146
161
 
@@ -171,7 +186,6 @@ class DocumentContext extends EventEmitter {
171
186
  availableHeight: this.availableHeight,
172
187
  availableWidth: this.availableWidth,
173
188
  page: this.page,
174
- endingCell: this.endingCell,
175
189
  lastColumnWidth: this.lastColumnWidth
176
190
  });
177
191
  }
@@ -184,7 +198,6 @@ class DocumentContext extends EventEmitter {
184
198
  this.availableWidth = saved.availableWidth;
185
199
  this.availableHeight = saved.availableHeight;
186
200
  this.page = saved.page;
187
- this.endingCell = saved.endingCell;
188
201
  this.lastColumnWidth = saved.lastColumnWidth;
189
202
  }
190
203
 
@@ -193,13 +206,23 @@ class DocumentContext extends EventEmitter {
193
206
  let prevPage = this.page;
194
207
  let prevY = this.y;
195
208
 
209
+ // If we are in a column group
210
+ if (this.snapshots.length > 0) {
211
+ let lastSnapshot = this.snapshots[this.snapshots.length - 1];
212
+ // We have to update prevY accordingly by also taking into consideration
213
+ // the 'y' of cells that don't break page
214
+ if (lastSnapshot.bottomMost && lastSnapshot.bottomMost.y) {
215
+ prevY = Math.max(this.y, lastSnapshot.bottomMost.y);
216
+ }
217
+ }
218
+
196
219
  let createNewPage = nextPageIndex >= this.pages.length;
197
220
  if (createNewPage) {
198
221
  let currentAvailableWidth = this.availableWidth;
199
222
  let currentPageOrientation = this.getCurrentPage().pageSize.orientation;
200
223
 
201
224
  let pageSize = getPageSize(this.getCurrentPage(), pageOrientation);
202
- this.addPage(pageSize);
225
+ this.addPage(pageSize, null, this.getCurrentPage().customProperties);
203
226
 
204
227
  if (currentPageOrientation === pageSize.orientation) {
205
228
  this.availableWidth = currentAvailableWidth;
@@ -217,14 +240,20 @@ class DocumentContext extends EventEmitter {
217
240
  };
218
241
  }
219
242
 
220
- addPage(pageSize) {
221
- let page = { items: [], pageSize: pageSize };
243
+ addPage(pageSize, pageMargin = null, customProperties = {}) {
244
+ if (pageMargin !== null) {
245
+ this.pageMargins = pageMargin;
246
+ this.x = pageMargin.left;
247
+ this.availableWidth = pageSize.width - pageMargin.left - pageMargin.right;
248
+ }
249
+
250
+ let page = { items: [], pageSize: pageSize, pageMargins: this.pageMargins, customProperties: customProperties };
222
251
  this.pages.push(page);
223
252
  this.backgroundLength.push(0);
224
253
  this.page = this.pages.length - 1;
225
254
  this.initializePage();
226
255
 
227
- this.emit('pageAdded');
256
+ this.emit('pageAdded', page);
228
257
 
229
258
  return page;
230
259
  }