Skip to content

Commit b941752

Browse files
committed
For danfickle#180 - PERF - Only create page lists of collected boxes if required.
Saves memory if not every layer will draw every box category on every page. Also, have a separate list for replaced elements, so we don’t have to scan the blocks list when painting them.
1 parent 710b964 commit b941752

File tree

3 files changed

+103
-39
lines changed

3 files changed

+103
-39
lines changed

openhtmltopdf-core/src/main/java/com/openhtmltopdf/layout/Layer.java

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -400,9 +400,9 @@ private void dlCollect(RenderingContext c, List<List<DisplayListOperation>> dlPa
400400
PageResult pg = pgResults.get(i);
401401
List<DisplayListOperation> dlPageList = dlPages.get(i);
402402

403-
if (!pg.blocks.isEmpty()) {
404-
Map<TableCellBox, List<CollapsedBorderSide>> collapsedTableBorders = pg.tcells.isEmpty() ? null : dlCollectCollapsedTableBorders(c, pg.tcells);
405-
DisplayListOperation dlo = new PaintBackgroundAndBorders(pg.blocks, c, collapsedTableBorders);
403+
if (!pg.blocks().isEmpty()) {
404+
Map<TableCellBox, List<CollapsedBorderSide>> collapsedTableBorders = pg.tcells().isEmpty() ? null : dlCollectCollapsedTableBorders(c, pg.tcells());
405+
DisplayListOperation dlo = new PaintBackgroundAndBorders(pg.blocks(), c, collapsedTableBorders);
406406
dlPageList.add(dlo);
407407
}
408408

@@ -413,18 +413,18 @@ private void dlCollect(RenderingContext c, List<List<DisplayListOperation>> dlPa
413413
}
414414
}
415415

416-
if (!pg.blocks.isEmpty()) {
417-
DisplayListOperation dlo = new PaintListMarkers(pg.blocks, c);
416+
if (!pg.blocks().isEmpty()) {
417+
DisplayListOperation dlo = new PaintListMarkers(pg.blocks(), c);
418418
dlPageList.add(dlo);
419419
}
420420

421-
if (!pg.inlines.isEmpty()) {
422-
DisplayListOperation dlo = new PaintInlineContent(pg.inlines, c);
421+
if (!pg.inlines().isEmpty()) {
422+
DisplayListOperation dlo = new PaintInlineContent(pg.inlines(), c);
423423
dlPageList.add(dlo);
424424
}
425425

426-
if (!pg.blocks.isEmpty()) {
427-
DisplayListOperation dlo = new PaintReplacedElements(pg.blocks, c);
426+
if (!pg.replaceds().isEmpty()) {
427+
DisplayListOperation dlo = new PaintReplacedElements(pg.replaceds(), c);
428428
dlPageList.add(dlo);
429429
}
430430
}
@@ -449,24 +449,24 @@ private void dlCollectFloatAsLayer(RenderingContext c, List<PageBox> pages, Bloc
449449
PageResult pg = pgResults.get(i);
450450
List<DisplayListOperation> dlPageList = dlPages.get(i);
451451

452-
if (!pg.blocks.isEmpty()) {
453-
Map<TableCellBox, List<CollapsedBorderSide>> collapsedTableBorders = pg.tcells.isEmpty() ? null : dlCollectCollapsedTableBorders(c, pg.tcells);
454-
DisplayListOperation dlo = new PaintBackgroundAndBorders(pg.blocks, c, collapsedTableBorders);
452+
if (!pg.blocks().isEmpty()) {
453+
Map<TableCellBox, List<CollapsedBorderSide>> collapsedTableBorders = pg.tcells().isEmpty() ? null : dlCollectCollapsedTableBorders(c, pg.tcells());
454+
DisplayListOperation dlo = new PaintBackgroundAndBorders(pg.blocks(), c, collapsedTableBorders);
455455
dlPageList.add(dlo);
456456
}
457457

458-
if (!pg.blocks.isEmpty()) {
459-
DisplayListOperation dlo = new PaintListMarkers(pg.blocks, c);
458+
if (!pg.blocks().isEmpty()) {
459+
DisplayListOperation dlo = new PaintListMarkers(pg.blocks(), c);
460460
dlPageList.add(dlo);
461461
}
462462

463-
if (!pg.inlines.isEmpty()) {
464-
DisplayListOperation dlo = new PaintInlineContent(pg.inlines, c);
463+
if (!pg.inlines().isEmpty()) {
464+
DisplayListOperation dlo = new PaintInlineContent(pg.inlines(), c);
465465
dlPageList.add(dlo);
466466
}
467467

468-
if (!pg.blocks.isEmpty()) {
469-
DisplayListOperation dlo = new PaintReplacedElements(pg.blocks, c);
468+
if (!pg.replaceds().isEmpty()) {
469+
DisplayListOperation dlo = new PaintReplacedElements(pg.replaceds(), c);
470470
dlPageList.add(dlo);
471471
}
472472
}
@@ -555,20 +555,31 @@ private void dlPaintInlineContent(RenderingContext c, List<DisplayListItem> inli
555555
}
556556
}
557557

558-
private void dlPaintReplacedElements(RenderingContext c, List<DisplayListItem> blocks) {
559-
for (DisplayListItem dli : blocks) {
558+
private void dlPaintReplacedElements(RenderingContext c, List<DisplayListItem> replaceds) {
559+
for (int i = 0; i < replaceds.size(); i++) {
560+
DisplayListItem dli = replaceds.get(i);
561+
DisplayListItem prev = (i - 1) >= 0 ? replaceds.get(i - 1) : null;
562+
DisplayListItem next = (i + 1) < replaceds.size() ? replaceds.get(i + 1) : null;
563+
560564
if (dli instanceof OperatorClip) {
565+
if (next instanceof OperatorSetClip) {
566+
// Its an empty clip/setClip pair with no replaceds between them.
567+
continue;
568+
}
569+
561570
OperatorClip clip = (OperatorClip) dli;
562571
c.getOutputDevice().clip(clip.getClip());
563572
} else if (dli instanceof OperatorSetClip) {
573+
if (prev instanceof OperatorClip) {
574+
// Its an empty clip/setClip pair with no replaceds between them.
575+
continue;
576+
}
577+
564578
OperatorSetClip setClip = (OperatorSetClip) dli;
565579
c.getOutputDevice().setClip(setClip.getSetClipShape());
566580
} else {
567581
BlockBox box = (BlockBox) dli;
568-
569-
if (box.isReplaced()) {
570-
c.getOutputDevice().paintReplacedElement(c, box);
571-
}
582+
c.getOutputDevice().paintReplacedElement(c, box);
572583
}
573584
}
574585
}
@@ -610,7 +621,7 @@ public void dlPaint(RenderingContext c, List<DisplayListOperation> pageOperation
610621
} else if (op instanceof PaintReplacedElements) {
611622

612623
PaintReplacedElements dlo = (PaintReplacedElements) op;
613-
dlPaintReplacedElements(dlo.getContext(), dlo.getBlocks());
624+
dlPaintReplacedElements(dlo.getContext(), dlo.getReplaceds());
614625

615626
} else {
616627

openhtmltopdf-core/src/main/java/com/openhtmltopdf/layout/PagedBoxCollector.java

Lines changed: 66 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.awt.Rectangle;
44
import java.awt.Shape;
55
import java.util.ArrayList;
6+
import java.util.Collections;
67
import java.util.List;
78

89
import com.openhtmltopdf.css.style.CssContext;
@@ -21,9 +22,54 @@
2122
public class PagedBoxCollector {
2223

2324
public static class PageResult {
24-
public final List<DisplayListItem> blocks = new ArrayList<DisplayListItem>();
25-
public final List<DisplayListItem> inlines = new ArrayList<DisplayListItem>();
26-
public final List<TableCellBox> tcells = new ArrayList<TableCellBox>();
25+
private List<DisplayListItem> _blocks = null;
26+
private List<DisplayListItem> _inlines = null;
27+
private List<TableCellBox> _tcells = null;
28+
private List<DisplayListItem> _replaceds = null;
29+
30+
private void addBlock(DisplayListItem block) {
31+
if (_blocks == null) {
32+
_blocks = new ArrayList<DisplayListItem>();
33+
}
34+
_blocks.add(block);
35+
}
36+
37+
private void addInline(DisplayListItem inline) {
38+
if (_inlines == null) {
39+
_inlines = new ArrayList<DisplayListItem>();
40+
}
41+
_inlines.add(inline);
42+
}
43+
44+
private void addTableCell(TableCellBox tcell) {
45+
if (_tcells == null) {
46+
_tcells = new ArrayList<TableCellBox>();
47+
}
48+
_tcells.add(tcell);
49+
}
50+
51+
private void addReplaced(DisplayListItem replaced) {
52+
if (_replaceds == null) {
53+
_replaceds = new ArrayList<DisplayListItem>();
54+
}
55+
_replaceds.add(replaced);
56+
}
57+
58+
public List<DisplayListItem> blocks() {
59+
return this._blocks == null ? Collections.<DisplayListItem>emptyList() : this._blocks;
60+
}
61+
62+
public List<DisplayListItem> inlines() {
63+
return this._inlines == null ? Collections.<DisplayListItem>emptyList() : this._inlines;
64+
}
65+
66+
public List<TableCellBox> tcells() {
67+
return this._tcells == null ? Collections.<TableCellBox>emptyList() : this._tcells;
68+
}
69+
70+
public List<DisplayListItem> replaceds() {
71+
return this._replaceds == null ? Collections.<DisplayListItem>emptyList() : this._replaceds;
72+
}
2773
}
2874

2975
public static class PageFinder {
@@ -127,13 +173,13 @@ private void collectInline(CssContext c, Layer layer) {
127173

128174
if (b.intersects(c, pageClip)) {
129175
if (b instanceof InlineLayoutBox) {
130-
result.get(i).inlines.add(b);
176+
result.get(i).addInline(b);
131177
} else {
132178
BlockBox bb = (BlockBox) b;
133179

134180
if (bb.isInline()) {
135181
if (intersectsAny(c, pageClip, b, b)) {
136-
result.get(i).inlines.add(b);
182+
result.get(i).addInline(b);
137183
}
138184
} else {
139185
collect(c, layer, bb, pageClip);
@@ -170,10 +216,10 @@ public void collect(CssContext c, Layer layer, Box container, Shape parentClip)
170216

171217
for (int i = pgStart; i <= pgEnd; i++) {
172218
PageResult res = result.get(i);
173-
res.inlines.add(container);
219+
res.addInline(container);
174220

175221
// Recursively add all children of the line box to the inlines list.
176-
((LineBox) container).addAllChildren(res.inlines, layer);
222+
((LineBox) container).addAllChildren(res._inlines, layer);
177223
}
178224

179225
} else {
@@ -206,15 +252,21 @@ public void collect(CssContext c, Layer layer, Box container, Shape parentClip)
206252
if (ourClip != null) {
207253
// Add a clip operation before the block and its descendents (inline or block).
208254
DisplayListItem dlClip = new OperatorClip(ourClip);
209-
pageResult.blocks.add(dlClip);
210-
pageResult.inlines.add(dlClip);
255+
pageResult.addBlock(dlClip);
256+
pageResult.addInline(dlClip);
257+
pageResult.addReplaced(dlClip);
211258
}
212259

213-
pageResult.blocks.add(container);
260+
pageResult.addBlock(container);
261+
262+
if (container instanceof BlockBox &&
263+
((BlockBox) container).isReplaced()) {
264+
pageResult.addReplaced(container);
265+
}
214266

215267
if (container instanceof TableCellBox &&
216268
((TableCellBox) container).hasCollapsedPaintingBorder()) {
217-
pageResult.tcells.add((TableCellBox) container);
269+
pageResult.addTableCell((TableCellBox) container);
218270
}
219271
}
220272
}
@@ -249,8 +301,9 @@ public void collect(CssContext c, Layer layer, Box container, Shape parentClip)
249301
// Test to see if it fits within the page margins.
250302
if (intersectsAggregateBounds(pageClip, container)) {
251303
DisplayListItem dlSetClip = new OperatorSetClip(parentClip);
252-
pageResult.blocks.add(dlSetClip);
253-
pageResult.inlines.add(dlSetClip);
304+
pageResult.addBlock(dlSetClip);
305+
pageResult.addInline(dlSetClip);
306+
pageResult.addReplaced(dlSetClip);
254307
}
255308
}
256309
}

openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/displaylist/PaintReplacedElements.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public PaintReplacedElements(List<DisplayListItem> blocks, RenderingContext c) {
1414
this.context = c;
1515
}
1616

17-
public List<DisplayListItem> getBlocks() {
17+
public List<DisplayListItem> getReplaceds() {
1818
return blocks;
1919
}
2020

0 commit comments

Comments
 (0)