Skip to content

Commit f9c8af0

Browse files
committed
[RELEASE] iText 7 pdfHTML - 3.0.3
https://github.com/itext/i7j-pdfhtml/releases/tag/3.0.3 * release/3.0.3: [RELEASE] pdfHTML 3.0.3 Remove fixed todo Fix wrong todos number Add support to utf-8 image format in svg Update cmp Support word-break property Update cmp-s Update cmp-s after span wrapping support Fix test accroding to new log message in case of problems with data image Add test for collaboration between radiobuttons and page-counter Update ToDo remarks Add missing copyright headers Add support of pages target-counter(s). Finalize whole target-counter logic Add missing copyright headers Implement non-page(s) target-counter(s) and fix counter bad perfomance Update cmp-s Support overflow-wrap Update CONTRIBUTING.md with latest information and links Divide the CssUtils class into several classes Remove "free" word from method name Get rid of using "LicenseKeyProductFeature" in ReflectionUtils class Add new test for descender/ascender calculations Add new test for absolute positioning Make mutable final sets unmodifable Add BatchConversionTest Add missing copyright headers Implement target-counter for page Link tests with the jira issue Fix body background size Add TODO references to the tests in com.itextpdf.html2pdf.css.w3c.css_backgrounds.bg_size.vector Test cmp update and new test added Add supporting SvgCssContext and add minor improvements Add new tests illustrating problem of text-decoration-color effect on nested elements Add test to show that negative paddings processed incorrectly Remove package-info.java Update ToDo remark in CssOpacityTest#innerOpacityTest [AFTER RELEASE] pdfHTML 3.0.2 Add some minor improvements to w3c tests
2 parents c702758 + 3f96313 commit f9c8af0

File tree

620 files changed

+13850
-979
lines changed

Some content is hidden

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

620 files changed

+13850
-979
lines changed

CONTRIBUTING.md

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,7 @@ Before you submit your pull request consider the following guidelines:
6868
* Verify that your proposed change hasn't already been addressed in the develop branch.
6969
* Don't send a separate pull request for every single file you change.
7070
* Please sign the [iText Contributor License Agreement (iCLA)](#cla) before sending pull
71-
requests for any change of more than 20 significant lines of code (we're not counting curly braces and other syntactical sugar).
72-
We cannot accept code without this agreement.
71+
requests. We cannot accept code without this agreement.
7372
* Fork the iText repository on GitHub.
7473
* Clone your iText fork to your local machine.
7574
* Make your changes, **including appropriate test cases**.
@@ -100,8 +99,7 @@ To ensure consistency throughout the source code, keep these rules in mind as yo
10099

101100
* We develop in Java first, and then port to .NET, so code submissions in Java are preferred.
102101
Nevertheless this shouldn't stop you from making a good pull request to the .NET port.
103-
* All Java code **must** be Java 7. Sorry, no lambda expressions or other Java 8 language features.
104-
* All features or bug fixes **must be tested** by one or more [unit tests][unit-testing].
102+
* All features or bug fixes **must be tested** by one or more unit tests.
105103
* All public API methods **must be documented** with JavaDoc. To see how we document our APIs, please check
106104
out the existing [javadocs][javadocs].
107105
* We follow the rules contained in
@@ -151,8 +149,7 @@ reference JIRA or GitHub issues that this commit **Closes**.
151149

152150
## <a name="cla">Signing the iCLA</a>
153151

154-
Please sign the **iText Contributor License Agreement (iCLA)** before sending pull requests. For any larger code
155-
changes (more than 20 lines of significant code) to be accepted, the iCLA must be signed. It's a quick process, we promise!
152+
Please sign the [**iText Contributor License Agreement (iCLA)**][cla] before sending pull requests. For any code changes to be accepted, the iCLA must be signed. It's a quick process, we promise!
156153

157154
We'll need you to [(digitally) sign and then email, fax or mail the form][cla].
158155

@@ -165,18 +162,17 @@ We use the [Stack Exchange][stackoverflow] network for free support and [GitHub]
165162
* StackExchange: [http://stackexchange.com/legal](http://stackexchange.com/legal)
166163
* Github: [https://help.github.com/articles/github-terms-of-service/](https://help.github.com/articles/github-terms-of-service/)
167164

168-
[cla]: http://itextpdf.com/policy
165+
[cla]: https://itextpdf.com/en/how-buy/legal/itext-contributor-license-agreement
169166
[coc]: CODE_OF_CONDUCT.md
170-
[github]: https://github.com/itext/itext7
171-
[java-style-guide]: http://www.oracle.com/technetwork/java/codeconvtoc-136057.html
172-
[javadocs]: http://itextpdf.com/api
173-
[pull]: https://github.com/itext/itext7/pulls
167+
[github]: https://github.com/itext/i7j-pdfhtml
168+
[java-style-guide]: https://www.oracle.com/technetwork/java/codeconvtoc-136057.html
169+
[javadocs]: https://itextpdf.com/api
170+
[pull]: https://github.com/itext/i7j-pdfhtml/pulls
174171
[sscce]: http://sscce.org/
175-
[stackoverflow]: http://stackoverflow.com/questions/tagged/itext7
176-
[good-questions]: http://stackoverflow.com/help/how-to-ask
177-
[mcve]: http://stackoverflow.com/help/mcve
178-
[support]: http://itextpdf.com/support
179-
[unit-testing]: http://junit.org/
172+
[stackoverflow]: https://stackoverflow.com/questions/tagged/itext7
173+
[good-questions]: https://stackoverflow.com/help/how-to-ask
174+
[mcve]: https://stackoverflow.com/help/mcve
175+
[support]: https://itextpdf.com/support
180176
[git-commit]: https://chris.beams.io/posts/git-commit/
181177
[git-commit-separate]: https://chris.beams.io/posts/git-commit/#separate
182178
[git-commit-limit-50]: https://chris.beams.io/posts/git-commit/#limit-50

pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
<parent>
66
<groupId>com.itextpdf</groupId>
77
<artifactId>root</artifactId>
8-
<version>7.1.13</version>
9-
<relativePath/>
8+
<version>7.1.14</version>
9+
<relativePath />
1010
</parent>
1111

1212
<artifactId>html2pdf</artifactId>
13-
<version>3.0.2</version>
13+
<version>3.0.3</version>
1414

1515
<name>pdfHTML</name>
1616
<description>pdfHTML is an iText 7 add-on that lets you to parse (X)HTML snippets and the associated CSS and converts

src/main/java/com/itextpdf/html2pdf/ConverterProperties.java

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ This file is part of the iText (R) project.
5656
*/
5757
public class ConverterProperties {
5858

59+
/**
60+
* Default maximum number of layouts.
61+
*/
62+
private static final int DEFAULT_LIMIT_OF_LAYOUTS = 10;
63+
5964
/**
6065
* The media device description.
6166
*/
@@ -103,11 +108,16 @@ public class ConverterProperties {
103108

104109
/**
105110
* Indicates whether the document should be opened in immediate flush or not
106-
**/
111+
*/
107112
private boolean immediateFlush = true;
108113

109114
/**
110-
* Meta info that will be added to the events thrown by html2Pdf
115+
* Maximum number of layouts.
116+
*/
117+
private int limitOfLayouts = DEFAULT_LIMIT_OF_LAYOUTS;
118+
119+
/**
120+
* Meta info that will be added to the events thrown by html2Pdf.
111121
*/
112122
private IMetaInfo metaInfo;
113123

@@ -134,6 +144,7 @@ public ConverterProperties(ConverterProperties other) {
134144
this.outlineHandler = other.outlineHandler;
135145
this.charset = other.charset;
136146
this.metaInfo = other.metaInfo;
147+
this.limitOfLayouts = other.limitOfLayouts;
137148
}
138149

139150
/**
@@ -190,6 +201,26 @@ public ConverterProperties setFontProvider(FontProvider fontProvider) {
190201
return this;
191202
}
192203

204+
/**
205+
* Gets maximum number of layouts.
206+
*
207+
* @return layouts limit
208+
*/
209+
public int getLimitOfLayouts() {
210+
return limitOfLayouts;
211+
}
212+
213+
/**
214+
* Sets maximum number of layouts.
215+
*
216+
* @param limitOfLayouts layouts limit
217+
* @return the {@link ConverterProperties} instance
218+
*/
219+
public ConverterProperties setLimitOfLayouts(int limitOfLayouts) {
220+
this.limitOfLayouts = limitOfLayouts;
221+
return this;
222+
}
223+
193224
/**
194225
* Gets the TagWorkerFactory instance.
195226
* <p>

src/main/java/com/itextpdf/html2pdf/LogMessageConstant.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,14 @@ public final class LogMessageConstant {
5050
/** The Constant ACROFORM_NOT_SUPPORTED_FOR_SELECT. */
5151
public static final String ACROFORM_NOT_SUPPORTED_FOR_SELECT = "AcroForm fields creation for select fields (ComboBoxField and ListBoxField) is not supported. They will be flattened instead.";
5252
public static final String ANCHOR_LINK_NOT_HANDLED = "The anchor link was not handled. Could not create a destination for element \"{0}\" with ID \"{1}\", which is processed by \"{2}\" tag worker class.";
53+
/** The Constant CANNOT_RESOLVE_TARGET_COUNTER_VALUE. */
54+
public static final String CANNOT_RESOLVE_TARGET_COUNTER_VALUE
55+
= "Cannot resolve target-counter value with given target \"{0}\"";
5356
/** The Constant CONTENT_PROPERTY_INVALID. */
5457
public static final String CONTENT_PROPERTY_INVALID = "Content property \"{0}\" is either invalid or uses unsupported function.";
58+
/** The Constant CUSTOM_RENDERER_IS_SET_FOR_HTML_DOCUMENT. */
59+
public static final String CUSTOM_RENDERER_IS_SET_FOR_HTML_DOCUMENT = "A custom renderer which doesn't extend " +
60+
"HtmlDocumentRenderer is set for HtmlDocument. Counters and target-counters may be displayed incorrectly.";
5561
/** The Constant CSS_PROPERTY_IN_PERCENTS_NOT_SUPPORTED. */
5662
public static final String CSS_PROPERTY_IN_PERCENTS_NOT_SUPPORTED = "Css property {0} in percents is not supported";
5763
public static final String DEFAULT_VALUE_OF_CSS_PROPERTY_UNKNOWN = "Default value of the css property \"{0}\" is unknown.";
@@ -65,6 +71,10 @@ public final class LogMessageConstant {
6571
public static final String ERROR_WHILE_LAYOUT_OF_FORM_FIELD = "Cannot layout form field field. It won't be displayed";
6672
/** The Constant ERROR_WHILE_LAYOUT_OF_FORM_FIELD_WITH_TYPE. */
6773
public static final String ERROR_WHILE_LAYOUT_OF_FORM_FIELD_WITH_TYPE = "Error during layout of form filed with type {0}.";
74+
/** The Constant EXCEEDED_THE_MAXIMUM_NUMBER_OF_RELAYOUTS. */
75+
public static final String EXCEEDED_THE_MAXIMUM_NUMBER_OF_RELAYOUTS = "Exceeded the maximum number of relayouts. " +
76+
"The resultant document may look not as expected. " +
77+
"Because of the content being dynamic iText performs several relayouts to produce correct document.";
6878
/** The Constant INPUT_FIELD_DOES_NOT_FIT. */
6979
public static final String INPUT_FIELD_DOES_NOT_FIT = "Input field doesn't fit in outer object. It will be clipped";
7080
/** The Constant INPUT_TYPE_IS_INVALID. */

src/main/java/com/itextpdf/html2pdf/attach/ProcessorContext.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@ public class ProcessorContext {
160160
*/
161161
private boolean processingInlineSvg;
162162

163+
private final int limitOfLayouts;
164+
163165
/**
164166
* Instantiates a new {@link ProcessorContext} instance.
165167
*
@@ -203,6 +205,7 @@ public ProcessorContext(ConverterProperties converterProperties) {
203205

204206
resourceResolver = new HtmlResourceResolver(baseUri, this, converterProperties.getResourceRetriever());
205207

208+
limitOfLayouts = converterProperties.getLimitOfLayouts();
206209
cssContext = new CssContext();
207210
linkContext = new LinkContext();
208211

@@ -214,6 +217,15 @@ public ProcessorContext(ConverterProperties converterProperties) {
214217
processingInlineSvg = false;
215218
}
216219

220+
/**
221+
* Gets maximum number of layouts.
222+
*
223+
* @return layouts limit
224+
*/
225+
public int getLimitOfLayouts() {
226+
return limitOfLayouts;
227+
}
228+
217229
/**
218230
* Sets the font provider.
219231
*

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

Lines changed: 63 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ This file is part of the iText (R) project.
4747
import com.itextpdf.html2pdf.attach.IHtmlProcessor;
4848
import com.itextpdf.html2pdf.attach.ITagWorker;
4949
import com.itextpdf.html2pdf.attach.ProcessorContext;
50+
import com.itextpdf.html2pdf.attach.impl.layout.HtmlDocument;
5051
import com.itextpdf.html2pdf.attach.impl.layout.HtmlDocumentRenderer;
5152
import com.itextpdf.html2pdf.attach.impl.layout.RunningElementContainer;
5253
import com.itextpdf.html2pdf.attach.impl.layout.form.element.IPlaceholderable;
@@ -55,6 +56,7 @@ This file is part of the iText (R) project.
5556
import com.itextpdf.html2pdf.attach.util.LinkHelper;
5657
import com.itextpdf.html2pdf.css.CssConstants;
5758
import com.itextpdf.html2pdf.css.apply.ICssApplier;
59+
import com.itextpdf.html2pdf.css.apply.util.CounterProcessorUtil;
5860
import com.itextpdf.html2pdf.css.apply.util.PageBreakApplierUtil;
5961
import com.itextpdf.html2pdf.css.resolve.DefaultCssResolver;
6062
import com.itextpdf.html2pdf.events.PdfHtmlEvent;
@@ -75,6 +77,7 @@ This file is part of the iText (R) project.
7577
import com.itextpdf.layout.font.Range;
7678
import com.itextpdf.layout.property.Property;
7779
import com.itextpdf.layout.property.RenderingMode;
80+
import com.itextpdf.layout.renderer.DocumentRenderer;
7881
import com.itextpdf.styledxmlparser.css.CssDeclaration;
7982
import com.itextpdf.styledxmlparser.css.font.CssFontFace;
8083
import com.itextpdf.styledxmlparser.css.CssFontFaceRule;
@@ -241,18 +244,59 @@ public Document processDocument(INode root, PdfDocument pdfDocument) {
241244
addFontFaceFonts();
242245
root = findHtmlNode(root);
243246

247+
if (context.getCssContext().isNonPagesTargetCounterPresent()) {
248+
visitToProcessCounters(root);
249+
context.getCssContext().getCounterManager().clearManager();
250+
}
244251
visit(root);
245-
Document doc = (Document) roots.get(0);
252+
HtmlDocument doc = (HtmlDocument) roots.get(0);
246253
// TODO DEVSIX-4261 more precise check if a counter was actually added to the document
247-
if (context.getCssContext().isPagesCounterPresent() && doc.getRenderer() instanceof HtmlDocumentRenderer) {
248-
doc.relayout();
254+
if (context.getCssContext().isPagesCounterPresent()) {
255+
if (doc.getRenderer() instanceof HtmlDocumentRenderer) {
256+
((HtmlDocumentRenderer) doc.getRenderer()).processWaitingElement();
257+
int counter = 0;
258+
do {
259+
++counter;
260+
doc.relayout();
261+
if (counter >= context.getLimitOfLayouts()) {
262+
logger.warn(
263+
MessageFormatUtil.format(LogMessageConstant.EXCEEDED_THE_MAXIMUM_NUMBER_OF_RELAYOUTS));
264+
break;
265+
}
266+
} while (((DocumentRenderer) doc.getRenderer()).isRelayoutRequired());
267+
} else {
268+
logger.warn(LogMessageConstant.CUSTOM_RENDERER_IS_SET_FOR_HTML_DOCUMENT);
269+
}
249270
}
250271
cssResolver = null;
251272
roots = null;
252273
EventCounterHandler.getInstance().onEvent(PdfHtmlEvent.CONVERT, context.getEventCountingMetaInfo(), getClass());
253274
return doc;
254275
}
255276

277+
/**
278+
* Recursively processes a node to preprocess target-counters.
279+
*
280+
* @param node the node
281+
*/
282+
private void visitToProcessCounters(INode node) {
283+
if (node instanceof IElementNode) {
284+
final IElementNode element = (IElementNode) node;
285+
if (cssResolver instanceof DefaultCssResolver) {
286+
((DefaultCssResolver) cssResolver).resolveContentAndCountersStyles(node, context.getCssContext());
287+
}
288+
CounterProcessorUtil.startProcessingCounters(context.getCssContext(), element);
289+
visitToProcessCounters(createPseudoElement(element, null, CssConstants.BEFORE));
290+
for (final INode childNode : element.childNodes()) {
291+
if (!context.isProcessingInlineSvg()) {
292+
visitToProcessCounters(childNode);
293+
}
294+
}
295+
visitToProcessCounters(createPseudoElement(element, null, CssConstants.AFTER));
296+
CounterProcessorUtil.endProcessingCounters(context.getCssContext(), element);
297+
}
298+
}
299+
256300
/**
257301
* Recursively processes a node converting HTML into PDF using tag workers.
258302
*
@@ -284,23 +328,26 @@ private void visit(INode node) {
284328

285329
context.getOutlineHandler().addOutlineAndDestToDocument(tagWorker, element, context);
286330

287-
visitPseudoElement(element, tagWorker, CssConstants.BEFORE);
288-
visitPseudoElement(element, tagWorker, CssConstants.PLACEHOLDER);
331+
CounterProcessorUtil.startProcessingCounters(context.getCssContext(), element);
332+
visit(createPseudoElement(element, tagWorker, CssConstants.BEFORE));
333+
visit(createPseudoElement(element, tagWorker, CssConstants.PLACEHOLDER));
289334
for (INode childNode : element.childNodes()) {
290335
if (!context.isProcessingInlineSvg()) {
291336
visit(childNode);
292337
}
293338
}
294-
visitPseudoElement(element, tagWorker, CssConstants.AFTER);
339+
visit(createPseudoElement(element, tagWorker, CssConstants.AFTER));
340+
CounterProcessorUtil.endProcessingCounters(context.getCssContext(), element);
295341

296342
if (tagWorker != null) {
297343
tagWorker.processEnd(element, context);
298344
LinkHelper.createDestination(tagWorker, element, context);
299345
context.getOutlineHandler().setDestinationToElement(tagWorker, element);
300346
context.getState().pop();
301347

302-
if (!TagConstants.BODY.equals(element.name()) && !TagConstants.HTML.equals(element.name()))
348+
if (!TagConstants.BODY.equals(element.name()) && !TagConstants.HTML.equals(element.name())) {
303349
runApplier(element, tagWorker);
350+
}
304351
if (!context.getState().empty()) {
305352
PageBreakApplierUtil.addPageBreakElementBefore(context, context.getState().top(), element, tagWorker);
306353
tagWorker = processRunningElement(tagWorker, element, context);
@@ -445,31 +492,34 @@ private boolean createFont(String fontFamily, CssFontFace.CssFontFaceSrc src, Ra
445492
}
446493

447494
/**
448-
* Processes a pseudo element (before and after CSS).
495+
* Creates a pseudo element (before and after CSS).
449496
*
450497
* @param node the node
498+
* @param tagWorker the tagWorker
451499
* @param pseudoElementName the pseudo element name
500+
* @return created pseudo element
452501
*/
453-
private void visitPseudoElement(IElementNode node, ITagWorker tagWorker, String pseudoElementName) {
502+
private static CssPseudoElementNode createPseudoElement(IElementNode node,
503+
ITagWorker tagWorker, String pseudoElementName) {
454504
switch (pseudoElementName) {
455505
case CssConstants.BEFORE:
456506
case CssConstants.AFTER:
457507
if (!CssPseudoElementUtil.hasBeforeAfterElements(node)) {
458-
return;
508+
return null;
459509
}
460510
break;
461511
case CssConstants.PLACEHOLDER:
462512
if (!(TagConstants.INPUT.equals(node.name()) || TagConstants.TEXTAREA.equals(node.name())) || // TODO DEVSIX-1944: Resolve the issue and remove the line
463513
null == tagWorker
464514
|| !(tagWorker.getElementResult() instanceof IPlaceholderable)
465515
|| null == ((IPlaceholderable) tagWorker.getElementResult()).getPlaceholder()) {
466-
return;
516+
return null;
467517
}
468518
break;
469519
default:
470-
return;
520+
return null;
471521
}
472-
visit(new CssPseudoElementNode(node, pseudoElementName));
522+
return new CssPseudoElementNode(node, pseudoElementName);
473523
}
474524

475525
/**

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,9 @@ This file is part of the iText (R) project.
4343
package com.itextpdf.html2pdf.attach.impl.layout;
4444

4545
import com.itextpdf.html2pdf.css.CssConstants;
46-
import com.itextpdf.html2pdf.css.apply.util.FontStyleApplierUtil;
4746
import com.itextpdf.layout.property.UnitValue;
4847
import com.itextpdf.styledxmlparser.css.CssContextNode;
49-
import com.itextpdf.styledxmlparser.css.util.CssUtils;
48+
import com.itextpdf.styledxmlparser.css.util.CssDimensionParsingUtils;
5049

5150
/**
5251
* Container class for grouping necessary values used in dimension calculation
@@ -73,8 +72,8 @@ boolean isAutoDimension() {
7372
}
7473

7574
float parseDimension(CssContextNode node, String content, float maxAvailableDimension, float additionalWidthFix) {
76-
float fontSize = CssUtils.parseAbsoluteFontSize(node.getStyles().get(CssConstants.FONT_SIZE));
77-
UnitValue unitValue = CssUtils.parseLengthValueToPt(content, fontSize, 0);
75+
float fontSize = CssDimensionParsingUtils.parseAbsoluteFontSize(node.getStyles().get(CssConstants.FONT_SIZE));
76+
UnitValue unitValue = CssDimensionParsingUtils.parseLengthValueToPt(content, fontSize, 0);
7877
if (unitValue == null) {
7978
return 0;
8079
}

0 commit comments

Comments
 (0)