pdfmake 0.3.12 → 0.3.13

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.
@@ -458,7 +458,9 @@ class DocumentContext extends _events.EventEmitter {
458
458
  }
459
459
  let page = {
460
460
  items: [],
461
- pageSize: pageSize,
461
+ pageSize: {
462
+ ...pageSize
463
+ },
462
464
  pageMargins: this.pageMargins,
463
465
  customProperties: customProperties
464
466
  };
@@ -277,6 +277,7 @@ class ElementWriter extends _events.EventEmitter {
277
277
  if (!useBlockXOffset && block.height > ctx.availableHeight) {
278
278
  return false;
279
279
  }
280
+ let unbreakableFillsInserted = 0;
280
281
  block.items.forEach(item => {
281
282
  switch (item.type) {
282
283
  case 'line':
@@ -296,9 +297,11 @@ class ElementWriter extends _events.EventEmitter {
296
297
  (0, _tools.offsetVector)(v, useBlockXOffset ? block.xOffset || 0 : ctx.x, useBlockYOffset ? block.yOffset || 0 : ctx.y);
297
298
  if (v._isFillColorFromUnbreakable) {
298
299
  // If the item is a fillColor from an unbreakable block
299
- // We have to add it at the beginning of the items body array of the page
300
+ // We have to add it at the beginning of the items body array of the page,
301
+ // after the fills already inserted from this block so that they keep their draw order
300
302
  delete v._isFillColorFromUnbreakable;
301
- const endOfBackgroundItemsIndex = ctx.backgroundLength[ctx.page];
303
+ const endOfBackgroundItemsIndex = ctx.backgroundLength[ctx.page] + unbreakableFillsInserted;
304
+ unbreakableFillsInserted++;
302
305
  page.items.splice(endOfBackgroundItemsIndex, 0, {
303
306
  type: 'vector',
304
307
  item: v
@@ -490,8 +490,9 @@ class LayoutBuilder {
490
490
  * When in snaking columns, first tries moving to next column.
491
491
  * If no columns available, moves to next page and resets x to left margin.
492
492
  * @param {string} pageOrientation - Optional page orientation for the new page
493
+ * @param {TableProcessor} [tableProcessor] - Reapply table alignment in the new column
493
494
  */
494
- snakingAwarePageBreak(pageOrientation) {
495
+ snakingAwarePageBreak(pageOrientation, tableProcessor) {
495
496
  let ctx = this.writer.context();
496
497
  let snakingSnapshot = ctx.getSnakingSnapshot();
497
498
  if (!snakingSnapshot) {
@@ -500,7 +501,7 @@ class LayoutBuilder {
500
501
 
501
502
  // Try flowing to next column first
502
503
  if (this.writer.canMoveToNextColumn()) {
503
- this.writer.moveToNextColumn();
504
+ this.writer.moveToNextColumn(tableProcessor ? context => tableProcessor.alignTable(context) : undefined);
504
505
  return;
505
506
  }
506
507
 
@@ -514,6 +515,9 @@ class LayoutBuilder {
514
515
  let savedLastColumnWidth = ctx.lastColumnWidth;
515
516
  ctx.resetSnakingColumnsForNewPage();
516
517
  ctx.lastColumnWidth = savedLastColumnWidth;
518
+ if (tableProcessor) {
519
+ tableProcessor.alignTable(ctx);
520
+ }
517
521
  }
518
522
 
519
523
  // vertical container
@@ -964,7 +968,7 @@ class LayoutBuilder {
964
968
  let rowTopPageY = this.cell._leftEndingCell._startingRowSpanY + this.cell._leftEndingCell._rowTopPageYPadding;
965
969
  return this.cell._leftEndingCell._rowTopPageY - rowTopPageY + this.cell._leftEndingCell._bottomY;
966
970
  } else {
967
- if (this.cell.positions[0].pageNumber !== this.cell._leftEndingCell._lastPageNumber) {
971
+ if (this.cell._lastPageNumber !== this.cell._leftEndingCell._lastPageNumber) {
968
972
  return this.bottomY - this.cell._leftEndingCell._bottomY;
969
973
  }
970
974
  return this.viewHeight + this.cell._leftEndingCell._bottomY - this.bottomY;
@@ -1038,7 +1042,11 @@ class LayoutBuilder {
1038
1042
  // or fall back to a minimum of padding + line height + border
1039
1043
  let minRowHeight = lastRowHeight > 0 ? lastRowHeight : processor.rowPaddingTop + 14 + processor.rowPaddingBottom + processor.bottomLineWidth + processor.topLineWidth;
1040
1044
  if (this.writer.context().availableHeight < minRowHeight) {
1041
- this.snakingAwarePageBreak();
1045
+ // Column selection needs the container origin, before table alignment.
1046
+ if (processor.alignmentOffset) {
1047
+ this.writer.context().addMargin(-processor.alignmentOffset, processor.alignmentOffset);
1048
+ }
1049
+ this.snakingAwarePageBreak(undefined, processor);
1042
1050
 
1043
1051
  // Skip border when headerRows present (header repeat includes it)
1044
1052
  if (processor.layout.hLineWhenBroken !== false && !processor.headerRows) {
@@ -9,13 +9,25 @@ class OutputDocument {
9
9
  constructor(pdfDocumentPromise) {
10
10
  this.pdfDocumentPromise = pdfDocumentPromise;
11
11
  this.bufferPromise = null;
12
+ this.streamEnded = false;
13
+ this.streamEndListenerAttached = false;
12
14
  }
13
15
 
14
16
  /**
15
17
  * @returns {Promise<object>}
16
18
  */
17
- getStream() {
18
- return this.pdfDocumentPromise;
19
+ async getStream() {
20
+ const stream = await this.pdfDocumentPromise;
21
+ if (this.streamEnded) {
22
+ throw new Error('PDF stream has already been consumed.');
23
+ }
24
+ if (!this.streamEndListenerAttached) {
25
+ stream.once('end', () => {
26
+ this.streamEnded = true;
27
+ });
28
+ this.streamEndListenerAttached = true;
29
+ }
30
+ return stream;
19
31
  }
20
32
 
21
33
  /**
@@ -24,7 +36,7 @@ class OutputDocument {
24
36
  getBuffer() {
25
37
  const getBufferInternal = async () => {
26
38
  const stream = await this.getStream();
27
- return new Promise(resolve => {
39
+ return new Promise((resolve, reject) => {
28
40
  let chunks = [];
29
41
  stream.on('data', chunk => {
30
42
  chunks.push(chunk);
@@ -32,6 +44,7 @@ class OutputDocument {
32
44
  stream.on('end', () => {
33
45
  resolve(Buffer.concat(chunks));
34
46
  });
47
+ stream.on('error', reject);
35
48
  stream.end();
36
49
  });
37
50
  };
@@ -11,6 +11,11 @@ class OutputDocumentServer extends _OutputDocument.default {
11
11
  * @returns {Promise}
12
12
  */
13
13
  async write(filename) {
14
+ await this.pdfDocumentPromise;
15
+ if (this.bufferPromise !== null) {
16
+ await _fs.default.promises.writeFile(filename, await this.getBuffer());
17
+ return;
18
+ }
14
19
  const stream = await this.getStream();
15
20
  const writeStream = _fs.default.createWriteStream(filename);
16
21
  const streamEnded = new Promise((resolve, reject) => {
package/js/PDFDocument.js CHANGED
@@ -129,12 +129,12 @@ class PDFDocument extends _pdfkit.PDFDocument {
129
129
  }
130
130
  return obj;
131
131
  };
132
- if (typeof src === 'object') {
133
- return checkRequired(src);
134
- }
135
- let attachment = checkRequired(this.attachments[src]);
132
+ let attachment = checkRequired(typeof src === 'object' ? src : this.attachments[src]);
136
133
  if (this.virtualfs && this.virtualfs.existsSync(attachment.src)) {
137
- return this.virtualfs.readFileSync(attachment.src);
134
+ return {
135
+ ...attachment,
136
+ src: this.virtualfs.readFileSync(attachment.src)
137
+ };
138
138
  }
139
139
  this.validateLocalFile(attachment.src);
140
140
  return attachment;
@@ -153,9 +153,13 @@ class PageElementWriter extends _ElementWriter.default {
153
153
  /**
154
154
  * Move to the next column in a column group (snaking columns).
155
155
  * Handles repeatables and emits columnChanged event.
156
+ * @param {Function} [updateContext] - Adjust the new column before inserting repeatables
156
157
  */
157
- moveToNextColumn() {
158
+ moveToNextColumn(updateContext) {
158
159
  let nextColumn = this.context().moveToNextColumn();
160
+ if (updateContext) {
161
+ updateContext(this.context());
162
+ }
159
163
 
160
164
  // Handle repeatables (like table headers) for the new column
161
165
  this.repeatables.forEach(function (rep) {
@@ -102,6 +102,7 @@ class TableProcessor {
102
102
  availableWidth = writer.context().availableWidth - this.offsets.total;
103
103
  _columnCalculator.default.buildColumnWidths(tableNode.table.widths, availableWidth, this.offsets.total, tableNode);
104
104
  this.tableWidth = tableNode._offsets.total + getTableInnerContentWidth();
105
+ this.alignTable(writer.context());
105
106
  this.rowSpanData = prepareRowSpanData();
106
107
  this.cleanUpRepeatables = false;
107
108
 
@@ -134,6 +135,15 @@ class TableProcessor {
134
135
  // update the border properties of all cells before drawing any lines
135
136
  prepareCellBorders(this.tableNode.table.body);
136
137
  }
138
+ alignTable(context) {
139
+ const freeWidth = Math.max(0, context.availableWidth - this.tableWidth);
140
+ this.alignmentOffset = this.tableNode.tableAlignment === 'center' ? freeWidth / 2 : this.tableNode.tableAlignment === 'right' ? freeWidth : 0;
141
+ if (this.alignmentOffset) {
142
+ // Keep the container width intact: column widths have already been resolved.
143
+ // Row snapshots preserve this origin across page breaks.
144
+ context.addMargin(this.alignmentOffset, -this.alignmentOffset);
145
+ }
146
+ }
137
147
  onRowBreak(rowIndex, writer) {
138
148
  return () => {
139
149
  let offset = this.rowPaddingTop + (!this.headerRows ? this.topLineWidth : 0);
@@ -340,6 +350,9 @@ class TableProcessor {
340
350
  if (this.cleanUpRepeatables) {
341
351
  writer.popFromRepeatables();
342
352
  }
353
+ if (this.alignmentOffset) {
354
+ writer.context().addMargin(-this.alignmentOffset, this.alignmentOffset);
355
+ }
343
356
  }
344
357
  endRow(rowIndex, writer, pageBreaks) {
345
358
  const getLineXs = () => {
@@ -21,7 +21,7 @@ const groupDecorations = (line, pdfDocument) => {
21
21
  let thickness = (0, _variableType.isNumber)(inline.decorationThickness) ? inline.decorationThickness : null;
22
22
  for (let ii = 0, ll = decoration.length; ii < ll; ii++) {
23
23
  let decorationItem = decoration[ii];
24
- if (!currentGroup || decorationItem !== currentGroup.decoration || style !== currentGroup.decorationStyle || color !== currentGroup.decorationColor) {
24
+ if (!currentGroup || decorationItem !== currentGroup.decoration || style !== currentGroup.decorationStyle || color !== currentGroup.decorationColor || thickness !== currentGroup.decorationThickness) {
25
25
  currentGroup = {
26
26
  line: line,
27
27
  decoration: decorationItem,
@@ -69,7 +69,7 @@ class TextDecorator {
69
69
  let max = 0;
70
70
  for (let i = 0, l = group.inlines.length; i < l; i++) {
71
71
  let inline = group.inlines[i];
72
- max = inline.fontSize > max ? i : max;
72
+ max = inline.fontSize > group.inlines[max].fontSize ? i : max;
73
73
  }
74
74
  return group.inlines[max];
75
75
  };
@@ -135,7 +135,7 @@ class TextDecorator {
135
135
  sv = 1;
136
136
  let nbWaves = Math.ceil(totalWidth / (sh * 2)) + 1;
137
137
  let rwx = x + firstInline.x - 1;
138
- this.pdfDocument.rect(x + firstInline.x, y - sv, totalWidth, y + sv).clip();
138
+ this.pdfDocument.rect(x + firstInline.x, y - sv, totalWidth, 2 * sv).clip();
139
139
  this.pdfDocument.lineWidth(lw / 3);
140
140
  this.pdfDocument.moveTo(rwx, y);
141
141
  for (let i = 0; i < nbWaves; i++) {
@@ -12,7 +12,7 @@ function buildColumnWidths(columns, availableWidth, offsetTotal = 0, tableNode)
12
12
  let starMaxMax = 0;
13
13
  let fixedColumns = [];
14
14
  let initial_availableWidth = availableWidth;
15
- columns.forEach(column => {
15
+ columns.forEach((column, colIndex) => {
16
16
  if (isAutoColumn(column)) {
17
17
  autoColumns.push(column);
18
18
  autoMin += column._minWidth;
@@ -22,10 +22,16 @@ function buildColumnWidths(columns, availableWidth, offsetTotal = 0, tableNode)
22
22
  starMaxMin = Math.max(starMaxMin, column._minWidth);
23
23
  starMaxMax = Math.max(starMaxMax, column._maxWidth);
24
24
  } else {
25
- fixedColumns.push(column);
25
+ fixedColumns.push({
26
+ column,
27
+ colIndex
28
+ });
26
29
  }
27
30
  });
28
- fixedColumns.forEach((col, colIndex) => {
31
+ fixedColumns.forEach(({
32
+ column: col,
33
+ colIndex
34
+ }) => {
29
35
  // width specified as %
30
36
  if ((0, _variableType.isString)(col.width) && /\d+%/.test(col.width)) {
31
37
  // In tables we have to take into consideration the reserved width for paddings and borders
@@ -38,7 +44,7 @@ function buildColumnWidths(columns, availableWidth, offsetTotal = 0, tableNode)
38
44
  if (colIndex === 0) {
39
45
  // first column assumes whole borderLeft and half of border right
40
46
  reservedWidth = paddingLeft + paddingRight + borderLeft + borderRight / 2;
41
- } else if (colIndex === fixedColumns.length - 1) {
47
+ } else if (colIndex === columns.length - 1) {
42
48
  // last column assumes whole borderRight and half of border left
43
49
  reservedWidth = paddingLeft + paddingRight + borderLeft / 2 + borderRight;
44
50
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pdfmake",
3
- "version": "0.3.12",
3
+ "version": "0.3.13",
4
4
  "description": "Client/server side PDF printing in pure JavaScript",
5
5
  "main": "js/index.js",
6
6
  "esnext": "src/index.js",
@@ -493,7 +493,7 @@ class DocumentContext extends EventEmitter {
493
493
  this.availableWidth = pageSize.width - pageMargin.left - pageMargin.right;
494
494
  }
495
495
 
496
- let page = { items: [], pageSize: pageSize, pageMargins: this.pageMargins, customProperties: customProperties };
496
+ let page = { items: [], pageSize: { ...pageSize }, pageMargins: this.pageMargins, customProperties: customProperties };
497
497
  this.pages.push(page);
498
498
  this.backgroundLength.push(0);
499
499
  this.page = this.pages.length - 1;
@@ -331,6 +331,8 @@ class ElementWriter extends EventEmitter {
331
331
  return false;
332
332
  }
333
333
 
334
+ let unbreakableFillsInserted = 0;
335
+
334
336
  block.items.forEach(item => {
335
337
  switch (item.type) {
336
338
  case 'line':
@@ -354,9 +356,11 @@ class ElementWriter extends EventEmitter {
354
356
  offsetVector(v, useBlockXOffset ? (block.xOffset || 0) : ctx.x, useBlockYOffset ? (block.yOffset || 0) : ctx.y);
355
357
  if (v._isFillColorFromUnbreakable) {
356
358
  // If the item is a fillColor from an unbreakable block
357
- // We have to add it at the beginning of the items body array of the page
359
+ // We have to add it at the beginning of the items body array of the page,
360
+ // after the fills already inserted from this block so that they keep their draw order
358
361
  delete v._isFillColorFromUnbreakable;
359
- const endOfBackgroundItemsIndex = ctx.backgroundLength[ctx.page];
362
+ const endOfBackgroundItemsIndex = ctx.backgroundLength[ctx.page] + unbreakableFillsInserted;
363
+ unbreakableFillsInserted++;
360
364
  page.items.splice(endOfBackgroundItemsIndex, 0, {
361
365
  type: 'vector',
362
366
  item: v
@@ -566,8 +566,9 @@ class LayoutBuilder {
566
566
  * When in snaking columns, first tries moving to next column.
567
567
  * If no columns available, moves to next page and resets x to left margin.
568
568
  * @param {string} pageOrientation - Optional page orientation for the new page
569
+ * @param {TableProcessor} [tableProcessor] - Reapply table alignment in the new column
569
570
  */
570
- snakingAwarePageBreak(pageOrientation) {
571
+ snakingAwarePageBreak(pageOrientation, tableProcessor) {
571
572
  let ctx = this.writer.context();
572
573
  let snakingSnapshot = ctx.getSnakingSnapshot();
573
574
  if (!snakingSnapshot) {
@@ -576,7 +577,7 @@ class LayoutBuilder {
576
577
 
577
578
  // Try flowing to next column first
578
579
  if (this.writer.canMoveToNextColumn()) {
579
- this.writer.moveToNextColumn();
580
+ this.writer.moveToNextColumn(tableProcessor ? context => tableProcessor.alignTable(context) : undefined);
580
581
  return;
581
582
  }
582
583
 
@@ -590,6 +591,9 @@ class LayoutBuilder {
590
591
  let savedLastColumnWidth = ctx.lastColumnWidth;
591
592
  ctx.resetSnakingColumnsForNewPage();
592
593
  ctx.lastColumnWidth = savedLastColumnWidth;
594
+ if (tableProcessor) {
595
+ tableProcessor.alignTable(ctx);
596
+ }
593
597
  }
594
598
 
595
599
  // vertical container
@@ -1072,7 +1076,7 @@ class LayoutBuilder {
1072
1076
  let rowTopPageY = this.cell._leftEndingCell._startingRowSpanY + this.cell._leftEndingCell._rowTopPageYPadding;
1073
1077
  return this.cell._leftEndingCell._rowTopPageY - rowTopPageY + this.cell._leftEndingCell._bottomY;
1074
1078
  } else {
1075
- if (this.cell.positions[0].pageNumber !== this.cell._leftEndingCell._lastPageNumber) {
1079
+ if (this.cell._lastPageNumber !== this.cell._leftEndingCell._lastPageNumber) {
1076
1080
  return this.bottomY - this.cell._leftEndingCell._bottomY;
1077
1081
  }
1078
1082
 
@@ -1165,7 +1169,11 @@ class LayoutBuilder {
1165
1169
  processor.bottomLineWidth + processor.topLineWidth
1166
1170
  );
1167
1171
  if (this.writer.context().availableHeight < minRowHeight) {
1168
- this.snakingAwarePageBreak();
1172
+ // Column selection needs the container origin, before table alignment.
1173
+ if (processor.alignmentOffset) {
1174
+ this.writer.context().addMargin(-processor.alignmentOffset, processor.alignmentOffset);
1175
+ }
1176
+ this.snakingAwarePageBreak(undefined, processor);
1169
1177
 
1170
1178
  // Skip border when headerRows present (header repeat includes it)
1171
1179
  if (processor.layout.hLineWhenBroken !== false && !processor.headerRows) {
@@ -6,13 +6,27 @@ class OutputDocument {
6
6
  constructor(pdfDocumentPromise) {
7
7
  this.pdfDocumentPromise = pdfDocumentPromise;
8
8
  this.bufferPromise = null;
9
+ this.streamEnded = false;
10
+ this.streamEndListenerAttached = false;
9
11
  }
10
12
 
11
13
  /**
12
14
  * @returns {Promise<object>}
13
15
  */
14
- getStream() {
15
- return this.pdfDocumentPromise;
16
+ async getStream() {
17
+ const stream = await this.pdfDocumentPromise;
18
+ if (this.streamEnded) {
19
+ throw new Error('PDF stream has already been consumed.');
20
+ }
21
+
22
+ if (!this.streamEndListenerAttached) {
23
+ stream.once('end', () => {
24
+ this.streamEnded = true;
25
+ });
26
+ this.streamEndListenerAttached = true;
27
+ }
28
+
29
+ return stream;
16
30
  }
17
31
 
18
32
  /**
@@ -21,7 +35,7 @@ class OutputDocument {
21
35
  getBuffer() {
22
36
  const getBufferInternal = (async () => {
23
37
  const stream = await this.getStream();
24
- return new Promise((resolve) => {
38
+ return new Promise((resolve, reject) => {
25
39
  let chunks = [];
26
40
  stream.on('data', chunk => {
27
41
  chunks.push(chunk);
@@ -29,6 +43,7 @@ class OutputDocument {
29
43
  stream.on('end', () => {
30
44
  resolve(Buffer.concat(chunks));
31
45
  });
46
+ stream.on('error', reject);
32
47
  stream.end();
33
48
  });
34
49
  });
@@ -8,6 +8,12 @@ class OutputDocumentServer extends OutputDocument {
8
8
  * @returns {Promise}
9
9
  */
10
10
  async write(filename) {
11
+ await this.pdfDocumentPromise;
12
+ if (this.bufferPromise !== null) {
13
+ await fs.promises.writeFile(filename, await this.getBuffer());
14
+ return;
15
+ }
16
+
11
17
  const stream = await this.getStream();
12
18
  const writeStream = fs.createWriteStream(filename);
13
19
 
@@ -154,14 +154,13 @@ class PDFDocument extends PDFKitDocument {
154
154
  return obj;
155
155
  };
156
156
 
157
- if (typeof src === 'object') {
158
- return checkRequired(src);
159
- }
160
-
161
- let attachment = checkRequired(this.attachments[src]);
157
+ let attachment = checkRequired(typeof src === 'object' ? src : this.attachments[src]);
162
158
 
163
159
  if (this.virtualfs && this.virtualfs.existsSync(attachment.src)) {
164
- return this.virtualfs.readFileSync(attachment.src);
160
+ return {
161
+ ...attachment,
162
+ src: this.virtualfs.readFileSync(attachment.src)
163
+ };
165
164
  }
166
165
 
167
166
  this.validateLocalFile(attachment.src);
@@ -176,9 +176,13 @@ class PageElementWriter extends ElementWriter {
176
176
  /**
177
177
  * Move to the next column in a column group (snaking columns).
178
178
  * Handles repeatables and emits columnChanged event.
179
+ * @param {Function} [updateContext] - Adjust the new column before inserting repeatables
179
180
  */
180
- moveToNextColumn() {
181
+ moveToNextColumn(updateContext) {
181
182
  let nextColumn = this.context().moveToNextColumn();
183
+ if (updateContext) {
184
+ updateContext(this.context());
185
+ }
182
186
 
183
187
  // Handle repeatables (like table headers) for the new column
184
188
  this.repeatables.forEach(function (rep) {
@@ -109,6 +109,7 @@ class TableProcessor {
109
109
  ColumnCalculator.buildColumnWidths(tableNode.table.widths, availableWidth, this.offsets.total, tableNode);
110
110
 
111
111
  this.tableWidth = tableNode._offsets.total + getTableInnerContentWidth();
112
+ this.alignTable(writer.context());
112
113
  this.rowSpanData = prepareRowSpanData();
113
114
  this.cleanUpRepeatables = false;
114
115
 
@@ -150,6 +151,17 @@ class TableProcessor {
150
151
  prepareCellBorders(this.tableNode.table.body);
151
152
  }
152
153
 
154
+ alignTable(context) {
155
+ const freeWidth = Math.max(0, context.availableWidth - this.tableWidth);
156
+ this.alignmentOffset = this.tableNode.tableAlignment === 'center' ? freeWidth / 2 :
157
+ (this.tableNode.tableAlignment === 'right' ? freeWidth : 0);
158
+ if (this.alignmentOffset) {
159
+ // Keep the container width intact: column widths have already been resolved.
160
+ // Row snapshots preserve this origin across page breaks.
161
+ context.addMargin(this.alignmentOffset, -this.alignmentOffset);
162
+ }
163
+ }
164
+
153
165
  onRowBreak(rowIndex, writer) {
154
166
  return () => {
155
167
  let offset = this.rowPaddingTop + (!this.headerRows ? this.topLineWidth : 0);
@@ -376,6 +388,9 @@ class TableProcessor {
376
388
  if (this.cleanUpRepeatables) {
377
389
  writer.popFromRepeatables();
378
390
  }
391
+ if (this.alignmentOffset) {
392
+ writer.context().addMargin(-this.alignmentOffset, this.alignmentOffset);
393
+ }
379
394
  }
380
395
 
381
396
  endRow(rowIndex, writer, pageBreaks) {
@@ -19,7 +19,8 @@ const groupDecorations = (line, pdfDocument) => {
19
19
  for (let ii = 0, ll = decoration.length; ii < ll; ii++) {
20
20
  let decorationItem = decoration[ii];
21
21
  if (!currentGroup || decorationItem !== currentGroup.decoration ||
22
- style !== currentGroup.decorationStyle || color !== currentGroup.decorationColor) {
22
+ style !== currentGroup.decorationStyle || color !== currentGroup.decorationColor ||
23
+ thickness !== currentGroup.decorationThickness) {
23
24
 
24
25
  currentGroup = {
25
26
  line: line,
@@ -79,7 +80,7 @@ class TextDecorator {
79
80
  let max = 0;
80
81
  for (let i = 0, l = group.inlines.length; i < l; i++) {
81
82
  let inline = group.inlines[i];
82
- max = inline.fontSize > max ? i : max;
83
+ max = inline.fontSize > group.inlines[max].fontSize ? i : max;
83
84
  }
84
85
  return group.inlines[max];
85
86
  };
@@ -155,7 +156,7 @@ class TextDecorator {
155
156
  let sh = 0.7, sv = 1;
156
157
  let nbWaves = Math.ceil(totalWidth / (sh * 2)) + 1;
157
158
  let rwx = x + firstInline.x - 1;
158
- this.pdfDocument.rect(x + firstInline.x, y - sv, totalWidth, y + sv).clip();
159
+ this.pdfDocument.rect(x + firstInline.x, y - sv, totalWidth, 2 * sv).clip();
159
160
  this.pdfDocument.lineWidth(lw / 3);
160
161
  this.pdfDocument.moveTo(rwx, y);
161
162
  for (let i = 0; i < nbWaves; i++) {
@@ -10,7 +10,7 @@ function buildColumnWidths(columns, availableWidth, offsetTotal = 0, tableNode)
10
10
  let fixedColumns = [];
11
11
  let initial_availableWidth = availableWidth;
12
12
 
13
- columns.forEach(column => {
13
+ columns.forEach((column, colIndex) => {
14
14
  if (isAutoColumn(column)) {
15
15
  autoColumns.push(column);
16
16
  autoMin += column._minWidth;
@@ -20,11 +20,11 @@ function buildColumnWidths(columns, availableWidth, offsetTotal = 0, tableNode)
20
20
  starMaxMin = Math.max(starMaxMin, column._minWidth);
21
21
  starMaxMax = Math.max(starMaxMax, column._maxWidth);
22
22
  } else {
23
- fixedColumns.push(column);
23
+ fixedColumns.push({ column, colIndex });
24
24
  }
25
25
  });
26
26
 
27
- fixedColumns.forEach((col, colIndex) => {
27
+ fixedColumns.forEach(({ column: col, colIndex }) => {
28
28
  // width specified as %
29
29
  if (isString(col.width) && /\d+%/.test(col.width)) {
30
30
  // In tables we have to take into consideration the reserved width for paddings and borders
@@ -38,7 +38,7 @@ function buildColumnWidths(columns, availableWidth, offsetTotal = 0, tableNode)
38
38
  // first column assumes whole borderLeft and half of border right
39
39
  reservedWidth = paddingLeft + paddingRight + borderLeft + (borderRight / 2);
40
40
 
41
- } else if (colIndex === fixedColumns.length - 1) {
41
+ } else if (colIndex === columns.length - 1) {
42
42
  // last column assumes whole borderRight and half of border left
43
43
  reservedWidth = paddingLeft + paddingRight + (borderLeft / 2) + borderRight;
44
44