Skip to content

Commit d0a9a2d

Browse files
committed
[RELEASE] iText 7 pdfHTML - 2.1.5
https://github.com/itext/i7j-pdfhtml/releases/tag/2.1.5 * release/2.1.5: [RELEASE] 2.1.5-SNAPSHOT -> 2.1.5 Make first letter of resource file small Purge itext artifacts from local maven repository Do not use paragraph's end tags for separation reasons in Javadoc. Improve flushing of HtmlDocumentRenderer Call equals() for string literal, passing the variable as an argument, to avoid NPE Add functional ranges tests from html2pdf private Use local Maven repository Update README.md DEVSIX-3176 Fix a few SpotBugs warnings Add tests for generic font families Fix some typos in javadocs of CssConstants Add missing copyright headers Fix parsing named page size declarations with orientation in @page media Add new unit test for PageSizeParser Add test illustrating the issue Move html tests from FT repository Move test HTML_BlockElements from FT repository Add a test which demonstrates the issue with invalid font size processing. Move tests from FT repository Refactor Jenkinsfile QA-2471 Add missing copyright headers Fix counter(pages) calculation in case page is trimmed at the end Move tests from FT repository Add slack notifications to #ci channel Add monthly cron job for master branch Move html with svg tests Move HTML_Tables tests Move HTML_Lists tests Move tests from FT repository [RELEASE] Update dependency versions Partial revert of commit f9eb6af to re-enable code coverage Don't provide a SonarQube target branch when analyzing the main branch
2 parents b942f42 + dc3f422 commit d0a9a2d

File tree

260 files changed

+22683
-175
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

260 files changed

+22683
-175
lines changed

Jenkinsfile

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
#!/usr/bin/env groovy
2+
@Library('pipeline-library')_
3+
4+
def schedule = env.BRANCH_NAME.contains('master') ? '@monthly' : env.BRANCH_NAME == 'develop' ? '@midnight' : ''
5+
def sonarBranchName = env.BRANCH_NAME.contains('master') ? '-Dsonar.branch.name=master' : '-Dsonar.branch.name=' + env.BRANCH_NAME
6+
def sonarBranchTarget = env.BRANCH_NAME.contains('master') ? '' : env.BRANCH_NAME == 'develop' ? '-Dsonar.branch.target=master' : '-Dsonar.branch.target=develop'
27

38
pipeline {
49

@@ -19,7 +24,7 @@ pipeline {
1924
}
2025

2126
triggers {
22-
cron(env.BRANCH_NAME == 'develop' ? '@midnight' : '')
27+
cron(schedule)
2328
}
2429

2530
tools {
@@ -33,8 +38,9 @@ pipeline {
3338
timeout(time: 5, unit: 'MINUTES')
3439
}
3540
steps {
36-
withMaven(jdk: "${JDK_VERSION}", maven: 'M3') {
41+
withMaven(jdk: "${JDK_VERSION}", maven: 'M3', mavenLocalRepo: '.repository') {
3742
sh 'mvn clean'
43+
sh 'mvn dependency:purge-local-repository -Dinclude=com.itextpdf -DresolutionFuzziness=groupId -DreResolve=false'
3844
}
3945
}
4046
}
@@ -43,22 +49,19 @@ pipeline {
4349
timeout(time: 5, unit: 'MINUTES')
4450
}
4551
steps {
46-
withMaven(jdk: "${JDK_VERSION}", maven: 'M3') {
47-
sh 'mvn compile test-compile'
52+
withMaven(jdk: "${JDK_VERSION}", maven: 'M3', mavenLocalRepo: '.repository') {
53+
sh 'mvn compile test-compile package -Dmaven.test.skip=true -Dmaven.javadoc.failOnError=false'
4854
}
4955
}
5056
}
5157
stage('Run Tests') {
5258
options {
5359
timeout(time: 30, unit: 'MINUTES')
5460
}
55-
environment {
56-
SONAR_BRANCH_TARGET= sh (returnStdout: true, script: '[ $BRANCH_NAME = master ] && echo master || echo develop').trim()
57-
}
5861
steps {
59-
withMaven(jdk: "${JDK_VERSION}", maven: 'M3') {
62+
withMaven(jdk: "${JDK_VERSION}", maven: 'M3', mavenLocalRepo: '.repository') {
6063
withSonarQubeEnv('Sonar') {
61-
sh 'mvn --activate-profiles test verify -DgsExec="${gsExec}" -DcompareExec="${compareExec}" -Dmaven.test.skip=false -Dmaven.test.failure.ignore=false -Dmaven.javadoc.skip=true org.jacoco:jacoco-maven-plugin:prepare-agent org.jacoco:jacoco-maven-plugin:report sonar:sonar -Dsonar.branch.name="${BRANCH_NAME}" -Dsonar.branch.target="${SONAR_BRANCH_TARGET}"'
64+
sh 'mvn --activate-profiles test -DgsExec="${gsExec}" -DcompareExec="${compareExec}" -Dmaven.test.skip=false -Dmaven.test.failure.ignore=false -Dmaven.javadoc.skip=true org.jacoco:jacoco-maven-plugin:prepare-agent verify org.jacoco:jacoco-maven-plugin:report sonar:sonar ' + sonarBranchName + ' ' + sonarBranchTarget
6265
}
6366
}
6467
}
@@ -68,7 +71,7 @@ pipeline {
6871
timeout(time: 30, unit: 'MINUTES')
6972
}
7073
steps {
71-
withMaven(jdk: "${JDK_VERSION}", maven: 'M3') {
74+
withMaven(jdk: "${JDK_VERSION}", maven: 'M3', mavenLocalRepo: '.repository') {
7275
sh 'mvn --activate-profiles qa verify -Dpmd.analysisCache=true'
7376
}
7477
}
@@ -108,7 +111,7 @@ pipeline {
108111
timeout(time: 5, unit: 'MINUTES')
109112
}
110113
steps {
111-
archiveArtifacts allowEmptyArchive: true, artifacts: '**/*.jar'
114+
archiveArtifacts allowEmptyArchive: true, artifacts: 'target/*.jar, target/*.pom', excludes: '**/fb-contrib-*.jar, **/findsecbugs-plugin-*.jar'
112115
}
113116
}
114117
}
@@ -129,6 +132,20 @@ pipeline {
129132
changed {
130133
echo 'Things were different before... \uD83E\uDD14'
131134
}
135+
fixed {
136+
script {
137+
if (env.BRANCH_NAME.contains('master') || (env.BRANCH_NAME == 'develop')) {
138+
slackNotifier("#ci", currentBuild.currentResult, "${env.BRANCH_NAME} - Back to normal")
139+
}
140+
}
141+
}
142+
regression {
143+
script {
144+
if (env.BRANCH_NAME.contains('master') || (env.BRANCH_NAME == 'develop')) {
145+
slackNotifier("#ci", currentBuild.currentResult, "${env.BRANCH_NAME} - First failure")
146+
}
147+
}
148+
}
132149
}
133150

134151
}

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ Contact [sales] for more info.
3131
[building]: BUILDING.md
3232
[contributing]: https://github.com/itext/itext7/blob/develop/CONTRIBUTING.md
3333
[itext]: http://itextpdf.com/
34-
[github]: https://github.com/itext/pdfHtml
35-
[latest]: https://github.com/itext/pdfHtml/releases/latest
34+
[github]: https://github.com/itext/i7j-pdfhtml/
35+
[latest]: https://github.com/itext/i7j-pdfhtml/releases/latest
3636
[sales]: http://itextpdf.com/sales
3737
[gratis]: https://en.wikipedia.org/wiki/Gratis_versus_libre
3838
[pdfHtml]: http://itextpdf.com/itext7/pdfHtml

findbugs-filter.xml

Lines changed: 0 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -22,81 +22,9 @@
2222
</Or>
2323
<Bug pattern="EXS_EXCEPTION_SOFTENING_NO_CONSTRAINTS"/>
2424
</Match>
25-
<Match>
26-
<Class name="com.itextpdf.html2pdf.attach.impl.DefaultHtmlProcessor"/>
27-
<Method name="visit" params="com.itextpdf.styledxmlparser.node.INode"/>
28-
<Bug pattern="LSC_LITERAL_STRING_COMPARISON"/>
29-
</Match>
30-
<Match>
31-
<Class name="com.itextpdf.html2pdf.attach.impl.layout.HeightDimensionContainer"/>
32-
<Method
33-
name="&lt;init&gt;"
34-
params="com.itextpdf.styledxmlparser.css.CssContextNode, float, float, com.itextpdf.layout.renderer.IRenderer, float"
35-
/>
36-
<Bug pattern="LSC_LITERAL_STRING_COMPARISON"/>
37-
</Match>
38-
<Match>
39-
<Class name="com.itextpdf.html2pdf.attach.impl.layout.WidthDimensionContainer"/>
40-
<Method
41-
name="&lt;init&gt;"
42-
params="com.itextpdf.styledxmlparser.css.CssContextNode, float, com.itextpdf.layout.renderer.IRenderer, float"
43-
/>
44-
<Bug pattern="LSC_LITERAL_STRING_COMPARISON"/>
45-
</Match>
46-
<Match>
47-
<Class name="com.itextpdf.html2pdf.attach.impl.tags.ThTagWorker"/>
48-
<Method
49-
name="processEnd"
50-
params="com.itextpdf.styledxmlparser.node.IElementNode, com.itextpdf.html2pdf.attach.ProcessorContext"
51-
/>
52-
<Bug pattern="LSC_LITERAL_STRING_COMPARISON"/>
53-
</Match>
54-
<Match>
55-
<Class name="com.itextpdf.html2pdf.attach.util.WaitingColgroupsHelper"/>
56-
<Or>
57-
<Method name="applyColStyles" params=""/>
58-
<Method
59-
name="applyColStyles"
60-
params="com.itextpdf.styledxmlparser.node.INode, com.itextpdf.html2pdf.attach.util.RowColHelper"
61-
/>
62-
</Or>
63-
<Bug pattern="LSC_LITERAL_STRING_COMPARISON"/>
64-
</Match>
6525
<Match>
6626
<Class name="com.itextpdf.html2pdf.css.CssConstants"/>
6727
<Field name="OVERFLOW_VALUES"/>
6828
<Bug pattern="MS_MUTABLE_COLLECTION"/>
6929
</Match>
70-
<Match>
71-
<Class name="com.itextpdf.html2pdf.css.apply.util.BackgroundApplierUtil"/>
72-
<Method
73-
name="applyBackground"
74-
params="java.util.Map, com.itextpdf.html2pdf.attach.ProcessorContext, com.itextpdf.layout.IPropertyContainer"
75-
/>
76-
<Bug pattern="LSC_LITERAL_STRING_COMPARISON"/>
77-
</Match>
78-
<Match>
79-
<Class name="com.itextpdf.html2pdf.css.apply.util.FontStyleApplierUtil"/>
80-
<Method
81-
name="applyFontStyles"
82-
params="java.util.Map, com.itextpdf.html2pdf.attach.ProcessorContext, com.itextpdf.styledxmlparser.node.IStylesContainer, com.itextpdf.layout.IPropertyContainer"
83-
/>
84-
<Bug pattern="LSC_LITERAL_STRING_COMPARISON"/>
85-
</Match>
86-
<Match>
87-
<Class name="com.itextpdf.html2pdf.css.resolve.DefaultCssResolver"/>
88-
<Method
89-
name="collectCssDeclarations"
90-
params="com.itextpdf.styledxmlparser.node.INode, com.itextpdf.styledxmlparser.resolver.resource.ResourceResolver, com.itextpdf.html2pdf.css.resolve.CssContext"
91-
/>
92-
<Or>
93-
<Bug pattern="DM_DEFAULT_ENCODING"/>
94-
<Bug pattern="LSC_LITERAL_STRING_COMPARISON"/>
95-
</Or>
96-
</Match>
97-
<Match>
98-
<Class name="com.itextpdf.html2pdf.html.HtmlUtils"/>
99-
<Method name="isStyleSheetLink" params="com.itextpdf.styledxmlparser.node.IElementNode"/>
100-
<Bug pattern="LSC_LITERAL_STRING_COMPARISON"/>
101-
</Match>
10230
</FindBugsFilter>

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
<parent>
55
<groupId>com.itextpdf</groupId>
66
<artifactId>root</artifactId>
7-
<version>7.1.7</version>
7+
<version>7.1.8</version>
88
<relativePath/>
99
</parent>
1010
<artifactId>html2pdf</artifactId>
11-
<version>2.1.4</version>
11+
<version>2.1.5</version>
1212
<name>pdfHTML</name>
1313
<description>pdfHTML is an iText 7 add-on that lets you to parse (X)HTML snippets and the associated CSS and converts
1414
them to PDF.</description>

src/main/java/com/itextpdf/html2pdf/attach/impl/DefaultHtmlProcessor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ private void visit(INode node) {
330330

331331
visitPseudoElement(element, tagWorker, CssConstants.BEFORE);
332332
visitPseudoElement(element, tagWorker, CssConstants.PLACEHOLDER);
333-
if (element.name().equals(TagConstants.BODY) || element.name().equals(TagConstants.HTML))
333+
if (TagConstants.BODY.equals(element.name()) || TagConstants.HTML.equals(element.name()))
334334
runApplier(element, tagWorker);
335335
for (INode childNode : element.childNodes()) {
336336
if (!context.isProcessingInlineSvg()) {
@@ -345,7 +345,7 @@ private void visit(INode node) {
345345
context.getOutlineHandler().addDestination(tagWorker, element);
346346
context.getState().pop();
347347

348-
if (!element.name().equals(TagConstants.BODY) && !element.name().equals(TagConstants.HTML))
348+
if (!TagConstants.BODY.equals(element.name()) && !TagConstants.HTML.equals(element.name()))
349349
runApplier(element, tagWorker);
350350
if (!context.getState().empty()) {
351351
PageBreakApplierUtil.addPageBreakElementBefore(context, context.getState().top(), element, tagWorker);

src/main/java/com/itextpdf/html2pdf/attach/impl/layout/HeightDimensionContainer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class HeightDimensionContainer extends DimensionContainer {
5656

5757
HeightDimensionContainer(CssContextNode pmbcNode, float width, float maxHeight, IRenderer renderer, float additionalWidthFix) {
5858
String height = pmbcNode.getStyles().get(CssConstants.HEIGHT);
59-
if (height != null && !height.equals(CssConstants.AUTO)) {
59+
if (height != null && !CssConstants.AUTO.equals(height)) {
6060
dimension = parseDimension(pmbcNode, height, maxHeight, additionalWidthFix);
6161
}
6262
minDimension = getMinHeight(pmbcNode, maxHeight, additionalWidthFix);

src/main/java/com/itextpdf/html2pdf/attach/impl/layout/HtmlDocumentRenderer.java

Lines changed: 74 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -191,22 +191,9 @@ public void addChild(IRenderer renderer) {
191191
*/
192192
@Override
193193
public void close() {
194-
if (waitingElement != null) {
195-
IRenderer r = this.waitingElement;
196-
waitingElement = null;
197-
super.addChild(r);
198-
}
194+
processWaitingElement();
199195
super.close();
200-
if (TRIM_LAST_BLANK_PAGE) {
201-
PdfDocument pdfDocument = document.getPdfDocument();
202-
if (pdfDocument.getNumberOfPages() > 1) {
203-
PdfPage lastPage = pdfDocument.getLastPage();
204-
if (lastPage.getContentStreamCount() == 1 && lastPage.getContentStream(0).getOutputStream().getCurrentPos() <= 0) {
205-
// Remove last empty page
206-
pdfDocument.removePage(pdfDocument.getNumberOfPages());
207-
}
208-
}
209-
}
196+
trimLastPageIfNecessary();
210197
document.getPdfDocument().removeEventHandler(PdfDocumentEvent.END_PAGE, handler);
211198
for (int i = 1; i <= document.getPdfDocument().getNumberOfPages(); ++i) {
212199
PdfPage page = document.getPdfDocument().getPage(i);
@@ -222,21 +209,76 @@ public void close() {
222209
@Override
223210
public IRenderer getNextRenderer() {
224211
// Process waiting element to get the correct number of pages
225-
if (waitingElement != null) {
226-
super.addChild(waitingElement);
227-
waitingElement = null;
228-
}
212+
processWaitingElement();
229213
HtmlDocumentRenderer relayoutRenderer = new HtmlDocumentRenderer(document, immediateFlush);
230214
PageSize defaultPageSize = document.getPdfDocument().getDefaultPageSize();
231215
float[] defaultPageMargins = {document.getTopMargin(), document.getRightMargin(), document.getBottomMargin(), document.getRightMargin()};
232216
relayoutRenderer.firstPageProc = firstPageProc.reset(defaultPageSize, defaultPageMargins);
233217
relayoutRenderer.leftPageProc = leftPageProc.reset(defaultPageSize, defaultPageMargins);
234218
relayoutRenderer.rightPageProc = rightPageProc.reset(defaultPageSize, defaultPageMargins);
235-
relayoutRenderer.estimatedNumberOfPages = currentPageNumber;
219+
relayoutRenderer.estimatedNumberOfPages = currentPageNumber - simulateTrimLastPage();
236220
relayoutRenderer.handler = handler.setHtmlDocumentRenderer(relayoutRenderer);
237221
return relayoutRenderer;
238222
}
239223

224+
@Override
225+
public void flush(){
226+
processWaitingElement();
227+
super.flush();
228+
}
229+
230+
void processWaitingElement(){
231+
if (waitingElement != null) {
232+
IRenderer r = this.waitingElement;
233+
waitingElement = null;
234+
super.addChild(r);
235+
}
236+
}
237+
238+
boolean shouldAttemptTrimLastPage() {
239+
return TRIM_LAST_BLANK_PAGE && document.getPdfDocument().getNumberOfPages() > 1;
240+
}
241+
242+
void trimLastPageIfNecessary() {
243+
if (shouldAttemptTrimLastPage()) {
244+
PdfDocument pdfDocument = document.getPdfDocument();
245+
PdfPage lastPage = pdfDocument.getLastPage();
246+
if (lastPage.getContentStreamCount() == 1 && lastPage.getContentStream(0).getOutputStream().getCurrentPos() <= 0) {
247+
// Remove last empty page
248+
pdfDocument.removePage(pdfDocument.getNumberOfPages());
249+
}
250+
}
251+
}
252+
253+
/**
254+
* Returns the number of pages that will be trimmed on {@link #close()}
255+
* @return 0 if no pages will be trimmed, or positive number of trimmed pages in case any are trimmed
256+
*/
257+
int simulateTrimLastPage() {
258+
if (shouldAttemptTrimLastPage()) {
259+
int lastPageNumber = document.getPdfDocument().getNumberOfPages();
260+
// At the moment we only check if some element was positioned on this page
261+
// However, there might theoretically be an inconsistency with the method that
262+
// actually does the trimming because that method checks the canvas output only.
263+
// We might want to simulate drawing on canvas here in the future, or possibly
264+
// consider invisible elements in the method that actually does the trimming
265+
boolean willAnyContentBeDrawnOnLastPage = false;
266+
for (IRenderer renderer : childRenderers) {
267+
if (renderer.getOccupiedArea().getPageNumber() == lastPageNumber) {
268+
willAnyContentBeDrawnOnLastPage = true;
269+
}
270+
}
271+
for (IRenderer renderer : positionedRenderers) {
272+
if (renderer.getOccupiedArea().getPageNumber() == lastPageNumber) {
273+
willAnyContentBeDrawnOnLastPage = true;
274+
}
275+
}
276+
return willAnyContentBeDrawnOnLastPage ? 0 : 1;
277+
} else {
278+
return 0;
279+
}
280+
}
281+
240282
/* (non-Javadoc)
241283
* @see com.itextpdf.layout.renderer.DocumentRenderer#updateCurrentArea(com.itextpdf.layout.layout.LayoutResult)
242284
*/
@@ -385,6 +427,18 @@ int getEstimatedNumberOfPages() {
385427
return estimatedNumberOfPages;
386428
}
387429

430+
private static boolean isRunningElementsOnly(IRenderer waitingElement) {
431+
boolean res;
432+
if (res = waitingElement instanceof ParagraphRenderer && !waitingElement.getChildRenderers().isEmpty()) {
433+
List<IRenderer> childRenderers = waitingElement.getChildRenderers();
434+
int i = 0;
435+
while (res && i < childRenderers.size()) {
436+
res = childRenderers.get(i++) instanceof RunningElement.RunningElementRenderer;
437+
}
438+
}
439+
return res;
440+
}
441+
388442
/**
389443
* Gets a page processor for the page.
390444
*
@@ -422,18 +476,6 @@ private boolean isPageRight(int pageNum) {
422476
return !isPageLeft(pageNum);
423477
}
424478

425-
private static boolean isRunningElementsOnly(IRenderer waitingElement) {
426-
boolean res;
427-
if (res = waitingElement instanceof ParagraphRenderer && !waitingElement.getChildRenderers().isEmpty()) {
428-
List<IRenderer> childRenderers = waitingElement.getChildRenderers();
429-
int i = 0;
430-
while (res && i < childRenderers.size()) {
431-
res = childRenderers.get(i++) instanceof RunningElement.RunningElementRenderer;
432-
}
433-
}
434-
return res;
435-
}
436-
437479
private static class PageMarginBoxesDrawingHandler implements IEventHandler {
438480
private HtmlDocumentRenderer htmlDocumentRenderer;
439481

src/main/java/com/itextpdf/html2pdf/attach/impl/layout/PageSizeParser.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,13 +119,15 @@ static PageSize fetchPageSize(String pageSizeStr, float em, float rem, PageSize
119119
}
120120
}
121121

122-
boolean b1 = pageSizeChunks.length == 1 && (namedPageSize != null || landscape != null);
123-
boolean b2 = namedPageSize != null && landscape != null;
124-
if (b1 || b2) {
122+
boolean isValidSingleWordDeclaration = pageSizeChunks.length == 1 && (namedPageSize != null || landscape != null);
123+
boolean isValidTwoWordDeclaration = namedPageSize != null && landscape != null;
124+
if (isValidSingleWordDeclaration || isValidTwoWordDeclaration) {
125125
if (namedPageSize != null) {
126126
pageSize = namedPageSize;
127127
}
128-
if (Boolean.TRUE.equals(landscape)) {
128+
boolean landscapeRequestedAndNeedRotation = Boolean.TRUE.equals(landscape) && pageSize.getWidth() < pageSize.getHeight();
129+
boolean portraitRequestedAndNeedRotation = Boolean.FALSE.equals(landscape) && pageSize.getHeight() < pageSize.getWidth();
130+
if (landscapeRequestedAndNeedRotation || portraitRequestedAndNeedRotation) {
129131
pageSize = pageSize.rotate();
130132
}
131133
} else {

0 commit comments

Comments
 (0)