pdfmake 0.2.4 → 0.3.0-beta.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.
Files changed (128) hide show
  1. package/CHANGELOG.md +10 -27
  2. package/README.md +11 -7
  3. package/build/pdfmake.js +44733 -42435
  4. package/build/pdfmake.js.map +1 -1
  5. package/build/pdfmake.min.js +2 -2
  6. package/build/pdfmake.min.js.map +1 -1
  7. package/build/standard-fonts/Courier.js +27 -0
  8. package/build/standard-fonts/Helvetica.js +27 -0
  9. package/build/standard-fonts/Symbol.js +21 -0
  10. package/build/standard-fonts/Times.js +27 -0
  11. package/build/standard-fonts/ZapfDingbats.js +21 -0
  12. package/build/vfs_fonts.js +2 -2
  13. package/build-vfs.js +2 -2
  14. package/fonts/Roboto/Roboto-Italic.ttf +0 -0
  15. package/fonts/Roboto/Roboto-Medium.ttf +0 -0
  16. package/fonts/Roboto/Roboto-MediumItalic.ttf +0 -0
  17. package/fonts/Roboto/Roboto-Regular.ttf +0 -0
  18. package/fonts/Roboto.js +8 -0
  19. package/js/3rd-party/svg-to-pdfkit/source.js +4301 -0
  20. package/js/3rd-party/svg-to-pdfkit.js +11 -0
  21. package/js/DocMeasure.js +758 -0
  22. package/js/DocPreprocessor.js +291 -0
  23. package/js/DocumentContext.js +306 -0
  24. package/js/ElementWriter.js +400 -0
  25. package/js/LayoutBuilder.js +840 -0
  26. package/js/Line.js +125 -0
  27. package/js/OutputDocument.js +86 -0
  28. package/js/OutputDocumentServer.js +34 -0
  29. package/js/PDFDocument.js +190 -0
  30. package/js/PageElementWriter.js +165 -0
  31. package/js/PageSize.js +88 -0
  32. package/js/Printer.js +300 -0
  33. package/js/Renderer.js +463 -0
  34. package/js/SVGMeasure.js +89 -0
  35. package/js/StyleContextStack.js +206 -0
  36. package/js/TableProcessor.js +590 -0
  37. package/js/TextBreaker.js +182 -0
  38. package/js/TextDecorator.js +181 -0
  39. package/js/TextInlines.js +248 -0
  40. package/js/URLResolver.js +82 -0
  41. package/js/base.js +69 -0
  42. package/js/browser-extensions/OutputDocumentBrowser.js +131 -0
  43. package/js/browser-extensions/URLBrowserResolver.js +94 -0
  44. package/js/browser-extensions/fonts/Roboto.js +42 -0
  45. package/js/browser-extensions/index.js +70 -0
  46. package/js/browser-extensions/pdfMake.js +17 -0
  47. package/js/browser-extensions/standard-fonts/Courier.js +42 -0
  48. package/js/browser-extensions/standard-fonts/Helvetica.js +42 -0
  49. package/js/browser-extensions/standard-fonts/Symbol.js +27 -0
  50. package/js/browser-extensions/standard-fonts/Times.js +42 -0
  51. package/js/browser-extensions/standard-fonts/ZapfDingbats.js +27 -0
  52. package/js/browser-extensions/virtual-fs-cjs.js +3 -0
  53. package/js/columnCalculator.js +142 -0
  54. package/js/helpers/node.js +122 -0
  55. package/js/helpers/tools.js +48 -0
  56. package/js/helpers/variableType.js +52 -0
  57. package/js/index.js +21 -0
  58. package/js/qrEnc.js +810 -0
  59. package/js/standardPageSizes.js +57 -0
  60. package/js/tableLayouts.js +127 -0
  61. package/js/virtual-fs.js +77 -0
  62. package/package.json +26 -22
  63. package/src/3rd-party/svg-to-pdfkit.js +2 -2
  64. package/src/DocMeasure.js +703 -0
  65. package/src/DocPreprocessor.js +264 -0
  66. package/src/DocumentContext.js +309 -0
  67. package/src/ElementWriter.js +394 -0
  68. package/src/LayoutBuilder.js +821 -0
  69. package/src/Line.js +114 -0
  70. package/src/OutputDocument.js +78 -0
  71. package/src/OutputDocumentServer.js +26 -0
  72. package/src/PDFDocument.js +174 -0
  73. package/src/PageElementWriter.js +160 -0
  74. package/src/PageSize.js +53 -0
  75. package/src/Printer.js +277 -0
  76. package/src/Renderer.js +405 -0
  77. package/src/SVGMeasure.js +79 -0
  78. package/src/StyleContextStack.js +216 -0
  79. package/src/TableProcessor.js +558 -0
  80. package/src/TextBreaker.js +149 -0
  81. package/src/TextDecorator.js +161 -0
  82. package/src/TextInlines.js +223 -0
  83. package/src/URLResolver.js +72 -0
  84. package/src/base.js +61 -0
  85. package/src/browser-extensions/OutputDocumentBrowser.js +117 -0
  86. package/src/browser-extensions/URLBrowserResolver.js +49 -53
  87. package/src/browser-extensions/fonts/Roboto.js +27 -0
  88. package/src/browser-extensions/index.js +55 -0
  89. package/src/browser-extensions/pdfMake.js +10 -282
  90. package/src/browser-extensions/standard-fonts/Courier.js +27 -0
  91. package/src/browser-extensions/standard-fonts/Helvetica.js +27 -0
  92. package/src/browser-extensions/standard-fonts/Symbol.js +21 -0
  93. package/src/browser-extensions/standard-fonts/Times.js +27 -0
  94. package/src/browser-extensions/standard-fonts/ZapfDingbats.js +21 -0
  95. package/src/browser-extensions/virtual-fs-cjs.js +1 -0
  96. package/src/columnCalculator.js +29 -32
  97. package/src/helpers/node.js +110 -0
  98. package/src/helpers/tools.js +39 -0
  99. package/src/helpers/variableType.js +39 -0
  100. package/src/index.js +16 -0
  101. package/src/qrEnc.js +15 -10
  102. package/src/standardPageSizes.js +1 -3
  103. package/src/tableLayouts.js +100 -0
  104. package/src/virtual-fs.js +66 -0
  105. package/standard-fonts/Courier.js +8 -0
  106. package/standard-fonts/Helvetica.js +9 -0
  107. package/standard-fonts/Symbol.js +5 -0
  108. package/standard-fonts/Times.js +8 -0
  109. package/standard-fonts/ZapfDingbats.js +5 -0
  110. package/src/browser-extensions/virtual-fs.js +0 -55
  111. package/src/docMeasure.js +0 -807
  112. package/src/docPreprocessor.js +0 -255
  113. package/src/documentContext.js +0 -314
  114. package/src/elementWriter.js +0 -322
  115. package/src/fontProvider.js +0 -68
  116. package/src/helpers.js +0 -126
  117. package/src/imageMeasure.js +0 -51
  118. package/src/layoutBuilder.js +0 -807
  119. package/src/line.js +0 -91
  120. package/src/pageElementWriter.js +0 -174
  121. package/src/pdfKitEngine.js +0 -21
  122. package/src/printer.js +0 -705
  123. package/src/styleContextStack.js +0 -179
  124. package/src/svgMeasure.js +0 -70
  125. package/src/tableProcessor.js +0 -561
  126. package/src/textDecorator.js +0 -157
  127. package/src/textTools.js +0 -373
  128. package/src/traversalTracker.js +0 -47
@@ -1,807 +0,0 @@
1
- 'use strict';
2
-
3
- var TraversalTracker = require('./traversalTracker');
4
- var DocPreprocessor = require('./docPreprocessor');
5
- var DocMeasure = require('./docMeasure');
6
- var DocumentContext = require('./documentContext');
7
- var PageElementWriter = require('./pageElementWriter');
8
- var ColumnCalculator = require('./columnCalculator');
9
- var TableProcessor = require('./tableProcessor');
10
- var Line = require('./line');
11
- var isString = require('./helpers').isString;
12
- var isArray = require('./helpers').isArray;
13
- var isUndefined = require('./helpers').isUndefined;
14
- var isNull = require('./helpers').isNull;
15
- var pack = require('./helpers').pack;
16
- var offsetVector = require('./helpers').offsetVector;
17
- var fontStringify = require('./helpers').fontStringify;
18
- var getNodeId = require('./helpers').getNodeId;
19
- var isFunction = require('./helpers').isFunction;
20
- var TextTools = require('./textTools');
21
- var StyleContextStack = require('./styleContextStack');
22
- var isNumber = require('./helpers').isNumber;
23
-
24
- function addAll(target, otherArray) {
25
- otherArray.forEach(function (item) {
26
- target.push(item);
27
- });
28
- }
29
-
30
- /**
31
- * Creates an instance of LayoutBuilder - layout engine which turns document-definition-object
32
- * into a set of pages, lines, inlines and vectors ready to be rendered into a PDF
33
- *
34
- * @param {Object} pageSize - an object defining page width and height
35
- * @param {Object} pageMargins - an object defining top, left, right and bottom margins
36
- */
37
- function LayoutBuilder(pageSize, pageMargins, imageMeasure, svgMeasure) {
38
- this.pageSize = pageSize;
39
- this.pageMargins = pageMargins;
40
- this.tracker = new TraversalTracker();
41
- this.imageMeasure = imageMeasure;
42
- this.svgMeasure = svgMeasure;
43
- this.tableLayouts = {};
44
- }
45
-
46
- LayoutBuilder.prototype.registerTableLayouts = function (tableLayouts) {
47
- this.tableLayouts = pack(this.tableLayouts, tableLayouts);
48
- };
49
-
50
- /**
51
- * Executes layout engine on document-definition-object and creates an array of pages
52
- * containing positioned Blocks, Lines and inlines
53
- *
54
- * @param {Object} docStructure document-definition-object
55
- * @param {Object} fontProvider font provider
56
- * @param {Object} styleDictionary dictionary with style definitions
57
- * @param {Object} defaultStyle default style definition
58
- * @return {Array} an array of pages
59
- */
60
- LayoutBuilder.prototype.layoutDocument = function (docStructure, fontProvider, styleDictionary, defaultStyle, background, header, footer, images, watermark, pageBreakBeforeFct) {
61
-
62
- function addPageBreaksIfNecessary(linearNodeList, pages) {
63
-
64
- if (!isFunction(pageBreakBeforeFct)) {
65
- return false;
66
- }
67
-
68
- linearNodeList = linearNodeList.filter(function (node) {
69
- return node.positions.length > 0;
70
- });
71
-
72
- linearNodeList.forEach(function (node) {
73
- var nodeInfo = {};
74
- [
75
- 'id', 'text', 'ul', 'ol', 'table', 'image', 'qr', 'canvas', 'svg', 'columns',
76
- 'headlineLevel', 'style', 'pageBreak', 'pageOrientation',
77
- 'width', 'height'
78
- ].forEach(function (key) {
79
- if (node[key] !== undefined) {
80
- nodeInfo[key] = node[key];
81
- }
82
- });
83
- nodeInfo.startPosition = node.positions[0];
84
- nodeInfo.pageNumbers = Array.from(new Set(node.positions.map(function (node) { return node.pageNumber; })));
85
- nodeInfo.pages = pages.length;
86
- nodeInfo.stack = isArray(node.stack);
87
-
88
- node.nodeInfo = nodeInfo;
89
- });
90
-
91
- for (var index = 0; index < linearNodeList.length; index++) {
92
- var node = linearNodeList[index];
93
- if (node.pageBreak !== 'before' && !node.pageBreakCalculated) {
94
- node.pageBreakCalculated = true;
95
- var pageNumber = node.nodeInfo.pageNumbers[0];
96
- var followingNodesOnPage = [];
97
- var nodesOnNextPage = [];
98
- var previousNodesOnPage = [];
99
- if (pageBreakBeforeFct.length > 1) {
100
- for (var ii = index + 1, l = linearNodeList.length; ii < l; ii++) {
101
- if (linearNodeList[ii].nodeInfo.pageNumbers.indexOf(pageNumber) > -1) {
102
- followingNodesOnPage.push(linearNodeList[ii].nodeInfo);
103
- }
104
- if (pageBreakBeforeFct.length > 2 && linearNodeList[ii].nodeInfo.pageNumbers.indexOf(pageNumber + 1) > -1) {
105
- nodesOnNextPage.push(linearNodeList[ii].nodeInfo);
106
- }
107
- }
108
- }
109
- if (pageBreakBeforeFct.length > 3) {
110
- for (var ii = 0; ii < index; ii++) {
111
- if (linearNodeList[ii].nodeInfo.pageNumbers.indexOf(pageNumber) > -1) {
112
- previousNodesOnPage.push(linearNodeList[ii].nodeInfo);
113
- }
114
- }
115
- }
116
- if (pageBreakBeforeFct(node.nodeInfo, followingNodesOnPage, nodesOnNextPage, previousNodesOnPage)) {
117
- node.pageBreak = 'before';
118
- return true;
119
- }
120
- }
121
- }
122
-
123
- return false;
124
- }
125
-
126
- this.docPreprocessor = new DocPreprocessor();
127
- this.docMeasure = new DocMeasure(fontProvider, styleDictionary, defaultStyle, this.imageMeasure, this.svgMeasure, this.tableLayouts, images);
128
-
129
-
130
- function resetXYs(result) {
131
- result.linearNodeList.forEach(function (node) {
132
- node.resetXY();
133
- });
134
- }
135
-
136
- var result = this.tryLayoutDocument(docStructure, fontProvider, styleDictionary, defaultStyle, background, header, footer, images, watermark);
137
- while (addPageBreaksIfNecessary(result.linearNodeList, result.pages)) {
138
- resetXYs(result);
139
- result = this.tryLayoutDocument(docStructure, fontProvider, styleDictionary, defaultStyle, background, header, footer, images, watermark);
140
- }
141
-
142
- return result.pages;
143
- };
144
-
145
- LayoutBuilder.prototype.tryLayoutDocument = function (docStructure, fontProvider, styleDictionary, defaultStyle, background, header, footer, images, watermark, pageBreakBeforeFct) {
146
-
147
- this.linearNodeList = [];
148
- docStructure = this.docPreprocessor.preprocessDocument(docStructure);
149
- docStructure = this.docMeasure.measureDocument(docStructure);
150
-
151
- this.writer = new PageElementWriter(
152
- new DocumentContext(this.pageSize, this.pageMargins), this.tracker);
153
-
154
- var _this = this;
155
- this.writer.context().tracker.startTracking('pageAdded', function () {
156
- _this.addBackground(background);
157
- });
158
-
159
- this.addBackground(background);
160
- this.processNode(docStructure);
161
- this.addHeadersAndFooters(header, footer);
162
- if (watermark != null) {
163
- this.addWatermark(watermark, fontProvider, defaultStyle);
164
- }
165
-
166
- return { pages: this.writer.context().pages, linearNodeList: this.linearNodeList };
167
- };
168
-
169
-
170
- LayoutBuilder.prototype.addBackground = function (background) {
171
- var backgroundGetter = isFunction(background) ? background : function () {
172
- return background;
173
- };
174
-
175
- var context = this.writer.context();
176
- var pageSize = context.getCurrentPage().pageSize;
177
-
178
- var pageBackground = backgroundGetter(context.page + 1, pageSize);
179
-
180
- if (pageBackground) {
181
- this.writer.beginUnbreakableBlock(pageSize.width, pageSize.height);
182
- pageBackground = this.docPreprocessor.preprocessDocument(pageBackground);
183
- this.processNode(this.docMeasure.measureDocument(pageBackground));
184
- this.writer.commitUnbreakableBlock(0, 0);
185
- context.backgroundLength[context.page] += pageBackground.positions.length;
186
- }
187
- };
188
-
189
- LayoutBuilder.prototype.addStaticRepeatable = function (headerOrFooter, sizeFunction) {
190
- this.addDynamicRepeatable(function () {
191
- return JSON.parse(JSON.stringify(headerOrFooter)); // copy to new object
192
- }, sizeFunction);
193
- };
194
-
195
- LayoutBuilder.prototype.addDynamicRepeatable = function (nodeGetter, sizeFunction) {
196
- var pages = this.writer.context().pages;
197
-
198
- for (var pageIndex = 0, l = pages.length; pageIndex < l; pageIndex++) {
199
- this.writer.context().page = pageIndex;
200
-
201
- var node = nodeGetter(pageIndex + 1, l, this.writer.context().pages[pageIndex].pageSize);
202
-
203
- if (node) {
204
- var sizes = sizeFunction(this.writer.context().getCurrentPage().pageSize, this.pageMargins);
205
- this.writer.beginUnbreakableBlock(sizes.width, sizes.height);
206
- node = this.docPreprocessor.preprocessDocument(node);
207
- this.processNode(this.docMeasure.measureDocument(node));
208
- this.writer.commitUnbreakableBlock(sizes.x, sizes.y);
209
- }
210
- }
211
- };
212
-
213
- LayoutBuilder.prototype.addHeadersAndFooters = function (header, footer) {
214
- var headerSizeFct = function (pageSize, pageMargins) {
215
- return {
216
- x: 0,
217
- y: 0,
218
- width: pageSize.width,
219
- height: pageMargins.top
220
- };
221
- };
222
-
223
- var footerSizeFct = function (pageSize, pageMargins) {
224
- return {
225
- x: 0,
226
- y: pageSize.height - pageMargins.bottom,
227
- width: pageSize.width,
228
- height: pageMargins.bottom
229
- };
230
- };
231
-
232
- if (isFunction(header)) {
233
- this.addDynamicRepeatable(header, headerSizeFct);
234
- } else if (header) {
235
- this.addStaticRepeatable(header, headerSizeFct);
236
- }
237
-
238
- if (isFunction(footer)) {
239
- this.addDynamicRepeatable(footer, footerSizeFct);
240
- } else if (footer) {
241
- this.addStaticRepeatable(footer, footerSizeFct);
242
- }
243
- };
244
-
245
- LayoutBuilder.prototype.addWatermark = function (watermark, fontProvider, defaultStyle) {
246
- if (isString(watermark)) {
247
- watermark = { 'text': watermark };
248
- }
249
-
250
- if (!watermark.text) { // empty watermark text
251
- return;
252
- }
253
-
254
- watermark.font = watermark.font || defaultStyle.font || 'Roboto';
255
- watermark.fontSize = watermark.fontSize || 'auto';
256
- watermark.color = watermark.color || 'black';
257
- watermark.opacity = isNumber(watermark.opacity) ? watermark.opacity : 0.6;
258
- watermark.bold = watermark.bold || false;
259
- watermark.italics = watermark.italics || false;
260
- watermark.angle = !isUndefined(watermark.angle) && !isNull(watermark.angle) ? watermark.angle : null;
261
-
262
- if (watermark.angle === null) {
263
- watermark.angle = Math.atan2(this.pageSize.height, this.pageSize.width) * -180 / Math.PI;
264
- }
265
-
266
- if (watermark.fontSize === 'auto') {
267
- watermark.fontSize = getWatermarkFontSize(this.pageSize, watermark, fontProvider);
268
- }
269
-
270
- var watermarkObject = {
271
- text: watermark.text,
272
- font: fontProvider.provideFont(watermark.font, watermark.bold, watermark.italics),
273
- fontSize: watermark.fontSize,
274
- color: watermark.color,
275
- opacity: watermark.opacity,
276
- angle: watermark.angle
277
- };
278
-
279
- watermarkObject._size = getWatermarkSize(watermark, fontProvider);
280
-
281
- var pages = this.writer.context().pages;
282
- for (var i = 0, l = pages.length; i < l; i++) {
283
- pages[i].watermark = watermarkObject;
284
- }
285
-
286
- function getWatermarkSize(watermark, fontProvider) {
287
- var textTools = new TextTools(fontProvider);
288
- var styleContextStack = new StyleContextStack(null, { font: watermark.font, bold: watermark.bold, italics: watermark.italics });
289
-
290
- styleContextStack.push({
291
- fontSize: watermark.fontSize
292
- });
293
-
294
- var size = textTools.sizeOfString(watermark.text, styleContextStack);
295
- var rotatedSize = textTools.sizeOfRotatedText(watermark.text, watermark.angle, styleContextStack);
296
-
297
- return { size: size, rotatedSize: rotatedSize };
298
- }
299
-
300
- function getWatermarkFontSize(pageSize, watermark, fontProvider) {
301
- var textTools = new TextTools(fontProvider);
302
- var styleContextStack = new StyleContextStack(null, { font: watermark.font, bold: watermark.bold, italics: watermark.italics });
303
- var rotatedSize;
304
-
305
- /**
306
- * Binary search the best font size.
307
- * Initial bounds [0, 1000]
308
- * Break when range < 1
309
- */
310
- var a = 0;
311
- var b = 1000;
312
- var c = (a + b) / 2;
313
- while (Math.abs(a - b) > 1) {
314
- styleContextStack.push({
315
- fontSize: c
316
- });
317
- rotatedSize = textTools.sizeOfRotatedText(watermark.text, watermark.angle, styleContextStack);
318
- if (rotatedSize.width > pageSize.width) {
319
- b = c;
320
- c = (a + b) / 2;
321
- } else if (rotatedSize.width < pageSize.width) {
322
- if (rotatedSize.height > pageSize.height) {
323
- b = c;
324
- c = (a + b) / 2;
325
- } else {
326
- a = c;
327
- c = (a + b) / 2;
328
- }
329
- }
330
- styleContextStack.pop();
331
- }
332
- /*
333
- End binary search
334
- */
335
- return c;
336
- }
337
- };
338
-
339
- function decorateNode(node) {
340
- var x = node.x, y = node.y;
341
- node.positions = [];
342
-
343
- if (isArray(node.canvas)) {
344
- node.canvas.forEach(function (vector) {
345
- var x = vector.x, y = vector.y, x1 = vector.x1, y1 = vector.y1, x2 = vector.x2, y2 = vector.y2;
346
- vector.resetXY = function () {
347
- vector.x = x;
348
- vector.y = y;
349
- vector.x1 = x1;
350
- vector.y1 = y1;
351
- vector.x2 = x2;
352
- vector.y2 = y2;
353
- };
354
- });
355
- }
356
-
357
- node.resetXY = function () {
358
- node.x = x;
359
- node.y = y;
360
- if (isArray(node.canvas)) {
361
- node.canvas.forEach(function (vector) {
362
- vector.resetXY();
363
- });
364
- }
365
- };
366
- }
367
-
368
- LayoutBuilder.prototype.processNode = function (node) {
369
- var self = this;
370
-
371
- this.linearNodeList.push(node);
372
- decorateNode(node);
373
-
374
- applyMargins(function () {
375
- var unbreakable = node.unbreakable;
376
- if (unbreakable) {
377
- self.writer.beginUnbreakableBlock();
378
- }
379
-
380
- var absPosition = node.absolutePosition;
381
- if (absPosition) {
382
- self.writer.context().beginDetachedBlock();
383
- self.writer.context().moveTo(absPosition.x || 0, absPosition.y || 0);
384
- }
385
-
386
- var relPosition = node.relativePosition;
387
- if (relPosition) {
388
- self.writer.context().beginDetachedBlock();
389
- self.writer.context().moveToRelative(relPosition.x || 0, relPosition.y || 0);
390
- }
391
-
392
- if (node.stack) {
393
- self.processVerticalContainer(node);
394
- } else if (node.columns) {
395
- self.processColumns(node);
396
- } else if (node.ul) {
397
- self.processList(false, node);
398
- } else if (node.ol) {
399
- self.processList(true, node);
400
- } else if (node.table) {
401
- self.processTable(node);
402
- } else if (node.text !== undefined) {
403
- self.processLeaf(node);
404
- } else if (node.toc) {
405
- self.processToc(node);
406
- } else if (node.image) {
407
- self.processImage(node);
408
- } else if (node.svg) {
409
- self.processSVG(node);
410
- } else if (node.canvas) {
411
- self.processCanvas(node);
412
- } else if (node.qr) {
413
- self.processQr(node);
414
- } else if (!node._span) {
415
- throw 'Unrecognized document structure: ' + JSON.stringify(node, fontStringify);
416
- }
417
-
418
- if (absPosition || relPosition) {
419
- self.writer.context().endDetachedBlock();
420
- }
421
-
422
- if (unbreakable) {
423
- self.writer.commitUnbreakableBlock();
424
- }
425
- });
426
-
427
- function applyMargins(callback) {
428
- var margin = node._margin;
429
-
430
- if (node.pageBreak === 'before') {
431
- self.writer.moveToNextPage(node.pageOrientation);
432
- } else if (node.pageBreak === 'beforeOdd') {
433
- self.writer.moveToNextPage(node.pageOrientation);
434
- if ((self.writer.context().page + 1) % 2 === 1) {
435
- self.writer.moveToNextPage(node.pageOrientation);
436
- }
437
- } else if (node.pageBreak === 'beforeEven') {
438
- self.writer.moveToNextPage(node.pageOrientation);
439
- if ((self.writer.context().page + 1) % 2 === 0) {
440
- self.writer.moveToNextPage(node.pageOrientation);
441
- }
442
- }
443
-
444
- if (margin) {
445
- self.writer.context().moveDown(margin[1]);
446
- self.writer.context().addMargin(margin[0], margin[2]);
447
- }
448
-
449
- callback();
450
-
451
- if (margin) {
452
- self.writer.context().addMargin(-margin[0], -margin[2]);
453
- self.writer.context().moveDown(margin[3]);
454
- }
455
-
456
- if (node.pageBreak === 'after') {
457
- self.writer.moveToNextPage(node.pageOrientation);
458
- } else if (node.pageBreak === 'afterOdd') {
459
- self.writer.moveToNextPage(node.pageOrientation);
460
- if ((self.writer.context().page + 1) % 2 === 1) {
461
- self.writer.moveToNextPage(node.pageOrientation);
462
- }
463
- } else if (node.pageBreak === 'afterEven') {
464
- self.writer.moveToNextPage(node.pageOrientation);
465
- if ((self.writer.context().page + 1) % 2 === 0) {
466
- self.writer.moveToNextPage(node.pageOrientation);
467
- }
468
- }
469
- }
470
- };
471
-
472
- // vertical container
473
- LayoutBuilder.prototype.processVerticalContainer = function (node) {
474
- var self = this;
475
- node.stack.forEach(function (item) {
476
- self.processNode(item);
477
- addAll(node.positions, item.positions);
478
-
479
- //TODO: paragraph gap
480
- });
481
- };
482
-
483
- // columns
484
- LayoutBuilder.prototype.processColumns = function (columnNode) {
485
- var columns = columnNode.columns;
486
- var availableWidth = this.writer.context().availableWidth;
487
- var gaps = gapArray(columnNode._gap);
488
-
489
- if (gaps) {
490
- availableWidth -= (gaps.length - 1) * columnNode._gap;
491
- }
492
-
493
- ColumnCalculator.buildColumnWidths(columns, availableWidth);
494
- var result = this.processRow(columns, columns, gaps);
495
- addAll(columnNode.positions, result.positions);
496
-
497
-
498
- function gapArray(gap) {
499
- if (!gap) {
500
- return null;
501
- }
502
-
503
- var gaps = [];
504
- gaps.push(0);
505
-
506
- for (var i = columns.length - 1; i > 0; i--) {
507
- gaps.push(gap);
508
- }
509
-
510
- return gaps;
511
- }
512
- };
513
-
514
- LayoutBuilder.prototype.processRow = function (columns, widths, gaps, tableBody, tableRow, height) {
515
- var self = this;
516
- var pageBreaks = [], positions = [];
517
-
518
- this.tracker.auto('pageChanged', storePageBreakData, function () {
519
- widths = widths || columns;
520
-
521
- self.writer.context().beginColumnGroup();
522
-
523
- for (var i = 0, l = columns.length; i < l; i++) {
524
- var column = columns[i];
525
- var width = widths[i]._calcWidth;
526
- var leftOffset = colLeftOffset(i);
527
-
528
- if (column.colSpan && column.colSpan > 1) {
529
- for (var j = 1; j < column.colSpan; j++) {
530
- width += widths[++i]._calcWidth + gaps[i];
531
- }
532
- }
533
-
534
- self.writer.context().beginColumn(width, leftOffset, getEndingCell(column, i));
535
- if (!column._span) {
536
- self.processNode(column);
537
- addAll(positions, column.positions);
538
- } else if (column._columnEndingContext) {
539
- // row-span ending
540
- self.writer.context().markEnding(column);
541
- }
542
- }
543
-
544
- self.writer.context().completeColumnGroup(height);
545
- });
546
-
547
- return { pageBreaks: pageBreaks, positions: positions };
548
-
549
- function storePageBreakData(data) {
550
- var pageDesc;
551
-
552
- for (var i = 0, l = pageBreaks.length; i < l; i++) {
553
- var desc = pageBreaks[i];
554
- if (desc.prevPage === data.prevPage) {
555
- pageDesc = desc;
556
- break;
557
- }
558
- }
559
-
560
- if (!pageDesc) {
561
- pageDesc = data;
562
- pageBreaks.push(pageDesc);
563
- }
564
- pageDesc.prevY = Math.max(pageDesc.prevY, data.prevY);
565
- pageDesc.y = Math.min(pageDesc.y, data.y);
566
- }
567
-
568
- function colLeftOffset(i) {
569
- if (gaps && gaps.length > i) {
570
- return gaps[i];
571
- }
572
- return 0;
573
- }
574
-
575
- function getEndingCell(column, columnIndex) {
576
- if (column.rowSpan && column.rowSpan > 1) {
577
- var endingRow = tableRow + column.rowSpan - 1;
578
- if (endingRow >= tableBody.length) {
579
- throw 'Row span for column ' + columnIndex + ' (with indexes starting from 0) exceeded row count';
580
- }
581
- return tableBody[endingRow][columnIndex];
582
- }
583
-
584
- return null;
585
- }
586
- };
587
-
588
- // lists
589
- LayoutBuilder.prototype.processList = function (orderedList, node) {
590
- var self = this,
591
- items = orderedList ? node.ol : node.ul,
592
- gapSize = node._gapSize;
593
-
594
- this.writer.context().addMargin(gapSize.width);
595
-
596
- var nextMarker;
597
- this.tracker.auto('lineAdded', addMarkerToFirstLeaf, function () {
598
- items.forEach(function (item) {
599
- nextMarker = item.listMarker;
600
- self.processNode(item);
601
- addAll(node.positions, item.positions);
602
- });
603
- });
604
-
605
- this.writer.context().addMargin(-gapSize.width);
606
-
607
- function addMarkerToFirstLeaf(line) {
608
- // I'm not very happy with the way list processing is implemented
609
- // (both code and algorithm should be rethinked)
610
- if (nextMarker) {
611
- var marker = nextMarker;
612
- nextMarker = null;
613
-
614
- if (marker.canvas) {
615
- var vector = marker.canvas[0];
616
-
617
- offsetVector(vector, -marker._minWidth, 0);
618
- self.writer.addVector(vector);
619
- } else if (marker._inlines) {
620
- var markerLine = new Line(self.pageSize.width);
621
- markerLine.addInline(marker._inlines[0]);
622
- markerLine.x = -marker._minWidth;
623
- markerLine.y = line.getAscenderHeight() - markerLine.getAscenderHeight();
624
- self.writer.addLine(markerLine, true);
625
- }
626
- }
627
- }
628
- };
629
-
630
- // tables
631
- LayoutBuilder.prototype.processTable = function (tableNode) {
632
- var processor = new TableProcessor(tableNode);
633
-
634
- processor.beginTable(this.writer);
635
-
636
- var rowHeights = tableNode.table.heights;
637
- for (var i = 0, l = tableNode.table.body.length; i < l; i++) {
638
- processor.beginRow(i, this.writer);
639
-
640
- var height;
641
- if (isFunction(rowHeights)) {
642
- height = rowHeights(i);
643
- } else if (isArray(rowHeights)) {
644
- height = rowHeights[i];
645
- } else {
646
- height = rowHeights;
647
- }
648
-
649
- if (height === 'auto') {
650
- height = undefined;
651
- }
652
-
653
- var result = this.processRow(tableNode.table.body[i], tableNode.table.widths, tableNode._offsets.offsets, tableNode.table.body, i, height);
654
- addAll(tableNode.positions, result.positions);
655
-
656
- processor.endRow(i, this.writer, result.pageBreaks);
657
- }
658
-
659
- processor.endTable(this.writer);
660
- };
661
-
662
- // leafs (texts)
663
- LayoutBuilder.prototype.processLeaf = function (node) {
664
- var line = this.buildNextLine(node);
665
- if (line && (node.tocItem || node.id)) {
666
- line._node = node;
667
- }
668
- var currentHeight = (line) ? line.getHeight() : 0;
669
- var maxHeight = node.maxHeight || -1;
670
-
671
- if (line) {
672
- var nodeId = getNodeId(node);
673
- if (nodeId) {
674
- line.id = nodeId;
675
- }
676
- }
677
-
678
- if (node._tocItemRef) {
679
- line._pageNodeRef = node._tocItemRef;
680
- }
681
-
682
- if (node._pageRef) {
683
- line._pageNodeRef = node._pageRef._nodeRef;
684
- }
685
-
686
- if (line && line.inlines && isArray(line.inlines)) {
687
- for (var i = 0, l = line.inlines.length; i < l; i++) {
688
- if (line.inlines[i]._tocItemRef) {
689
- line.inlines[i]._pageNodeRef = line.inlines[i]._tocItemRef;
690
- }
691
-
692
- if (line.inlines[i]._pageRef) {
693
- line.inlines[i]._pageNodeRef = line.inlines[i]._pageRef._nodeRef;
694
- }
695
- }
696
- }
697
-
698
- while (line && (maxHeight === -1 || currentHeight < maxHeight)) {
699
- var positions = this.writer.addLine(line);
700
- node.positions.push(positions);
701
- line = this.buildNextLine(node);
702
- if (line) {
703
- currentHeight += line.getHeight();
704
- }
705
- }
706
- };
707
-
708
- LayoutBuilder.prototype.processToc = function (node) {
709
- if (node.toc.title) {
710
- this.processNode(node.toc.title);
711
- }
712
- if (node.toc._table) {
713
- this.processNode(node.toc._table);
714
- }
715
- };
716
-
717
- LayoutBuilder.prototype.buildNextLine = function (textNode) {
718
-
719
- function cloneInline(inline) {
720
- var newInline = inline.constructor();
721
- for (var key in inline) {
722
- newInline[key] = inline[key];
723
- }
724
- return newInline;
725
- }
726
-
727
- if (!textNode._inlines || textNode._inlines.length === 0) {
728
- return null;
729
- }
730
-
731
- var line = new Line(this.writer.context().availableWidth);
732
- var textTools = new TextTools(null);
733
-
734
- var isForceContinue = false;
735
- while (textNode._inlines && textNode._inlines.length > 0 &&
736
- (line.hasEnoughSpaceForInline(textNode._inlines[0], textNode._inlines.slice(1)) || isForceContinue)) {
737
- var isHardWrap = false;
738
- var inline = textNode._inlines.shift();
739
- isForceContinue = false;
740
-
741
- if (!inline.noWrap && inline.text.length > 1 && inline.width > line.getAvailableWidth()) {
742
- var widthPerChar = inline.width / inline.text.length;
743
- var maxChars = Math.floor(line.getAvailableWidth() / widthPerChar);
744
- if (maxChars < 1) {
745
- maxChars = 1;
746
- }
747
- if (maxChars < inline.text.length) {
748
- var newInline = cloneInline(inline);
749
-
750
- newInline.text = inline.text.substr(maxChars);
751
- inline.text = inline.text.substr(0, maxChars);
752
-
753
- newInline.width = textTools.widthOfString(newInline.text, newInline.font, newInline.fontSize, newInline.characterSpacing, newInline.fontFeatures);
754
- inline.width = textTools.widthOfString(inline.text, inline.font, inline.fontSize, inline.characterSpacing, inline.fontFeatures);
755
-
756
- textNode._inlines.unshift(newInline);
757
- isHardWrap = true;
758
- }
759
- }
760
-
761
- line.addInline(inline);
762
-
763
- isForceContinue = inline.noNewLine && !isHardWrap;
764
- }
765
-
766
- line.lastLineInParagraph = textNode._inlines.length === 0;
767
-
768
- return line;
769
- };
770
-
771
- // images
772
- LayoutBuilder.prototype.processImage = function (node) {
773
- var position = this.writer.addImage(node);
774
- node.positions.push(position);
775
- };
776
-
777
- LayoutBuilder.prototype.processSVG = function (node) {
778
- var position = this.writer.addSVG(node);
779
- node.positions.push(position);
780
- };
781
-
782
- LayoutBuilder.prototype.processCanvas = function (node) {
783
- var height = node._minHeight;
784
-
785
- if (node.absolutePosition === undefined && this.writer.context().availableHeight < height) {
786
- // TODO: support for canvas larger than a page
787
- // TODO: support for other overflow methods
788
-
789
- this.writer.moveToNextPage();
790
- }
791
-
792
- this.writer.alignCanvas(node);
793
-
794
- node.canvas.forEach(function (vector) {
795
- var position = this.writer.addVector(vector);
796
- node.positions.push(position);
797
- }, this);
798
-
799
- this.writer.context().moveDown(height);
800
- };
801
-
802
- LayoutBuilder.prototype.processQr = function (node) {
803
- var position = this.writer.addQr(node);
804
- node.positions.push(position);
805
- };
806
-
807
- module.exports = LayoutBuilder;