diff --git a/barcodes/pom.xml b/barcodes/pom.xml index f18864b69c..e1aa2840f0 100644 --- a/barcodes/pom.xml +++ b/barcodes/pom.xml @@ -4,7 +4,7 @@ com.itextpdf root - 7.2.0 + 7.2.1 barcodes iText 7 - barcodes diff --git a/barcodes/src/test/java/com/itextpdf/barcodes/BarcodePDF417Test.java b/barcodes/src/test/java/com/itextpdf/barcodes/BarcodePDF417Test.java index 4e57c2466f..7ecab0e0a9 100644 --- a/barcodes/src/test/java/com/itextpdf/barcodes/BarcodePDF417Test.java +++ b/barcodes/src/test/java/com/itextpdf/barcodes/BarcodePDF417Test.java @@ -238,7 +238,7 @@ public void barcode417XObjectTest() throws IOException, InterruptedException { barcode.setCode(text); PdfFormXObject xObject = barcode.createFormXObject(document); - canvas.addXObject(xObject, 10, 650); + canvas.addXObjectAt(xObject, 10, 650); document.close(); diff --git a/commons/pom.xml b/commons/pom.xml index b6b98f2c2a..787ccd8470 100644 --- a/commons/pom.xml +++ b/commons/pom.xml @@ -4,7 +4,7 @@ com.itextpdf root - 7.2.0 + 7.2.1 commons iText 7 - commons diff --git a/commons/src/main/java/com/itextpdf/commons/actions/ProductEventHandler.java b/commons/src/main/java/com/itextpdf/commons/actions/ProductEventHandler.java index 2e35486bee..51c7cf5791 100644 --- a/commons/src/main/java/com/itextpdf/commons/actions/ProductEventHandler.java +++ b/commons/src/main/java/com/itextpdf/commons/actions/ProductEventHandler.java @@ -25,11 +25,12 @@ This file is part of the iText (R) project. import com.itextpdf.commons.actions.confirmations.ConfirmEvent; import com.itextpdf.commons.actions.confirmations.ConfirmedEventWrapper; import com.itextpdf.commons.actions.contexts.UnknownContext; -import com.itextpdf.commons.exceptions.UnknownProductException; -import com.itextpdf.commons.logs.CommonsLogMessageConstant; import com.itextpdf.commons.actions.processors.DefaultITextProductEventProcessor; import com.itextpdf.commons.actions.processors.ITextProductEventProcessor; import com.itextpdf.commons.actions.sequence.SequenceId; +import com.itextpdf.commons.exceptions.ProductEventHandlerRepeatException; +import com.itextpdf.commons.exceptions.UnknownProductException; +import com.itextpdf.commons.logs.CommonsLogMessageConstant; import com.itextpdf.commons.utils.MessageFormatUtil; import java.util.ArrayList; @@ -47,7 +48,11 @@ This file is part of the iText (R) project. */ final class ProductEventHandler extends AbstractContextBasedEventHandler { static final ProductEventHandler INSTANCE = new ProductEventHandler(); + private static final Logger LOGGER = LoggerFactory.getLogger(ProductEventHandler.class); + // The constant has the following value for two reasons. First, to avoid the infinite loop. + // Second, to retry event processing several times for technical reasons. + private static final int MAX_EVENT_RETRY_COUNT = 4; private final ConcurrentHashMap processors = new ConcurrentHashMap<>(); private final WeakHashMap> events = new WeakHashMap<>(); @@ -63,24 +68,17 @@ private ProductEventHandler() { */ @Override protected void onAcceptedEvent(AbstractContextBasedITextEvent event) { - if (! (event instanceof AbstractProductProcessITextEvent)) { - return; - } - final AbstractProductProcessITextEvent productEvent = (AbstractProductProcessITextEvent) event; - final String productName = productEvent.getProductName(); - final ITextProductEventProcessor productEventProcessor = getActiveProcessor(productName); - if (productEventProcessor == null) { - throw new UnknownProductException( - MessageFormatUtil.format(UnknownProductException.UNKNOWN_PRODUCT, productName)); - } - productEventProcessor.onEvent(productEvent); - if (productEvent.getSequenceId() != null) { - if (productEvent instanceof ConfirmEvent) { - wrapConfirmedEvent((ConfirmEvent) productEvent, productEventProcessor); - } else { - addEvent(productEvent.getSequenceId(), productEvent); + for (int i = 0; i < MAX_EVENT_RETRY_COUNT; i++) { + try { + tryProcessEvent(event); + // process succeeded + return; + } catch (ProductEventHandlerRepeatException repeatException) { + // ignore this exception to retry the processing } } + // the final processing retry + tryProcessEvent(event); } ITextProductEventProcessor addProcessor(ITextProductEventProcessor processor) { @@ -138,6 +136,29 @@ void addEvent(SequenceId id, AbstractProductProcessITextEvent event) { } } + private void tryProcessEvent(AbstractContextBasedITextEvent event) { + if (! (event instanceof AbstractProductProcessITextEvent)) { + return; + } + final AbstractProductProcessITextEvent productEvent = (AbstractProductProcessITextEvent) event; + final String productName = productEvent.getProductName(); + final ITextProductEventProcessor productEventProcessor = getActiveProcessor(productName); + if (productEventProcessor == null) { + throw new UnknownProductException( + MessageFormatUtil.format(UnknownProductException.UNKNOWN_PRODUCT, productName)); + } + + productEventProcessor.onEvent(productEvent); + + if (productEvent.getSequenceId() != null) { + if (productEvent instanceof ConfirmEvent) { + wrapConfirmedEvent((ConfirmEvent) productEvent, productEventProcessor); + } else { + addEvent(productEvent.getSequenceId(), productEvent); + } + } + } + private void wrapConfirmedEvent(ConfirmEvent event, ITextProductEventProcessor productEventProcessor) { synchronized (events) { final List eventsList = events.get(event.getSequenceId()); diff --git a/commons/src/main/java/com/itextpdf/commons/actions/data/CommonsProductData.java b/commons/src/main/java/com/itextpdf/commons/actions/data/CommonsProductData.java index d921506e8d..13d4acf417 100644 --- a/commons/src/main/java/com/itextpdf/commons/actions/data/CommonsProductData.java +++ b/commons/src/main/java/com/itextpdf/commons/actions/data/CommonsProductData.java @@ -28,7 +28,7 @@ This file is part of the iText (R) project. public final class CommonsProductData { static final String COMMONS_PUBLIC_PRODUCT_NAME = "Commons"; static final String COMMONS_PRODUCT_NAME = "commons"; - static final String COMMONS_VERSION = "7.2.0"; + static final String COMMONS_VERSION = "7.2.1"; static final int COMMONS_COPYRIGHT_SINCE = 2000; static final int COMMONS_COPYRIGHT_TO = 2021; diff --git a/commons/src/main/java/com/itextpdf/commons/actions/data/ProductData.java b/commons/src/main/java/com/itextpdf/commons/actions/data/ProductData.java index 9ac5373645..fccda50c2e 100644 --- a/commons/src/main/java/com/itextpdf/commons/actions/data/ProductData.java +++ b/commons/src/main/java/com/itextpdf/commons/actions/data/ProductData.java @@ -31,6 +31,7 @@ public final class ProductData { private final String publicProductName; private final String productName; private final String version; + private final String minimalCompatibleLicenseKeyVersion; private final int sinceCopyrightYear; private final int toCopyrightYear; @@ -45,9 +46,25 @@ public final class ProductData { */ public ProductData(String publicProductName, String productName, String version, int sinceCopyrightYear, int toCopyrightYear) { + this(publicProductName, productName, version, null, sinceCopyrightYear, toCopyrightYear); + } + + /** + * Creates a new instance of product data. + * + * @param publicProductName is a product name + * @param productName is a technical name of the product + * @param version is a version of the product + * @param minimalCompatibleLicenseKeyVersion is a minimal compatible version of licensekey library + * @param sinceCopyrightYear is the first year of a product development + * @param toCopyrightYear is a last year of a product development + */ + public ProductData(String publicProductName, String productName, String version, + String minimalCompatibleLicenseKeyVersion, int sinceCopyrightYear, int toCopyrightYear) { this.publicProductName = publicProductName; this.productName = productName; this.version = version; + this.minimalCompatibleLicenseKeyVersion = minimalCompatibleLicenseKeyVersion; this.sinceCopyrightYear = sinceCopyrightYear; this.toCopyrightYear = toCopyrightYear; } @@ -97,6 +114,15 @@ public int getToCopyrightYear() { return toCopyrightYear; } + /** + * Getter for the minimal compatible licensekey version. + * + * @return minimal compatible version of licensekey library. + */ + public String getMinCompatibleLicensingModuleVersion() { + return minimalCompatibleLicenseKeyVersion; + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/commons/src/main/java/com/itextpdf/commons/actions/processors/DefaultITextProductEventProcessor.java b/commons/src/main/java/com/itextpdf/commons/actions/processors/DefaultITextProductEventProcessor.java index 963489735f..0186684465 100644 --- a/commons/src/main/java/com/itextpdf/commons/actions/processors/DefaultITextProductEventProcessor.java +++ b/commons/src/main/java/com/itextpdf/commons/actions/processors/DefaultITextProductEventProcessor.java @@ -96,6 +96,7 @@ public void onEvent(AbstractProductProcessITextEvent event) { if (isNeededToLogMessage) { String message = new String(MESSAGE_FOR_LOGGING, StandardCharsets.ISO_8859_1); LOGGER.info(message); + // System out added with purpose. This is not a debug code System.out.println(message); } } diff --git a/commons/src/main/java/com/itextpdf/commons/exceptions/ProductEventHandlerRepeatException.java b/commons/src/main/java/com/itextpdf/commons/exceptions/ProductEventHandlerRepeatException.java new file mode 100644 index 0000000000..781c761abd --- /dev/null +++ b/commons/src/main/java/com/itextpdf/commons/exceptions/ProductEventHandlerRepeatException.java @@ -0,0 +1,37 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2021 iText Group NV + Authors: iText Software. + + This program is offered under a commercial and under the AGPL license. + For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + + AGPL licensing: + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +package com.itextpdf.commons.exceptions; + +/** + * The class represents a signal to the event handler that it is necessary to repeat the handling of the current event. + */ +public final class ProductEventHandlerRepeatException extends ITextException { + /** + * Creates a new instance of {@link ProductEventHandlerRepeatException} based on message. + * + * @param message the detail message + */ + public ProductEventHandlerRepeatException(String message) { + super(message); + } +} diff --git a/commons/src/main/java/com/itextpdf/commons/utils/DateTimeUtil.java b/commons/src/main/java/com/itextpdf/commons/utils/DateTimeUtil.java index 42f6939314..04c87f94cc 100644 --- a/commons/src/main/java/com/itextpdf/commons/utils/DateTimeUtil.java +++ b/commons/src/main/java/com/itextpdf/commons/utils/DateTimeUtil.java @@ -49,6 +49,7 @@ This file is part of the iText (R) project. import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; +import java.util.TimeZone; /** * This file is a helper class for internal usage only. @@ -146,6 +147,11 @@ public static String format(Date date, String pattern) { return initParserSDF(pattern).format(date); } + public static long getCurrentTimeZoneOffset() { + TimeZone tz = TimeZone.getDefault(); + return tz.getOffset(getCurrentTimeDate().getTime()); + } + private static DateFormat initParserSDF(String pattern) { final SimpleDateFormat parserSDF = new SimpleDateFormat(pattern); parserSDF.setCalendar(new GregorianCalendar()); diff --git a/commons/src/main/java/com/itextpdf/commons/utils/ProcessInfo.java b/commons/src/main/java/com/itextpdf/commons/utils/ProcessInfo.java new file mode 100644 index 0000000000..d86867ca1d --- /dev/null +++ b/commons/src/main/java/com/itextpdf/commons/utils/ProcessInfo.java @@ -0,0 +1,74 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2021 iText Group NV + Authors: iText Software. + + This program is offered under a commercial and under the AGPL license. + For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + + AGPL licensing: + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +package com.itextpdf.commons.utils; + +/** + * Class contains a process information, such as process exit code and process output. + */ +public final class ProcessInfo { + + private final int exitCode; + private final String processStdOutput; + private final String processErrOutput; + + /** + * Create a new instance, containing a process information, + * such as process exit code, process standard and error outputs. + * + * @param exitCode exit code of the process. + * @param processStdOutput the standard output of the process. + * @param processErrOutput the error output of the process. + */ + public ProcessInfo(int exitCode, String processStdOutput, String processErrOutput) { + this.exitCode = exitCode; + this.processStdOutput = processStdOutput; + this.processErrOutput = processErrOutput; + } + + /** + * Getter for a process exit code. + * + * @return Returns a process exit code. + */ + public int getExitCode() { + return exitCode; + } + + /** + * Getter for a standard process output. + * + * @return Returns a process standard output string. + */ + public String getProcessStdOutput() { + return processStdOutput; + } + + /** + * Getter for an error process output. + * + * @return Returns a process error output string. + */ + public String getProcessErrOutput() { + return processErrOutput; + } +} diff --git a/commons/src/main/java/com/itextpdf/commons/utils/SystemUtil.java b/commons/src/main/java/com/itextpdf/commons/utils/SystemUtil.java index 84fb04b518..616973f067 100644 --- a/commons/src/main/java/com/itextpdf/commons/utils/SystemUtil.java +++ b/commons/src/main/java/com/itextpdf/commons/utils/SystemUtil.java @@ -45,6 +45,7 @@ This file is part of the iText (R) project. import java.io.BufferedReader; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collections; @@ -130,6 +131,14 @@ public static StringBuilder runProcessAndCollectErrors(String execPath, String p return printProcessErrorsOutput(runProcess(execPath, params, null)); } + public static ProcessInfo runProcessAndGetProcessInfo(String command, String params) throws IOException, + InterruptedException { + Process p = runProcess(command, params, null); + String processStdOutput = printProcessStandardOutput(p).toString(); + String processErrOutput = printProcessErrorsOutput(p).toString(); + return new ProcessInfo(p.waitFor(), processStdOutput, processErrOutput); + } + static Process runProcess(String execPath, String params, String workingDirPath) throws IOException { List cmdList = prepareProcessArguments(execPath, params); String[] cmdArray = cmdList.toArray(new String[0]); @@ -181,8 +190,16 @@ static String getProcessOutput(Process p) throws IOException { } static StringBuilder printProcessErrorsOutput(Process p) throws IOException { + return printProcessOutput(p.getErrorStream()); + } + + static StringBuilder printProcessStandardOutput(Process p) throws IOException { + return printProcessOutput(p.getInputStream()); + } + + private static StringBuilder printProcessOutput(InputStream processStream) throws IOException { StringBuilder builder = new StringBuilder(); - BufferedReader bre = new BufferedReader(new InputStreamReader(p.getErrorStream())); + BufferedReader bre = new BufferedReader(new InputStreamReader(processStream)); String line; while ((line = bre.readLine()) != null) { System.out.println(line); diff --git a/commons/src/test/java/com/itextpdf/commons/actions/ProductEventHandlerTest.java b/commons/src/test/java/com/itextpdf/commons/actions/ProductEventHandlerTest.java index 32c09a84b3..035b7dc094 100644 --- a/commons/src/test/java/com/itextpdf/commons/actions/ProductEventHandlerTest.java +++ b/commons/src/test/java/com/itextpdf/commons/actions/ProductEventHandlerTest.java @@ -24,34 +24,37 @@ This file is part of the iText (R) project. import com.itextpdf.commons.actions.confirmations.ConfirmEvent; import com.itextpdf.commons.actions.confirmations.ConfirmedEventWrapper; +import com.itextpdf.commons.actions.processors.ITextProductEventProcessor; import com.itextpdf.commons.actions.sequence.SequenceId; import com.itextpdf.commons.ecosystem.ITextTestEvent; +import com.itextpdf.commons.exceptions.ProductEventHandlerRepeatException; import com.itextpdf.commons.exceptions.UnknownProductException; import com.itextpdf.commons.utils.MessageFormatUtil; +import com.itextpdf.test.AssertUtil; import com.itextpdf.test.ExtendedITextTest; import com.itextpdf.test.annotations.type.UnitTest; import org.junit.Assert; -import org.junit.Rule; +import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; @Category(UnitTest.class) public class ProductEventHandlerTest extends ExtendedITextTest { - @Rule - public ExpectedException junitExpectedException = ExpectedException.none(); + @Before + public void clearProcessors() { + ProductEventHandler.INSTANCE.clearProcessors(); + } @Test public void unknownProductTest() { ProductEventHandler handler = ProductEventHandler.INSTANCE; - junitExpectedException.expect(UnknownProductException.class); - junitExpectedException.expectMessage( - MessageFormatUtil.format(UnknownProductException.UNKNOWN_PRODUCT, "Unknown Product")); - - handler.onAcceptedEvent(new ITextTestEvent(new SequenceId(), null, "test-event", - "Unknown Product")); + AbstractContextBasedITextEvent event = new ITextTestEvent(new SequenceId(), null, "test-event", "Unknown Product"); + Exception ex = Assert.assertThrows(UnknownProductException.class, + () -> handler.onAcceptedEvent(event)); + Assert.assertEquals(MessageFormatUtil.format(UnknownProductException.UNKNOWN_PRODUCT, "Unknown Product"), + ex.getMessage()); } @Test @@ -114,4 +117,75 @@ public void confirmEventTest() { Assert.assertTrue(handler.getEvents(sequenceId).get(0) instanceof ConfirmedEventWrapper); Assert.assertEquals(event, ((ConfirmedEventWrapper) handler.getEvents(sequenceId).get(0)).getEvent()); } + + @Test + public void repeatEventHandlingWithFiveExceptionOnProcessingTest() { + ProductEventHandler handler = ProductEventHandler.INSTANCE; + + handler.addProcessor(new RepeatEventProcessor(5)); + + AbstractContextBasedITextEvent event = new ITextTestEvent(new SequenceId(), null, "test", + ProductNameConstant.ITEXT_CORE); + + Exception e = Assert.assertThrows(ProductEventHandlerRepeatException.class, + () -> handler.onAcceptedEvent(event)); + Assert.assertEquals("customMessage5", e.getMessage()); + } + + @Test + public void repeatEventHandlingWithFourExceptionOnProcessingTest() { + ProductEventHandler handler = ProductEventHandler.INSTANCE; + + handler.addProcessor(new RepeatEventProcessor(4)); + + AbstractContextBasedITextEvent event = new ITextTestEvent(new SequenceId(), null, "test", + ProductNameConstant.ITEXT_CORE); + + AssertUtil.doesNotThrow(() -> handler.onAcceptedEvent(event)); + } + + @Test + public void repeatEventHandlingWithOneExceptionOnProcessingTest() { + ProductEventHandler handler = ProductEventHandler.INSTANCE; + + handler.addProcessor(new RepeatEventProcessor(1)); + + AbstractContextBasedITextEvent event = new ITextTestEvent(new SequenceId(), null, "test", + ProductNameConstant.ITEXT_CORE); + + AssertUtil.doesNotThrow(() -> handler.onAcceptedEvent(event)); + } + + private static class RepeatEventProcessor implements ITextProductEventProcessor { + private final int exceptionsCount; + private int exceptionCounter = 0; + + public RepeatEventProcessor(int exceptionsCount) { + this.exceptionsCount = exceptionsCount; + } + + @Override + public void onEvent(AbstractProductProcessITextEvent event) { + if (exceptionCounter < exceptionsCount) { + exceptionCounter++; + throw new ProductEventHandlerRepeatException("customMessage" + exceptionCounter); + } + + } + + @Override + public String getProductName() { + return ProductNameConstant.ITEXT_CORE; + } + + @Override + public String getUsageType() { + return "someUsage"; + } + + @Override + public String getProducer() { + return "someProducer"; + } + } } diff --git a/commons/src/test/java/com/itextpdf/commons/actions/data/ProductDataTest.java b/commons/src/test/java/com/itextpdf/commons/actions/data/ProductDataTest.java index 0a9b02268c..c1525e8f4a 100644 --- a/commons/src/test/java/com/itextpdf/commons/actions/data/ProductDataTest.java +++ b/commons/src/test/java/com/itextpdf/commons/actions/data/ProductDataTest.java @@ -42,6 +42,18 @@ public void productDataCreationTest() { Assert.assertEquals(2100, productData.getToCopyrightYear()); } + @Test + public void productDataAnotherCreationTest() { + ProductData productData = new ProductData("publicProductName", "productName", "1.2", "4.0.0", 1900, 2100); + + Assert.assertEquals("publicProductName", productData.getPublicProductName()); + Assert.assertEquals("productName", productData.getProductName()); + Assert.assertEquals("1.2", productData.getVersion()); + Assert.assertEquals("4.0.0", productData.getMinCompatibleLicensingModuleVersion()); + Assert.assertEquals(1900, productData.getSinceCopyrightYear()); + Assert.assertEquals(2100, productData.getToCopyrightYear()); + } + @Test public void equalsTest() { ProductData a = new ProductData("publicProductName", "productName", "1.2", 1900, 2100); diff --git a/commons/src/test/java/com/itextpdf/commons/utils/DateTimeUtilTest.java b/commons/src/test/java/com/itextpdf/commons/utils/DateTimeUtilTest.java index b39e73059d..2b000c8fec 100644 --- a/commons/src/test/java/com/itextpdf/commons/utils/DateTimeUtilTest.java +++ b/commons/src/test/java/com/itextpdf/commons/utils/DateTimeUtilTest.java @@ -25,6 +25,7 @@ This file is part of the iText (R) project. import com.itextpdf.test.ExtendedITextTest; import com.itextpdf.test.annotations.type.UnitTest; +import java.util.Calendar; import java.util.Date; import org.junit.Assert; import org.junit.Test; @@ -32,6 +33,10 @@ This file is part of the iText (R) project. @Category(UnitTest.class) public class DateTimeUtilTest extends ExtendedITextTest { + + private static final double ZERO_DELTA = 1e-6; + private static final double ONE_SECOND_DELTA = 1000.0; + @Test public void getCurrentTest() { Date date = new Date(); @@ -43,4 +48,29 @@ public void isInPastTest() { Date date = new Date(1); Assert.assertTrue(DateTimeUtil.isInPast(date)); } + + @Test + public void parseDateAndGetUtcMillisFromEpochTest() { + Calendar parsedDate = DateTimeUtil.getCalendar(DateTimeUtil.parseWithDefaultPattern("2020-05-05")); + double millisFromEpochTo2020_05_05 = DateTimeUtil.getUtcMillisFromEpoch(parsedDate); + + long offset = DateTimeUtil.getCurrentTimeZoneOffset(); + Assert.assertEquals(1588636800000d - offset, millisFromEpochTo2020_05_05, ZERO_DELTA); + } + + @Test + public void compareUtcMillisFromEpochWithNullParamAndCurrentTimeTest() throws InterruptedException { + double getUtcMillisFromEpochWithNullParam = DateTimeUtil.getUtcMillisFromEpoch(null); + double millisFromEpochToCurrentTime = DateTimeUtil.getUtcMillisFromEpoch(DateTimeUtil.getCurrentTimeCalendar()); + + Assert.assertEquals(millisFromEpochToCurrentTime, getUtcMillisFromEpochWithNullParam, ONE_SECOND_DELTA); + } + + @Test + public void parseDateAndGetRelativeTimeTest() { + double relativeTime = DateTimeUtil.getRelativeTime(DateTimeUtil.parseWithDefaultPattern("2020-05-05")); + + long offset = DateTimeUtil.getCurrentTimeZoneOffset(); + Assert.assertEquals(1588636800000d - offset, relativeTime, ZERO_DELTA); + } } diff --git a/commons/src/test/java/com/itextpdf/commons/utils/ProcessInfoTest.java b/commons/src/test/java/com/itextpdf/commons/utils/ProcessInfoTest.java new file mode 100644 index 0000000000..9e8bf185c5 --- /dev/null +++ b/commons/src/test/java/com/itextpdf/commons/utils/ProcessInfoTest.java @@ -0,0 +1,58 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2021 iText Group NV + Authors: iText Software. + + This program is offered under a commercial and under the AGPL license. + For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + + AGPL licensing: + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +package com.itextpdf.commons.utils; + +import com.itextpdf.test.ExtendedITextTest; +import com.itextpdf.test.annotations.type.UnitTest; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +@Category(UnitTest.class) +public class ProcessInfoTest extends ExtendedITextTest { + + @Test + public void getExitCodeTest() { + int exitCode = 1; + ProcessInfo processInfo = new ProcessInfo(exitCode, null, null); + + Assert.assertEquals(exitCode, processInfo.getExitCode()); + } + + @Test + public void getProcessStdOutput() { + String stdOutput = "output"; + ProcessInfo processInfo = new ProcessInfo(0, stdOutput, null); + + Assert.assertEquals(stdOutput, processInfo.getProcessStdOutput()); + } + + @Test + public void getProcessErrOutput() { + String stdOutput = "output"; + ProcessInfo processInfo = new ProcessInfo(0, null, stdOutput); + + Assert.assertEquals(stdOutput, processInfo.getProcessErrOutput()); + } +} diff --git a/commons/src/test/java/com/itextpdf/commons/utils/SystemUtilTest.java b/commons/src/test/java/com/itextpdf/commons/utils/SystemUtilTest.java index 5e263e4e51..8b5772d1b4 100644 --- a/commons/src/test/java/com/itextpdf/commons/utils/SystemUtilTest.java +++ b/commons/src/test/java/com/itextpdf/commons/utils/SystemUtilTest.java @@ -165,6 +165,19 @@ public void runProcessAndWaitWithWorkingDirectoryTest() throws IOException, Inte Assert.assertTrue(FileUtil.fileExists(diff)); } + @Test + public void runProcessAndGetProcessInfoTest() throws IOException, InterruptedException { + String imageMagickPath = SystemUtil.getPropertyOrEnvironmentVariable(MAGICK_COMPARE_ENVIRONMENT_VARIABLE); + if (imageMagickPath == null) { + imageMagickPath = SystemUtil.getPropertyOrEnvironmentVariable(MAGICK_COMPARE_ENVIRONMENT_VARIABLE_LEGACY); + } + + ProcessInfo processInfo = SystemUtil.runProcessAndGetProcessInfo(imageMagickPath,"--version"); + + Assert.assertNotNull(processInfo); + Assert.assertEquals(0, processInfo.getExitCode()); + } + static class TestProcess extends Process { diff --git a/font-asian/pom.xml b/font-asian/pom.xml index 03918b59d0..03ca569696 100644 --- a/font-asian/pom.xml +++ b/font-asian/pom.xml @@ -4,7 +4,7 @@ com.itextpdf root - 7.2.0 + 7.2.1 font-asian iText 7 - Asian fonts diff --git a/forms/pom.xml b/forms/pom.xml index 0e96927d20..85f191ca6f 100644 --- a/forms/pom.xml +++ b/forms/pom.xml @@ -4,7 +4,7 @@ com.itextpdf root - 7.2.0 + 7.2.1 forms iText 7 - forms diff --git a/forms/src/main/java/com/itextpdf/forms/fields/PdfFormField.java b/forms/src/main/java/com/itextpdf/forms/fields/PdfFormField.java index 27b63396f0..22cdfef6d1 100644 --- a/forms/src/main/java/com/itextpdf/forms/fields/PdfFormField.java +++ b/forms/src/main/java/com/itextpdf/forms/fields/PdfFormField.java @@ -2020,6 +2020,12 @@ public PdfFormField setBorderWidth(float borderWidth) { return this; } + /** + * Sets the border style for the field. + * + * @param style the new border style. + * @return the edited field + */ public PdfFormField setBorderStyle(PdfDictionary style) { getWidgets().get(0).setBorderStyle(style); regenerateField(); @@ -2275,10 +2281,21 @@ protected boolean isWrappedObjectMustBeIndirect() { return true; } + /** + * Gets the {@link PdfDocument} that owns that form field. + * + * @return the {@link PdfDocument} that owns that form field. + */ protected PdfDocument getDocument() { return getPdfObject().getIndirectReference().getDocument(); } + /** + * Gets a {@link Rectangle} that matches the current size and position of this form field. + * + * @param field current form field. + * @return a {@link Rectangle} that matches the current size and position of this form field. + */ protected Rectangle getRect(PdfDictionary field) { PdfArray rect = field.getAsArray(PdfName.Rect); if (rect == null) { @@ -2292,6 +2309,12 @@ protected Rectangle getRect(PdfDictionary field) { return rect != null ? rect.toRectangle() : null; } + /** + * Convert {@link String} multidimensional array of combo box or list options to {@link PdfArray}. + * + * @param options Two-dimensional array of options. + * @return a {@link PdfArray} that contains all the options. + */ protected static PdfArray processOptions(String[][] options) { PdfArray array = new PdfArray(); for (String[] option : options) { @@ -2302,6 +2325,12 @@ protected static PdfArray processOptions(String[][] options) { return array; } + /** + * Convert {@link String} array of combo box or list options to {@link PdfArray}. + * + * @param options array of options. + * @return a {@link PdfArray} that contains all the options. + */ protected static PdfArray processOptions(String[] options) { PdfArray array = new PdfArray(); for (String option : options) { diff --git a/hyph/pom.xml b/hyph/pom.xml index be8bae62fd..d92651dc98 100644 --- a/hyph/pom.xml +++ b/hyph/pom.xml @@ -4,7 +4,7 @@ com.itextpdf root - 7.2.0 + 7.2.1 hyph iText 7 - hyph diff --git a/io/pom.xml b/io/pom.xml index a85fbbcd56..d4000b64f5 100644 --- a/io/pom.xml +++ b/io/pom.xml @@ -4,7 +4,7 @@ com.itextpdf root - 7.2.0 + 7.2.1 io iText 7 - io diff --git a/io/src/main/java/com/itextpdf/io/exceptions/IoExceptionMessage.java b/io/src/main/java/com/itextpdf/io/exceptions/IoExceptionMessage.java index 59be5a2f37..d8f725309c 100644 --- a/io/src/main/java/com/itextpdf/io/exceptions/IoExceptionMessage.java +++ b/io/src/main/java/com/itextpdf/io/exceptions/IoExceptionMessage.java @@ -63,5 +63,7 @@ public final class IoExceptionMessage { + " environment variable to a CLI command that can run the Ghostscript application. See BUILDING.MD in the root of the repository for more details."; public static final String GHOSTSCRIPT_FAILED = "GhostScript failed for "; public static final String CANNOT_OPEN_OUTPUT_DIRECTORY = "Cannot open output directory for "; - + public static final String IMAGE_MAGICK_OUTPUT_IS_NULL = "ImageMagick process output is null."; + public static final String IMAGE_MAGICK_PROCESS_EXECUTION_FAILED = + "ImageMagick process execution finished with errors: "; } diff --git a/io/src/main/java/com/itextpdf/io/logs/IoLogMessageConstant.java b/io/src/main/java/com/itextpdf/io/logs/IoLogMessageConstant.java index 4f21551ae7..8cafd90a8c 100644 --- a/io/src/main/java/com/itextpdf/io/logs/IoLogMessageConstant.java +++ b/io/src/main/java/com/itextpdf/io/logs/IoLogMessageConstant.java @@ -85,6 +85,10 @@ public final class IoLogMessageConstant { + "as finished. Consider using com.itextpdf.layout.tagging.LayoutTaggingHelper#replaceKidHint " + "method for replacing not yet finished kid hint of a finished parent hint."; + /** + * @deprecated Unused constant. Will be removed in 7.3 + */ + @Deprecated public static final String CANNOT_ADD_KID_HINT_WHICH_IS_ALREADY_ADDED_TO_ANOTHER_PARENT = "Layout tagging hints addition failed: cannot add a kid hint to a new parent if it is already added to " + "another parent. Consider using com.itextpdf.layout.tagging.LayoutTaggingHelper#moveHint method " @@ -168,6 +172,10 @@ public final class IoLogMessageConstant { public static final String DOCUMENT_IDS_ARE_CORRUPTED = "The document original and/or modified id is corrupted"; + /** + * @deprecated Unused constant. Will be removed in 7.3 + */ + @Deprecated public static final String DOCUMENT_SERIALIZATION_EXCEPTION_RAISED = "Unhandled exception while serialization"; public static final String DOCUMENT_VERSION_IN_CATALOG_CORRUPTED = "The document version specified in catalog is " @@ -175,6 +183,11 @@ public final class IoLogMessageConstant { public static final String DURING_CONSTRUCTION_OF_ICC_PROFILE_ERROR_OCCURRED = "During the construction of the ICC" + " profile, the {0} error with message \"{1}\" occurred, the ICC profile will not be installed in the " + "image."; + + /** + * @deprecated Unused constant. Will be removed in 7.3 + */ + @Deprecated public static final String ELEMENT_DOES_NOT_FIT_AREA = "Element does not fit current area. {0}"; public static final String ELEMENT_WAS_FORCE_PLACED_KEEP_WITH_NEXT_WILL_BE_IGNORED = @@ -304,6 +317,10 @@ public final class IoLogMessageConstant { public static final String INLINE_BLOCK_ELEMENT_WILL_BE_CLIPPED = "Inline block element does not fit into parent element and will be clipped"; + /** + * @deprecated Unused constant. Will be removed in 7.3 + */ + @Deprecated public static final String INPUT_STREAM_CONTENT_IS_LOST_ON_PDFSTREAM_SERIALIZATION = "PdfStream contains not null input stream. It's content will be lost in serialized object."; @@ -452,8 +469,16 @@ public final class IoLogMessageConstant { public static final String TABLE_WIDTH_IS_MORE_THAN_EXPECTED_DUE_TO_MIN_WIDTH = "Table width is more than expected due to min width of cell(s)."; + /** + * @deprecated Unused constant. Will be removed in 7.3 + */ + @Deprecated public static final String TAGGING_HINT_NOT_FINISHED_BEFORE_CLOSE = "Tagging hint wasn't finished before closing."; + /** + * @deprecated Unused constant. Will be removed in 7.3 + */ + @Deprecated public static final String TAG_STRUCTURE_CONTEXT_WILL_BE_REINITIALIZED_ON_SERIALIZATION = "Tag structure context is not null and will be reinitialized in the copy of document. The copy may lose " + "some data"; @@ -481,18 +506,34 @@ public final class IoLogMessageConstant { + "this means that element was added to the Canvas instance that was created not with constructor " + "taking PdfPage as argument. Not processed property: {0}"; + /** + * @deprecated Unused constant. Will be removed in 7.3 + */ + @Deprecated public static final String UNABLE_TO_INTERRUPT_THREAD = "Unable to interrupt a thread"; public static final String UNABLE_TO_INVERT_GRADIENT_TRANSFORMATION = "Unable to invert gradient transformation, " + "ignoring it"; + /** + * @deprecated Unused constant. Will be removed in 7.3 + */ + @Deprecated public static final String UNABLE_TO_REGISTER_EVENT_DATA_HANDLER_SHUTDOWN_HOOK = "Unable to register event data handler shutdown hook because of security reasons."; + /** + * @deprecated Unused constant. Will be removed in 7.3 + */ + @Deprecated public static final String UNABLE_TO_SEARCH_FOR_EVENT_CONTEXT = "It is impossible to retrieve event context because of the security reasons. Event counting may behave in " + "unexpected way"; + /** + * @deprecated Unused constant. Will be removed in 7.3 + */ + @Deprecated public static final String UNABLE_TO_UNREGISTER_EVENT_DATA_HANDLER_SHUTDOWN_HOOK = "Unable to unregister event data handler shutdown hook because of security permissions"; @@ -507,6 +548,10 @@ public final class IoLogMessageConstant { public static final String UNKNOWN_COLOR_FORMAT_MUST_BE_RGB_OR_RRGGBB = "Unknown color format: must be rgb or rrggbb."; + /** + * @deprecated Unused constant. Will be removed in 7.3 + */ + @Deprecated public static final String UNKNOWN_DIGEST_METHOD = "Unknown digest method. Valid values are MD5, SHA1 SHA256, SHA384, SHA512 and RIPEMD160."; @@ -542,6 +587,10 @@ public final class IoLogMessageConstant { public static final String XFDF_NO_F_OBJECT_TO_COMPARE = "Xfdf no f object to compare."; + /** + * @deprecated Unused constant. Will be removed in 7.3 + */ + @Deprecated public static final String XFDF_OUTPUT_STREAM_CORRUPTED = "Xfdf output stream is corrupted."; public static final String XFDF_UNSUPPORTED_ANNOTATION_ATTRIBUTE = "Xfdf unsupported attribute type"; diff --git a/io/src/main/java/com/itextpdf/io/source/OutputStream.java b/io/src/main/java/com/itextpdf/io/source/OutputStream.java index d78161b335..086b5f1d91 100644 --- a/io/src/main/java/com/itextpdf/io/source/OutputStream.java +++ b/io/src/main/java/com/itextpdf/io/source/OutputStream.java @@ -51,19 +51,56 @@ public class OutputStream extends java.io.Output //long=19 + max frac=6 => 26 => round to 32. private final ByteBuffer numBuffer = new ByteBuffer(32); - + private Boolean localHighPrecision; protected java.io.OutputStream outputStream = null; protected long currentPos = 0; protected boolean closeStream = true; + /** + * Gets global high precision setting. + * + * @return global high precision setting. + */ public static boolean getHighPrecision() { return ByteUtils.HighPrecision; } + /** + * Sets global high precision setting for all {@link OutputStream} instances. + * + * @param value if true, all floats and double will be written with high precision + * in all {@link OutputStream} instances. + */ public static void setHighPrecision(boolean value) { ByteUtils.HighPrecision = value; } + /** + * Gets local high precision setting. + * + * @return local high precision setting. + */ + public boolean getLocalHighPrecision() { + return this.localHighPrecision; + } + + /** + * Sets local high precision setting for the {@link OutputStream}. + * Global {@link ByteUtils#HighPrecision} setting will be overridden by this one. + * + * @param value if true, all floats and double will be written with high precision + * in the underlying {@link OutputStream}. + */ + public void setLocalHighPrecision(boolean value) { + this.localHighPrecision = value; + } + + /** + * Creates a new {@link OutputStream} instance + * based on {@link java.io.OutputStream} instance. + * + * @param outputStream the {@link OutputStream} instance. + */ public OutputStream(java.io.OutputStream outputStream) { super(); this.outputStream = outputStream; @@ -76,6 +113,22 @@ protected OutputStream() { super(); } + /** + * Creates a new {@link OutputStream} instance + * based on {@link java.io.OutputStream} instance and precision setting value. + * + * @param outputStream the {@link java.io.OutputStream} instance. + * @param localHighPrecision If true, all float and double values + * will be written with high precision. + * Global {@link ByteUtils#HighPrecision} setting + * will be overridden by this one. + */ + public OutputStream(java.io.OutputStream outputStream, boolean localHighPrecision) { + super(); + this.outputStream = outputStream; + this.localHighPrecision = localHighPrecision; + } + @Override public void write(int b) throws java.io.IOException { outputStream.write(b); @@ -94,6 +147,13 @@ public void write(byte[] b, int off, int len) throws java.io.IOException { currentPos += len; } + /** + * See {@link java.io.OutputStream#write(int)}. + * + * @param value byte to write. + * + * @throws IOException if {@link java.io.IOException} occurs. + */ public void writeByte(byte value) { try { write(value); @@ -109,10 +169,18 @@ public void flush() throws java.io.IOException { @Override public void close() throws java.io.IOException { - if (closeStream) + if (closeStream) { outputStream.close(); + } } + /** + * Writes long to internal {@link java.io.OutputStream} in ISO format. + * + * @param value value to write. + * + * @return this stream as passed generic stream. + */ public T writeLong(long value) { try { ByteUtils.getIsoBytes(value, numBuffer.reset()); @@ -123,6 +191,13 @@ public T writeLong(long value) { } } + /** + * Writes int to internal {@link java.io.OutputStream} in ISO format. + * + * @param value value to write. + * + * @return this stream as passed generic stream. + */ public T writeInteger(int value) { try { ByteUtils.getIsoBytes(value, numBuffer.reset()); @@ -133,27 +208,65 @@ public T writeInteger(int value) { } } + /** + * Writes float to internal {@link java.io.OutputStream} in ISO format. + * + * @param value value to write. + * + * @return this stream as passed generic stream. + */ public T writeFloat(float value) { - return writeFloat(value, ByteUtils.HighPrecision); + return writeFloat(value, localHighPrecision == null ? ByteUtils.HighPrecision : localHighPrecision); } + /** + * Writes float to internal {@link java.io.OutputStream} in ISO format. + * + * @param value value to write. + * @param highPrecision If true, float value will be written with high precision. + * + * @return this stream as passed generic stream. + */ public T writeFloat(float value, boolean highPrecision) { return writeDouble(value, highPrecision); } + /** + * Writes float array to internal {@link java.io.OutputStream} in ISO format. + * + * @param value float array to write. + * + * @return this stream as passed generic stream. + */ public T writeFloats(float[] value) { for (int i = 0; i < value.length; i++) { writeFloat(value[i]); - if (i < value.length - 1) + if (i < value.length - 1) { writeSpace(); + } } return (T) this; } + /** + * Writes double to internal {@link java.io.OutputStream} in ISO format. + * + * @param value value to write. + * + * @return this stream as passed generic stream. + */ public T writeDouble(double value) { - return writeDouble(value, ByteUtils.HighPrecision); + return writeDouble(value, localHighPrecision == null ? ByteUtils.HighPrecision : localHighPrecision); } + /** + * Writes double to internal {@link java.io.OutputStream} in ISO format. + * + * @param value value to write. + * @param highPrecision If true, double value will be written with high precision. + * + * @return this stream as passed generic stream. + */ public T writeDouble(double value, boolean highPrecision) { try { ByteUtils.getIsoBytes(value, numBuffer.reset(), highPrecision); @@ -164,6 +277,13 @@ public T writeDouble(double value, boolean highPrecision) { } } + /** + * Writes byte to internal {@link java.io.OutputStream}. + * + * @param value value to write. + * + * @return this stream as passed generic stream. + */ public T writeByte(int value) { try { write(value); @@ -173,18 +293,44 @@ public T writeByte(int value) { } } + /** + * Writes space to internal {@link java.io.OutputStream}. + * + * @return this stream as passed generic stream. + */ public T writeSpace() { return writeByte(' '); } + /** + * Writes new line to internal {@link java.io.OutputStream}. + * + * @return this stream as passed generic stream. + */ public T writeNewLine() { return writeByte('\n'); } + /** + * Writes {@code String} to internal {@link java.io.OutputStream} in ISO format. + * + * @param value string to write. + * + * @return this stream as passed generic stream. + */ public T writeString(String value) { return writeBytes(ByteUtils.getIsoBytes(value)); } + /** + * See {@link OutputStream#write(byte[])}. + * + * @param b byte array to write. + * + * @return this stream as passed generic stream. + * + * @throws com.itextpdf.io.exceptions.IOException if {@link java.io.IOException} is thrown. + */ public T writeBytes(byte[] b) { try { write(b); @@ -194,6 +340,17 @@ public T writeBytes(byte[] b) { } } + /** + * See {@link OutputStream#write(byte[], int, int)}. + * + * @param b the data to write. + * @param off the start offset in the data. + * @param len the number of bytes to write. + * + * @return this stream as passed generic stream. + * + * @throws com.itextpdf.io.exceptions.IOException if {@link java.io.IOException} is thrown. + */ public T writeBytes(byte[] b, int off, int len) { try { write(b, off, len); @@ -203,35 +360,70 @@ public T writeBytes(byte[] b, int off, int len) { } } + /** + * Gets current output stream position. + * + * @return current output stream position. + */ public long getCurrentPos() { return currentPos; } + /** + * Gets internal {@link java.io.OutputStream}. + * + * @return internal {@link java.io.OutputStream}. + */ public java.io.OutputStream getOutputStream() { return outputStream; } + /** + * Returns true, if internal {@link java.io.OutputStream} have to be closed after {@link #close()} call, + * false otherwise. + * + * @return true if stream needs to be closed, false if it's done manually. + */ public boolean isCloseStream() { return closeStream; } + /** + * Sets internal {@link java.io.OutputStream} to be closed after {@link OutputStream#close()}. + * + * @param closeStream true if stream needs to be closed, false if it's done manually. + */ public void setCloseStream(boolean closeStream) { this.closeStream = closeStream; } + /** + * See {@link ByteArrayOutputStream#assignBytes(byte[], int)}. + * + * @param bytes bytes to assign. + * @param count number of bytes to assign. + */ public void assignBytes(byte[] bytes, int count) { if (outputStream instanceof ByteArrayOutputStream) { ((ByteArrayOutputStream) outputStream).assignBytes(bytes, count); currentPos = count; - } else + } else { throw new IOException(IOException.BytesCanBeAssignedToByteArrayOutputStreamOnly); + } } + /** + * See {@link ByteArrayOutputStream#reset()}. + * + * @throws com.itextpdf.io.exceptions.IOException if internal {@link OutputStream}. + * is not a {@link ByteArrayOutputStream} instance. + */ public void reset() { if (outputStream instanceof ByteArrayOutputStream) { ((ByteArrayOutputStream) outputStream).reset(); currentPos = 0; - } else + } else { throw new IOException(IOException.BytesCanBeResetInByteArrayOutputStreamOnly); + } } } diff --git a/io/src/main/java/com/itextpdf/io/util/ImageMagickCompareResult.java b/io/src/main/java/com/itextpdf/io/util/ImageMagickCompareResult.java new file mode 100644 index 0000000000..c2ecb92acc --- /dev/null +++ b/io/src/main/java/com/itextpdf/io/util/ImageMagickCompareResult.java @@ -0,0 +1,62 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2021 iText Group NV + Authors: iText Software. + + This program is offered under a commercial and under the AGPL license. + For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + + AGPL licensing: + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +package com.itextpdf.io.util; + +/** + * A helper data class, which aggregates true/false result of ImageMagick comparing + * as well as the number of different pixels. + */ +public final class ImageMagickCompareResult { + + private final boolean result; + private final long diffPixels; + + /** + * Creates an instance that contains ImageMagick comparing result information. + * + * @param result true, if the compared images are equal. + * @param diffPixels number of different pixels. + */ + public ImageMagickCompareResult(boolean result, long diffPixels) { + this.result = result; + this.diffPixels = diffPixels; + } + + /** + * Returns image compare boolean value. + * + * @return true if the compared images are equal. + */ + public boolean isComparingResultSuccessful() { + return result; + } + + /** + * Getter for a different pixels count. + * + * @return Returns a a different pixels count. + */ + public long getDiffPixels() { + return diffPixels; + } +} diff --git a/io/src/main/java/com/itextpdf/io/util/ImageMagickHelper.java b/io/src/main/java/com/itextpdf/io/util/ImageMagickHelper.java index fc3c1abf3b..1481912b3f 100644 --- a/io/src/main/java/com/itextpdf/io/util/ImageMagickHelper.java +++ b/io/src/main/java/com/itextpdf/io/util/ImageMagickHelper.java @@ -44,11 +44,13 @@ This file is part of the iText (R) project. package com.itextpdf.io.util; import com.itextpdf.commons.utils.FileUtil; +import com.itextpdf.commons.utils.ProcessInfo; import com.itextpdf.commons.utils.SystemUtil; import com.itextpdf.io.exceptions.IoExceptionMessage; -import java.io.File; import java.io.IOException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * A utility class that is used as an interface to run 3rd-party tool ImageMagick. @@ -71,6 +73,9 @@ public class ImageMagickHelper { static final String MAGICK_COMPARE_KEYWORD = "ImageMagick Studio LLC"; private static final String TEMP_FILE_PREFIX = "itext_im_io_temp"; + private static final String DIFF_PIXELS_OUTPUT_REGEXP = "^\\d+\\.*\\d*(e\\+\\d+)?"; + + private static final Pattern pattern = Pattern.compile(DIFF_PIXELS_OUTPUT_REGEXP); private String compareExec; @@ -141,6 +146,58 @@ public boolean runImageMagickImageCompare(String outImageFilePath, String cmpIma */ public boolean runImageMagickImageCompare(String outImageFilePath, String cmpImageFilePath, String diffImageName, String fuzzValue) throws IOException, InterruptedException { + ImageMagickCompareResult compareResult = runImageMagickImageCompareAndGetResult(outImageFilePath, + cmpImageFilePath, diffImageName, fuzzValue); + + return compareResult.isComparingResultSuccessful(); + } + + /** + * Runs imageMagick to visually compare images with the specified fuzziness value and given threshold + * and generate difference output. + * + * @param outImageFilePath Path to the output image file + * @param cmpImageFilePath Path to the cmp image file + * @param diffImageName Path to the difference output image file + * @param fuzzValue String fuzziness value to compare images. Should be formatted as string with integer + * or decimal number. Can be null, if it is not required to use fuzziness + * @param threshold Long value of accepted threshold. + * + * @return boolean result of comparing: true - images are visually equal + * + * @throws IOException if there are file's reading/writing issues + * @throws InterruptedException if there is thread interruption while executing ImageMagick. + */ + public boolean runImageMagickImageCompareWithThreshold(String outImageFilePath, String cmpImageFilePath, + String diffImageName, String fuzzValue, long threshold) throws IOException, InterruptedException { + ImageMagickCompareResult compareResult = runImageMagickImageCompareAndGetResult(outImageFilePath, + cmpImageFilePath, diffImageName, fuzzValue); + + if (compareResult.isComparingResultSuccessful()) { + return true; + } else { + return compareResult.getDiffPixels() <= threshold; + } + } + + /** + * Runs imageMagick to visually compare images with the specified fuzziness value and generate difference output. + * This method returns an object of {@link ImageMagickCompareResult}, containing comparing result information, + * such as boolean result value and the number of different pixels. + * + * @param outImageFilePath Path to the output image file + * @param cmpImageFilePath Path to the cmp image file + * @param diffImageName Path to the difference output image file + * @param fuzzValue String fuzziness value to compare images. Should be formatted as string with integer + * or decimal number. Can be null, if it is not required to use fuzziness + * + * @return an object of {@link ImageMagickCompareResult}. containing comparing result information. + * + * @throws IOException if there are file's reading/writing issues + * @throws InterruptedException if there is thread interruption while executing ImageMagick. + */ + public ImageMagickCompareResult runImageMagickImageCompareAndGetResult(String outImageFilePath, + String cmpImageFilePath, String diffImageName, String fuzzValue) throws IOException, InterruptedException { if (!validateFuzziness(fuzzValue)) { throw new IllegalArgumentException("Invalid fuzziness value: " + fuzzValue); } @@ -160,12 +217,15 @@ public boolean runImageMagickImageCompare(String outImageFilePath, String cmpIma + replacementOutFile + "' '" + replacementCmpFile + "' '" + replacementDiff + "'"; - boolean result = SystemUtil.runProcessAndWait(compareExec, currCompareParams); + ProcessInfo processInfo = SystemUtil.runProcessAndGetProcessInfo(compareExec, currCompareParams); + boolean comparingResult = processInfo.getExitCode() == 0; + long diffPixels = parseImageMagickProcessOutput(processInfo.getProcessErrOutput()); + ImageMagickCompareResult resultInfo = new ImageMagickCompareResult(comparingResult, diffPixels); if (FileUtil.fileExists(replacementDiff)) { FileUtil.copy(replacementDiff, diffImageName); } - return result; + return resultInfo; } finally { FileUtil.removeFiles(new String[] {replacementOutFile, replacementCmpFile, replacementDiff}); } @@ -184,4 +244,29 @@ static boolean validateFuzziness(String fuzziness) { } } } + + private static long parseImageMagickProcessOutput(String processOutput) throws IOException { + if (null == processOutput) { + throw new IllegalArgumentException(IoExceptionMessage.IMAGE_MAGICK_OUTPUT_IS_NULL); + } + + if (processOutput.isEmpty()) { + return 0L; + } + + String[] processOutputLines = processOutput.split("\n"); + + for (String line : processOutputLines) { + try { + Matcher matcher = pattern.matcher(line); + if (matcher.find()) { + return (long) Double.valueOf(matcher.group()).longValue(); + } + } catch (NumberFormatException e) { + // Nothing should be done here because of the exception, that will be thrown later. + } + } + + throw new IOException(IoExceptionMessage.IMAGE_MAGICK_PROCESS_EXECUTION_FAILED + processOutput); + } } diff --git a/io/src/main/java/com/itextpdf/io/util/UrlUtil.java b/io/src/main/java/com/itextpdf/io/util/UrlUtil.java index fb30ffae09..bdd7f586c7 100644 --- a/io/src/main/java/com/itextpdf/io/util/UrlUtil.java +++ b/io/src/main/java/com/itextpdf/io/util/UrlUtil.java @@ -103,21 +103,21 @@ public static InputStream openStream(URL url) throws IOException { /** * This method gets the last redirected url. - * @param initialUrl an initial URL - * @return the last redirected url - * @throws IOException + * + * @param initialUrl an initial URL. + * + * @return the last redirected url. + * + * @throws IOException signals that an I/O exception has occurred. + * + * @deprecated {@link UrlUtil#getInputStreamOfFinalConnection(URL)} can be used to get input stream from final + * connection. */ + @Deprecated public static URL getFinalURL(URL initialUrl) throws IOException { - URL finalUrl = null; - URL nextUrl = initialUrl; - while (nextUrl != null) { - finalUrl = nextUrl; - URLConnection connection = finalUrl.openConnection(); - String location = connection.getHeaderField("location"); - // Close input stream deliberately to close the handle which is created during getHeaderField invocation - connection.getInputStream().close(); - nextUrl = location != null ? new URL(location) : null; - } + final URLConnection finalConnection = getFinalConnection(initialUrl); + final URL finalUrl = finalConnection.getURL(); + finalConnection.getInputStream().close(); return finalUrl; } @@ -138,4 +138,44 @@ public static String getFileUriString(String filename) throws MalformedURLExcept public static String getNormalizedFileUriString(String filename) { return "file://" + UrlUtil.toNormalizedURI(filename).getPath(); } + + /** + * Gets the input stream of connection related to last redirected url. You should manually close input stream after + * calling this method to not hold any open resources. + * + * @param initialUrl an initial URL. + * + * @return an input stream of connection related to the last redirected url. + * + * @throws IOException signals that an I/O exception has occurred. + */ + public static InputStream getInputStreamOfFinalConnection(URL initialUrl) throws IOException { + final URLConnection finalConnection = getFinalConnection(initialUrl); + return finalConnection.getInputStream(); + } + + /** + * Gets the connection related to the last redirected url. You should close connection manually after calling + * this method, to not hold any open resources. + * + * @param initialUrl an initial URL. + * + * @return connection related to the last redirected url. + * + * @throws IOException signals that an I/O exception has occurred. + */ + static URLConnection getFinalConnection(URL initialUrl) throws IOException { + URL nextUrl = initialUrl; + URLConnection connection = null; + while (nextUrl != null) { + connection = nextUrl.openConnection(); + final String location = connection.getHeaderField("location"); + nextUrl = location == null ? null : new URL(location); + if (nextUrl != null) { + // close input stream deliberately to close the handle which is created during getHeaderField invocation + connection.getInputStream().close(); + } + } + return connection; + } } diff --git a/io/src/test/java/com/itextpdf/io/source/OutputStreamTest.java b/io/src/test/java/com/itextpdf/io/source/OutputStreamTest.java new file mode 100644 index 0000000000..6608ebc6c8 --- /dev/null +++ b/io/src/test/java/com/itextpdf/io/source/OutputStreamTest.java @@ -0,0 +1,369 @@ +/* + + This file is part of the iText (R) project. + Copyright (c) 1998-2021 iText Group NV + Authors: Bruno Lowagie, Paulo Soares, et al. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License version 3 + as published by the Free Software Foundation with the addition of the + following permission added to Section 15 as permitted in Section 7(a): + FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY + ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT + OF THIRD PARTY RIGHTS + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Affero General Public License for more details. + You should have received a copy of the GNU Affero General Public License + along with this program; if not, see http://www.gnu.org/licenses or write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA, 02110-1301 USA, or download the license from the following URL: + http://itextpdf.com/terms-of-use/ + + The interactive user interfaces in modified source and object code versions + of this program must display Appropriate Legal Notices, as required under + Section 5 of the GNU Affero General Public License. + + In accordance with Section 7(b) of the GNU Affero General Public License, + a covered work must retain the producer line in every PDF that is created + or manipulated using iText. + + You can be released from the requirements of the license by purchasing + a commercial license. Buying such a license is mandatory as soon as you + develop commercial activities involving the iText software without + disclosing the source code of your own applications. + These activities include: offering paid services to customers as an ASP, + serving PDFs on the fly in a web application, shipping iText with a closed + source product. + + For more information, please contact iText Software Corp. at this + address: sales@itextpdf.com + */ +package com.itextpdf.io.source; + +import com.itextpdf.io.logs.IoLogMessageConstant; +import com.itextpdf.test.AssertUtil; +import com.itextpdf.test.ExtendedITextTest; +import com.itextpdf.test.annotations.LogMessage; +import com.itextpdf.test.annotations.LogMessages; +import com.itextpdf.test.annotations.type.UnitTest; + +import java.io.FileOutputStream; +import java.nio.charset.StandardCharsets; +import java.util.Objects; +import org.junit.Assert; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.io.IOException; + +@Category(UnitTest.class) +public class OutputStreamTest extends ExtendedITextTest { + + private static final String SOURCE_FOLDER = "./src/test/resources/com/itextpdf/io/source/OSTEST.txt"; + private static java.io.OutputStream IO_EXCEPTION_OUTPUT_STREAM; + + static { + try { + IO_EXCEPTION_OUTPUT_STREAM = new FileOutputStream(SOURCE_FOLDER, true); + IO_EXCEPTION_OUTPUT_STREAM.close(); + } catch (IOException e) { + //ignore + } + } + + @Test + public void changePrecisionTest() throws IOException { + //the data is random + double expected = 0.100001d; + try (ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + OutputStream stream + = new OutputStream<>(bytes, false)) { + stream.setLocalHighPrecision(true); + stream.writeDouble(expected); + stream.flush(); + Assert.assertEquals(Objects.toString(expected), new String(bytes.toByteArray(), StandardCharsets.UTF_8)); + } + } + + @Test + public void changePrecisionToFalseTest() throws IOException { + //the data is random + double expected = 0.000002d; + try (ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + OutputStream stream + = new OutputStream<>(bytes, false)) { + stream.setLocalHighPrecision(false); + stream.writeDouble(expected); + stream.flush(); + Assert.assertEquals("0", new String(bytes.toByteArray(), StandardCharsets.UTF_8)); + } + } + + @LogMessages(messages = { + @LogMessage(messageTemplate = IoLogMessageConstant.ATTEMPT_PROCESS_NAN, count = 1) + }) + @Test + public void writeNanTest() throws IOException { + //the data is random + String expected = "0"; + try (ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + OutputStream stream + = new OutputStream<>(bytes)) { + stream.writeDouble(Double.NaN); + stream.flush(); + Assert.assertEquals(expected, new String(bytes.toByteArray(), StandardCharsets.UTF_8)); + } + } + + @Test + public void writeValidByteArrayTest() throws IOException { + //the data is random + byte[] expected = new byte[] {(byte) 68, (byte) 14, (byte) 173, (byte) 105}; + try (ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + OutputStream stream + = new OutputStream<>(bytes)) { + stream.write(expected); + stream.flush(); + Assert.assertArrayEquals(expected, bytes.toByteArray()); + } + } + + @Test + public void writeValidBytesArrayTest() throws IOException { + //the data is random + byte[] expected = new byte[] {(byte) 15, (byte) 233, (byte) 58, (byte) 97}; + try (ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + OutputStream stream + = new OutputStream<>(bytes)) { + stream.writeBytes(expected); + stream.flush(); + Assert.assertArrayEquals(expected, bytes.toByteArray()); + } + } + + @Test + public void writeSingleValidByteTest() throws IOException { + //the data is random + byte expected = (byte) 193; + try (ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + OutputStream stream + = new OutputStream<>(bytes)) { + stream.writeByte(expected); + stream.flush(); + Assert.assertArrayEquals(new byte[] {expected}, bytes.toByteArray()); + } + } + + @Test + public void writeSingleValidIntegerTest() throws IOException { + //the data is random + int expected = 1695609641; + try (ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + OutputStream stream + = new OutputStream<>(bytes)) { + stream.writeInteger(expected); + stream.flush(); + Assert.assertEquals(Objects.toString(expected), new String(bytes.toByteArray(), StandardCharsets.UTF_8)); + } + } + + @Test + public void writeSingleValidLongTest() throws IOException { + //the data is random + long expected = 1695609641552L; + try (ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + OutputStream stream + = new OutputStream<>(bytes)) { + stream.writeLong(expected); + stream.flush(); + Assert.assertEquals(Objects.toString(expected), new String(bytes.toByteArray(), StandardCharsets.UTF_8)); + } + } + + @Test + public void writeValidFloatsArrayTest() throws IOException { + //the data is random + float[] expected = new float[] {12.05f, 0.001f}; + try (ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + OutputStream stream + = new OutputStream<>(bytes)) { + stream.writeFloats(expected); + stream.flush(); + Assert.assertEquals(expected[0] + " " + expected[1], new String(bytes.toByteArray(), StandardCharsets.UTF_8)); + } + } + + @Test + public void writeValidBytesWithOffsetTest() throws IOException { + //the data is random + byte[] expected = new byte[] {(byte) 233, (byte) 58}; + try (ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + OutputStream stream + = new OutputStream<>(bytes)) { + stream.writeBytes(new byte[] {(byte) 15, (byte) 233, (byte) 58, (byte) 97}, 1, 2); + stream.flush(); + Assert.assertArrayEquals(expected, bytes.toByteArray()); + } + } + + @Test() + public void writeBytesIOExceptionTest() throws IOException { + //Testing that the exception is thrown, not using specific one because of .NET compatability + Assert.assertThrows(Exception.class,() -> { + byte[] bytesToWrite = new byte[] {(byte) 71}; + try (java.io.OutputStream bytes = IO_EXCEPTION_OUTPUT_STREAM; + OutputStream stream + = new OutputStream<>(bytes)) { + stream.writeBytes(bytesToWrite); + } + }); + } + + @Test() + public void writeByteIOExceptionTest() throws IOException { + //Testing that the exception is thrown, not using specific one because of .NET compatability + Assert.assertThrows(Exception.class,() -> { + byte byteToWrite = (byte) 71; + try (java.io.OutputStream bytes = IO_EXCEPTION_OUTPUT_STREAM; + OutputStream stream + = new OutputStream<>(bytes)) { + stream.writeByte(byteToWrite); + } + }); + } + + @Test() + public void writeByteIntIOExceptionTest() throws IOException { + //Testing that the exception is thrown, not using specific one because of .NET compatability + Assert.assertThrows(Exception.class,() -> { + //the data is random + int byteToWrite = 71; + try (java.io.OutputStream bytes = IO_EXCEPTION_OUTPUT_STREAM; + OutputStream stream + = new OutputStream<>(bytes)) { + stream.writeByte(byteToWrite); + } + }); + } + + @Test() + public void writeDoubleIOExceptionTest() throws IOException { + //Testing that the exception is thrown, not using specific one because of .NET compatability + Assert.assertThrows(Exception.class,() -> { + //the data is random + double num = 55.55d; + try (java.io.OutputStream bytes = IO_EXCEPTION_OUTPUT_STREAM; + OutputStream stream + = new OutputStream<>(bytes)) { + stream.writeDouble(num); + } + }); + } + + @Test() + public void writeLongIOExceptionTest() throws IOException { + //Testing that the exception is thrown, not using specific one because of .NET compatability + Assert.assertThrows(Exception.class,() -> { + //the data is random + long num = 55L; + try (java.io.OutputStream bytes = IO_EXCEPTION_OUTPUT_STREAM; + OutputStream stream + = new OutputStream<>(bytes)) { + stream.writeLong(num); + } + }); + } + + @Test + public void writeValidStringTest() throws IOException { + String expected = "Test string to write"; + try (ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + OutputStream stream + = new OutputStream<>(bytes)) { + stream.writeString(expected); + stream.writeNewLine(); + stream.flush(); + Assert.assertEquals(expected + '\n', new String(bytes.toByteArray(), StandardCharsets.UTF_8)); + } + } + + @Test + public void gettersAndSettersTest() throws IOException { + AssertUtil.doesNotThrow(() -> { + //testing that stream is not closed, if setCloseStream is false + OutputStream stream + = new OutputStream<>(null); + stream.setCloseStream(false); + stream.close(); + }); + } + + @Test + public void assignBytesArrayTest() throws IOException { + //the data is random + byte[] expected = new byte[] {(byte) 15, (byte) 233, (byte) 58, (byte) 97}; + try (ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + OutputStream stream + = new OutputStream<>(bytes)) { + stream.assignBytes(expected, 4); + Assert.assertArrayEquals(expected, bytes.toByteArray()); + } + } + + @Test + public void assignBytesExceptionTest() throws IOException { + //Testing that the exception is thrown, not using specific one because of .NET compatability + Assert.assertThrows(Exception.class,() -> { + //the data is random + byte[] bytes = new byte[] {(byte) 15, (byte) 233, (byte) 58, (byte) 97}; + try (java.io.OutputStream outputStream = IO_EXCEPTION_OUTPUT_STREAM; + OutputStream stream + = new OutputStream<>(outputStream)) { + stream.assignBytes(bytes, 4); + } + }); + } + + @Test + public void resetTestNoException() throws IOException { + AssertUtil.doesNotThrow(() -> { + try (ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + OutputStream stream + = new OutputStream<>(bytes)) { + stream.writeBytes(new byte[] {(byte) 15, (byte) 233, (byte) 58, (byte) 97}); + stream.flush(); + stream.reset(); + } + }); + } + + @Test + public void resetExceptionTest() throws IOException { + //Testing that the exception is thrown, not using specific one because of .NET compatability + Assert.assertThrows(Exception.class,() -> { + try (java.io.OutputStream bytes = IO_EXCEPTION_OUTPUT_STREAM; + OutputStream stream + = new OutputStream<>(bytes)) { + stream.reset(); + } + }); + } + + @Test + public void localHighPrecisionOverridesGlobalTest() throws IOException { + //the data is random + double numberToWrite = 2.000002d; + try (ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + OutputStream stream + = new OutputStream<>(bytes, false)) { + OutputStream.setHighPrecision(true); + stream.setLocalHighPrecision(false); + stream.writeDouble(numberToWrite); + stream.flush(); + Assert.assertEquals("2", new String(bytes.toByteArray(), StandardCharsets.UTF_8)); + } + } +} diff --git a/io/src/test/java/com/itextpdf/io/util/ImageMagickHelperTest.java b/io/src/test/java/com/itextpdf/io/util/ImageMagickHelperTest.java index 9f74642db5..ef771df384 100644 --- a/io/src/test/java/com/itextpdf/io/util/ImageMagickHelperTest.java +++ b/io/src/test/java/com/itextpdf/io/util/ImageMagickHelperTest.java @@ -51,6 +51,8 @@ This file is part of the iText (R) project. import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintStream; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -349,4 +351,81 @@ public void compareEqualsImagesAndCheckFuzzinessTest() { } } + @Test + public void compareEqualImagesAndGetResult() throws InterruptedException, IOException { + String image = SOURCE_FOLDER + "image.png"; + String diff = DESTINATION_FOLDER + "diff_equalImages_result.png"; + + ImageMagickCompareResult result = new ImageMagickHelper().runImageMagickImageCompareAndGetResult( + image, + image, + diff, + "1"); + + Assert.assertTrue(result.isComparingResultSuccessful()); + Assert.assertEquals(0, result.getDiffPixels()); + } + + @Test + public void compareDifferentImagesAndGetResult() throws InterruptedException, IOException { + String image = SOURCE_FOLDER + "image.png"; + String image2 = SOURCE_FOLDER + "Im1_1.jpg"; + String diff = DESTINATION_FOLDER + "diff_equalImages.png"; + + ImageMagickCompareResult result = new ImageMagickHelper().runImageMagickImageCompareAndGetResult( + image, + image2, + diff, "1"); + + Assert.assertFalse(result.isComparingResultSuccessful()); + } + + @Test + public void runImageMagickImageCompareEqualWithThreshold() throws IOException, InterruptedException { + String image = SOURCE_FOLDER + "image.png"; + String image2 = SOURCE_FOLDER + "image.png"; + String diff = DESTINATION_FOLDER + "diff_equalImages.png"; + + boolean result = new ImageMagickHelper().runImageMagickImageCompareWithThreshold( + image, + image2, + diff, + "0", + 0); + + Assert.assertTrue(result); + } + + @Test + public void runImageMagickImageCompareWithEnoughThreshold() throws IOException, InterruptedException { + String image = SOURCE_FOLDER + "image.png"; + String image2 = SOURCE_FOLDER + "Im1_1.jpg"; + String diff = DESTINATION_FOLDER + "diff_equalImages.png"; + + boolean result = new ImageMagickHelper().runImageMagickImageCompareWithThreshold( + image, + image2, + diff, + "20", + 2000000); + + Assert.assertTrue(result); + } + + @Test + public void runImageMagickImageCompareWithNotEnoughThreshold() throws IOException, InterruptedException { + String image = SOURCE_FOLDER + "image.png"; + String image2 = SOURCE_FOLDER + "Im1_1.jpg"; + String diff = DESTINATION_FOLDER + "diff_equalImages.png"; + + boolean result = new ImageMagickHelper().runImageMagickImageCompareWithThreshold( + image, + image2, + diff, + "20", + 2000); + + Assert.assertFalse(result); + } + } diff --git a/io/src/test/java/com/itextpdf/io/util/UrlUtilTest.java b/io/src/test/java/com/itextpdf/io/util/UrlUtilTest.java index 3713bcca90..30e8ffb202 100644 --- a/io/src/test/java/com/itextpdf/io/util/UrlUtilTest.java +++ b/io/src/test/java/com/itextpdf/io/util/UrlUtilTest.java @@ -45,9 +45,13 @@ This file is part of the iText (R) project. import com.itextpdf.commons.utils.FileUtil; import com.itextpdf.test.ExtendedITextTest; import com.itextpdf.test.annotations.type.UnitTest; + import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; +import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; import java.nio.file.Paths; import org.junit.Assert; @@ -65,7 +69,9 @@ public static void beforeClass() { createDestinationFolder(destinationFolder); } - // Tests that after invocation of the getFinalURL method for local files, no handles are left open and the file is free to be removed + + // Tests that after invocation of the getFinalURL method for local files, no handles are left open and the file + // is free to be removed. @Test public void getFinalURLDoesNotLockFileTest() throws IOException { File tempFile = FileUtil.createTempFile(destinationFolder); @@ -75,6 +81,44 @@ public void getFinalURLDoesNotLockFileTest() throws IOException { Assert.assertTrue(FileUtil.deleteFile(tempFile)); } + // Tests, that getFinalConnection will be redirected some times for other urls, and initialUrl will be different + // from final url. + @Test + public void getFinalConnectionWhileRedirectingTest() throws IOException { + URL initialUrl = new URL("http://itextpdf.com"); + URL expectedURL = new URL("https://itextpdf.com/en"); + URLConnection finalConnection = null; + + try { + finalConnection = UrlUtil.getFinalConnection(initialUrl); + + Assert.assertNotNull(finalConnection); + Assert.assertNotEquals(initialUrl, finalConnection.getURL()); + Assert.assertEquals(expectedURL, finalConnection.getURL()); + } finally { + finalConnection.getInputStream().close(); + } + } + + // This test checks that when we pass invalid url and trying get stream related to final redirected url,exception + // would be thrown. + @Test + public void getInputStreamOfFinalConnectionThrowExceptionTest() throws IOException { + URL invalidUrl = new URL("http://itextpdf"); + + Assert.assertThrows(UnknownHostException.class, () -> UrlUtil.getInputStreamOfFinalConnection(invalidUrl)); + } + + // This test checks that when we pass valid url and trying get stream related to final redirected url, it would + // not be null. + @Test + public void getInputStreamOfFinalConnectionTest() throws IOException { + URL initialUrl = new URL("http://itextpdf.com"); + InputStream streamOfFinalConnectionOfInvalidUrl = UrlUtil.getInputStreamOfFinalConnection(initialUrl); + + Assert.assertNotNull(streamOfFinalConnectionOfInvalidUrl); + } + @Test public void getBaseUriTest() throws IOException { String absolutePathRoot = Paths.get("").toAbsolutePath().toUri().toURL().toExternalForm(); diff --git a/io/src/test/resources/com/itextpdf/io/source/OSTEST.txt b/io/src/test/resources/com/itextpdf/io/source/OSTEST.txt new file mode 100644 index 0000000000..5dd01c177f --- /dev/null +++ b/io/src/test/resources/com/itextpdf/io/source/OSTEST.txt @@ -0,0 +1 @@ +Hello, world! \ No newline at end of file diff --git a/itextcore/pom.xml b/itextcore/pom.xml index 111811a53e..4f0c76ed3b 100644 --- a/itextcore/pom.xml +++ b/itextcore/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.itextpdf itext7-core - 7.2.0 + 7.2.1 pom iText 7 Core A Free Java-PDF library diff --git a/kernel/pom.xml b/kernel/pom.xml index 356567bdeb..22872f401b 100644 --- a/kernel/pom.xml +++ b/kernel/pom.xml @@ -4,7 +4,7 @@ com.itextpdf root - 7.2.0 + 7.2.1 kernel iText 7 - kernel diff --git a/kernel/src/main/java/com/itextpdf/kernel/actions/data/ITextCoreProductData.java b/kernel/src/main/java/com/itextpdf/kernel/actions/data/ITextCoreProductData.java index 038639633b..7578ebd841 100644 --- a/kernel/src/main/java/com/itextpdf/kernel/actions/data/ITextCoreProductData.java +++ b/kernel/src/main/java/com/itextpdf/kernel/actions/data/ITextCoreProductData.java @@ -30,7 +30,7 @@ This file is part of the iText (R) project. */ public final class ITextCoreProductData { private static final String CORE_PUBLIC_PRODUCT_NAME = "Core"; - private static final String CORE_VERSION = "7.2.0"; + private static final String CORE_VERSION = "7.2.1"; private static final int CORE_COPYRIGHT_SINCE = 2000; private static final int CORE_COPYRIGHT_TO = 2021; diff --git a/kernel/src/main/java/com/itextpdf/kernel/crypto/CryptoUtil.java b/kernel/src/main/java/com/itextpdf/kernel/crypto/CryptoUtil.java index 92db7d0d81..ef54e5b978 100644 --- a/kernel/src/main/java/com/itextpdf/kernel/crypto/CryptoUtil.java +++ b/kernel/src/main/java/com/itextpdf/kernel/crypto/CryptoUtil.java @@ -42,20 +42,31 @@ This file is part of the iText (R) project. */ package com.itextpdf.kernel.crypto; +import com.itextpdf.commons.utils.MessageFormatUtil; +import com.itextpdf.kernel.exceptions.KernelExceptionMessageConstant; + import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.PrivateKey; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1OutputStream; /** * This file is a helper class for internal usage only. - * Be aware that it's API and functionality may be changed in future. + * Be aware that it's API and functionality may be changed in the future. */ public class CryptoUtil { + + private CryptoUtil() { + + } + public static Certificate readPublicCertificate(InputStream is) throws CertificateException { return CertificateFactory.getInstance("X.509").generateCertificate(is); } @@ -65,4 +76,22 @@ public static PrivateKey readPrivateKeyFromPKCS12KeyStore(InputStream keyStore, keystore.load(keyStore, pkPassword); return (PrivateKey) keystore.getKey(pkAlias, pkPassword); } + + /** + * Creates {@link ASN1OutputStream} instance and asserts for unexpected ASN1 encodings. + * + * @param outputStream the underlying stream + * @param asn1Encoding ASN1 encoding that will be used for writing. Only DER and BER are allowed as values. + * See also {@link ASN1Encoding}. + * + * @return an {@link ASN1OutputStream} instance. Exact stream implementation is chosen based on passed encoding. + */ + public static ASN1OutputStream createAsn1OutputStream(OutputStream outputStream, String asn1Encoding) { + if (!ASN1Encoding.DER.equals(asn1Encoding) && !ASN1Encoding.BER.equals(asn1Encoding)) { + throw new UnsupportedOperationException( + MessageFormatUtil.format(KernelExceptionMessageConstant.UNSUPPORTED_ASN1_ENCODING, asn1Encoding) + ); + } + return ASN1OutputStream.create(outputStream, asn1Encoding); + } } diff --git a/kernel/src/main/java/com/itextpdf/kernel/crypto/securityhandler/PubKeySecurityHandler.java b/kernel/src/main/java/com/itextpdf/kernel/crypto/securityhandler/PubKeySecurityHandler.java index 4e6c6e30a8..f82f090486 100644 --- a/kernel/src/main/java/com/itextpdf/kernel/crypto/securityhandler/PubKeySecurityHandler.java +++ b/kernel/src/main/java/com/itextpdf/kernel/crypto/securityhandler/PubKeySecurityHandler.java @@ -44,13 +44,27 @@ This file is part of the iText (R) project. package com.itextpdf.kernel.crypto.securityhandler; import com.itextpdf.io.util.StreamUtil; -import com.itextpdf.kernel.exceptions.PdfException; +import com.itextpdf.kernel.crypto.CryptoUtil; import com.itextpdf.kernel.exceptions.KernelExceptionMessageConstant; +import com.itextpdf.kernel.exceptions.PdfException; import com.itextpdf.kernel.pdf.PdfArray; import com.itextpdf.kernel.pdf.PdfDictionary; import com.itextpdf.kernel.pdf.PdfLiteral; import com.itextpdf.kernel.pdf.PdfName; import com.itextpdf.kernel.security.IExternalDecryptionProcess; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.Key; +import java.security.MessageDigest; +import java.security.PrivateKey; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; +import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1OutputStream; import org.bouncycastle.asn1.ASN1Primitive; @@ -68,18 +82,6 @@ This file is part of the iText (R) project. import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.TBSCertificateStructure; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.security.Key; -import java.security.MessageDigest; -import java.security.PrivateKey; -import java.security.cert.Certificate; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.List; - /** * @author Aiken Sam (aikensam@ieee.org) */ @@ -250,7 +252,7 @@ private byte[] getEncodedRecipient(int index) throws IOException, GeneralSecurit pkcs7input[23] = one; ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ASN1OutputStream k = ASN1OutputStream.create(baos); + ASN1OutputStream k = CryptoUtil.createAsn1OutputStream(baos, ASN1Encoding.DER); ASN1Primitive obj = createDERForRecipient(pkcs7input, (X509Certificate) certificate); k.writeObject(obj); cms = baos.toByteArray(); diff --git a/kernel/src/main/java/com/itextpdf/kernel/exceptions/KernelExceptionMessageConstant.java b/kernel/src/main/java/com/itextpdf/kernel/exceptions/KernelExceptionMessageConstant.java index d3169bdcf0..3099c5ba42 100644 --- a/kernel/src/main/java/com/itextpdf/kernel/exceptions/KernelExceptionMessageConstant.java +++ b/kernel/src/main/java/com/itextpdf/kernel/exceptions/KernelExceptionMessageConstant.java @@ -29,20 +29,20 @@ public final class KernelExceptionMessageConstant { public static final String AMOUNT_OF_BYTES_LESS_THAN_ZERO = "Amount of bytes in the PDF document cannot be less than zero"; public static final String ANNOTATION_SHALL_HAVE_REFERENCE_TO_PAGE = "Annotation shall have reference to page."; - public static final String APPEND_MODE_REQUIRES_A_DOCUMENT_WITHOUT_ERRORS_EVEN_IF_RECOVERY_IS_POSSIBLE = "Append " - + "mode requires a document without errors, even if recovery is possible."; + public static final String APPEND_MODE_REQUIRES_A_DOCUMENT_WITHOUT_ERRORS_EVEN_IF_RECOVERY_IS_POSSIBLE = + "Append mode requires a document without errors, even if recovery is possible."; public static final String BAD_CERTIFICATE_AND_KEY = "Bad public key certificate and/or private key."; - public static final String BAD_USER_PASSWORD = "Bad user password. Password is not provided or wrong password " - + "provided. Correct password should be passed to PdfReader constructor with properties. " - + "See ReaderProperties#setPassword() method."; + public static final String BAD_USER_PASSWORD = + "Bad user password. Password is not provided or wrong password provided. Correct password should be passed " + + "to PdfReader constructor with properties. See ReaderProperties#setPassword() method."; public static final String CANNOT_ADD_KID_TO_THE_FLUSHED_ELEMENT = "Cannot add kid to the flushed element."; - public static final String CANNOT_BE_EMBEDDED_DUE_TO_LICENSING_RESTRICTIONS = "{0} cannot be embedded due to " - + "licensing restrictions."; + public static final String CANNOT_BE_EMBEDDED_DUE_TO_LICENSING_RESTRICTIONS = + "{0} cannot be embedded due to licensing restrictions."; public static final String CANNOT_CLOSE_DOCUMENT = "Cannot close document."; - public static final String CANNOT_CLOSE_DOCUMENT_WITH_ALREADY_FLUSHED_PDF_CATALOG = "Cannot close document with " - + "already flushed PDF Catalog."; - public static final String CANNOT_CONVERT_PDF_ARRAY_TO_AN_ARRAY_OF_BOOLEANS = "Cannot convert PdfArray to an " - + "array of booleans"; + public static final String CANNOT_CLOSE_DOCUMENT_WITH_ALREADY_FLUSHED_PDF_CATALOG = + "Cannot close document with already flushed PDF Catalog."; + public static final String CANNOT_CONVERT_PDF_ARRAY_TO_AN_ARRAY_OF_BOOLEANS = + "Cannot convert PdfArray to an array of booleans"; public static final String CANNOT_CONVERT_PDF_ARRAY_TO_DOUBLE_ARRAY = "Cannot convert PdfArray to an array " + "of doubles."; public static final String CANNOT_CONVERT_PDF_ARRAY_TO_INT_ARRAY = "Cannot convert PdfArray to an array " @@ -122,6 +122,9 @@ public final class KernelExceptionMessageConstant { public static final String CONTENT_STREAM_MUST_NOT_INVOKE_OPERATORS_THAT_SPECIFY_COLORS_OR_OTHER_COLOR_RELATED_PARAMETERS = "Content stream must not invoke operators that specify colors or other color related parameters in " + "the graphics state."; + public static final String CORRUPTED_OUTLINE_DICTIONARY_HAS_INFINITE_LOOP = + "Document outline dictionary is corrupted: some outline (PDF object: \"{0}\") has wrong first/next link " + + "entry."; public static final String CORRUPTED_OUTLINE_NO_PARENT_ENTRY = "Document outline is corrupted: some outline (PDF object: \"{0}\") lacks the required parent entry."; public static final String CORRUPTED_OUTLINE_NO_TITLE_ENTRY = @@ -315,10 +318,12 @@ public final class KernelExceptionMessageConstant { public static final String UNKNOWN_ENCRYPTION_TYPE_V = "Unknown encryption type V == {0}."; public static final String UNKNOWN_GRAPHICS_STATE_DICTIONARY = "{0} is an unknown graphics state dictionary."; public static final String UNKNOWN_PDF_EXCEPTION = "Unknown PdfException."; + public static final String UNSUPPORTED_ASN1_ENCODING = + "Unknown ASN1-encoding {0}. Only DER and BER encodings are supported!"; public static final String UNSUPPORTED_FONT_EMBEDDING_STRATEGY = "Unsupported font embedding strategy."; public static final String UNSUPPORTED_XOBJECT_TYPE = "Unsupported XObject type."; - public static final String WHEN_ADDING_OBJECT_REFERENCE_TO_THE_TAG_TREE_IT_MUST_BE_CONNECTED_TO_NOT_FLUSHED_OBJECT = "" - + "When adding object reference to the tag tree, it must be connected to not flushed object."; + public static final String WHEN_ADDING_OBJECT_REFERENCE_TO_THE_TAG_TREE_IT_MUST_BE_CONNECTED_TO_NOT_FLUSHED_OBJECT = + "When adding object reference to the tag tree, it must be connected to not flushed object."; public static final String WHITE_POINT_IS_INCORRECTLY_SPECIFIED = "White point is incorrectly specified."; public static final String WMF_IMAGE_EXCEPTION = "WMF image exception."; public static final String WRONG_MEDIA_BOX_SIZE_TOO_FEW_ARGUMENTS = "Wrong media box size: {0}. Need at least 4 " diff --git a/kernel/src/main/java/com/itextpdf/kernel/font/PdfType0Font.java b/kernel/src/main/java/com/itextpdf/kernel/font/PdfType0Font.java index b46ba35653..109c4c9e4f 100644 --- a/kernel/src/main/java/com/itextpdf/kernel/font/PdfType0Font.java +++ b/kernel/src/main/java/com/itextpdf/kernel/font/PdfType0Font.java @@ -451,6 +451,8 @@ private int appendUniGlyphs(String text, int from, int to, List glyphs) { if (TextUtil.isSurrogatePair(text, k)) { val = TextUtil.convertToUtf32(text, k); processed += 2; + // Since a pair is processed, need to skip next char as well + k += 1; } else { val = text.charAt(k); processed++; diff --git a/kernel/src/main/java/com/itextpdf/kernel/font/PdfType3Font.java b/kernel/src/main/java/com/itextpdf/kernel/font/PdfType3Font.java index f27434587c..1d6f4496f3 100644 --- a/kernel/src/main/java/com/itextpdf/kernel/font/PdfType3Font.java +++ b/kernel/src/main/java/com/itextpdf/kernel/font/PdfType3Font.java @@ -444,6 +444,8 @@ private void addGlyphsFromDifferences(PdfArray differences, PdfDictionary charPr PdfObject obj = differences.get(k); if (obj.isNumber()) { currentNumber = ((PdfNumber) obj).intValue(); + } else if (currentNumber > SIMPLE_FONT_MAX_CHAR_CODE_VALUE) { + // Skip glyphs with id greater than 255 } else { String glyphName = ((PdfName) obj).getValue(); int unicode = fontEncoding.getUnicode(currentNumber); diff --git a/kernel/src/main/java/com/itextpdf/kernel/logs/KernelLogMessageConstant.java b/kernel/src/main/java/com/itextpdf/kernel/logs/KernelLogMessageConstant.java index 980cc29095..71ad08a8c1 100644 --- a/kernel/src/main/java/com/itextpdf/kernel/logs/KernelLogMessageConstant.java +++ b/kernel/src/main/java/com/itextpdf/kernel/logs/KernelLogMessageConstant.java @@ -48,6 +48,10 @@ This file is part of the iText (R) project. */ public final class KernelLogMessageConstant { + public static final String CORRUPTED_OUTLINE_DICTIONARY_HAS_INFINITE_LOOP = + "Document outline dictionary is corrupted: some outline (PDF object: \"{0}\") has wrong first/next link " + + "entry. Next outlines in this dictionary will be unprocessed."; + public static final String DCTDECODE_FILTER_DECODING = "DCTDecode filter decoding into the bit map is not supported. The stream data would be left in JPEG " + "baseline format"; diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/OcgPropertiesCopier.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/OcgPropertiesCopier.java index b10a19eb02..534a253f27 100644 --- a/kernel/src/main/java/com/itextpdf/kernel/pdf/OcgPropertiesCopier.java +++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/OcgPropertiesCopier.java @@ -115,24 +115,25 @@ private static Set getAllUsedNonFlushedOCGs(Map()); OcgPropertiesCopier.getUsedNonFlushedOCGsFromXObject(toAnnot.getRolloverAppearanceObject(), - fromAnnot.getRolloverAppearanceObject(), fromUsedOcgs, toOcProperties); + fromAnnot.getRolloverAppearanceObject(), fromUsedOcgs, toOcProperties, new HashSet<>()); OcgPropertiesCopier.getUsedNonFlushedOCGsFromXObject(toAnnot.getDownAppearanceObject(), - fromAnnot.getDownAppearanceObject(), fromUsedOcgs, toOcProperties); + fromAnnot.getDownAppearanceObject(), fromUsedOcgs, toOcProperties, new HashSet<>()); } } } final PdfDictionary toResources = toPage.getPdfObject().getAsDictionary(PdfName.Resources); final PdfDictionary fromResources = fromPage.getPdfObject().getAsDictionary(PdfName.Resources); - OcgPropertiesCopier.getUsedNonFlushedOCGsFromResources(toResources, fromResources, fromUsedOcgs, toOcProperties); + OcgPropertiesCopier.getUsedNonFlushedOCGsFromResources(toResources, fromResources, fromUsedOcgs, + toOcProperties, new HashSet<>()); } return fromUsedOcgs; } private static void getUsedNonFlushedOCGsFromResources(PdfDictionary toResources, PdfDictionary fromResources, - Set fromUsedOcgs, PdfDictionary toOcProperties) { + Set fromUsedOcgs, PdfDictionary toOcProperties, Set visitedObjects) { if (toResources != null && !toResources.isFlushed()) { // Copy OCGs from properties final PdfDictionary toProperties = toResources.getAsDictionary(PdfName.Properties); @@ -148,12 +149,19 @@ private static void getUsedNonFlushedOCGsFromResources(PdfDictionary toResources // Copy OCGs from xObject final PdfDictionary toXObject = toResources.getAsDictionary(PdfName.XObject); final PdfDictionary fromXObject = fromResources.getAsDictionary(PdfName.XObject); - OcgPropertiesCopier.getUsedNonFlushedOCGsFromXObject(toXObject, fromXObject, fromUsedOcgs, toOcProperties); + OcgPropertiesCopier.getUsedNonFlushedOCGsFromXObject(toXObject, fromXObject, fromUsedOcgs, toOcProperties, + visitedObjects); } } private static void getUsedNonFlushedOCGsFromXObject(PdfDictionary toXObject, PdfDictionary fromXObject, - Set fromUsedOcgs, PdfDictionary toOcProperties) { + Set fromUsedOcgs, PdfDictionary toOcProperties, Set visitedObjects) { + //Resolving cycled properties, by memorizing the visited objects + if (visitedObjects.contains(fromXObject)) { + return; + } + visitedObjects.add(fromXObject); + if (toXObject != null && !toXObject.isFlushed()) { if (toXObject.isStream() && !toXObject.isFlushed()) { final PdfStream toStream = (PdfStream) toXObject; @@ -161,7 +169,7 @@ private static void getUsedNonFlushedOCGsFromXObject(PdfDictionary toXObject, Pd OcgPropertiesCopier.getUsedNonFlushedOCGsFromOcDict(toStream.getAsDictionary(PdfName.OC), fromStream.getAsDictionary(PdfName.OC), fromUsedOcgs, toOcProperties); OcgPropertiesCopier.getUsedNonFlushedOCGsFromResources(toStream.getAsDictionary(PdfName.Resources), - fromStream.getAsDictionary(PdfName.Resources), fromUsedOcgs, toOcProperties); + fromStream.getAsDictionary(PdfName.Resources), fromUsedOcgs, toOcProperties, visitedObjects); } else { for (final PdfName name : toXObject.keySet()) { final PdfObject toCurrObj = toXObject.get(name); @@ -169,7 +177,8 @@ private static void getUsedNonFlushedOCGsFromXObject(PdfDictionary toXObject, Pd if (toCurrObj.isStream() && !toCurrObj.isFlushed()) { final PdfStream toStream = (PdfStream) toCurrObj; final PdfStream fromStream = (PdfStream) fromCurrObj; - OcgPropertiesCopier.getUsedNonFlushedOCGsFromXObject(toStream, fromStream, fromUsedOcgs, toOcProperties); + OcgPropertiesCopier.getUsedNonFlushedOCGsFromXObject(toStream, fromStream, fromUsedOcgs, + toOcProperties, visitedObjects); } } } diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfCatalog.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfCatalog.java index a6c9ee3aff..39d086d554 100644 --- a/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfCatalog.java +++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfCatalog.java @@ -47,6 +47,8 @@ This file is part of the iText (R) project. import com.itextpdf.commons.utils.MessageFormatUtil; import com.itextpdf.kernel.exceptions.PdfException; import com.itextpdf.kernel.exceptions.KernelExceptionMessageConstant; +import com.itextpdf.kernel.logs.KernelLogMessageConstant; +import com.itextpdf.kernel.pdf.PdfReader.StrictnessLevel; import com.itextpdf.kernel.pdf.action.PdfAction; import com.itextpdf.kernel.pdf.collection.PdfCollection; import com.itextpdf.kernel.pdf.layer.PdfOCProperties; @@ -91,7 +93,7 @@ public class PdfCatalog extends PdfObjectWrapper { */ protected PdfOCProperties ocProperties; - private static final String OutlineRoot = "Outlines"; + private static final String ROOT_OUTLINE_TITLE = "Outlines"; private PdfOutline outlines; @@ -561,6 +563,91 @@ void addRootOutline(PdfOutline outline) { } } + /** + * Construct {@link PdfCatalog dictionary} iteratively. Invalid pdf documents will be processed depending on {@link + * StrictnessLevel}, if it set to lenient, we will ignore and process invalid outline structure, otherwise {@link + * PdfException} will be thrown. + * + * @param outlineRoot {@link PdfOutline dictionary} root. + * @param names map containing the PdfObjects stored in the tree. + */ + void constructOutlines(PdfDictionary outlineRoot, Map names) { + if (outlineRoot == null) { + return; + } + + PdfReader reader = getDocument().getReader(); + final boolean isLenientLevel = + reader == null || StrictnessLevel.CONSERVATIVE.isStricter(reader.getStrictnessLevel()); + PdfDictionary current = outlineRoot.getAsDictionary(PdfName.First); + + outlines = new PdfOutline(ROOT_OUTLINE_TITLE, outlineRoot, getDocument()); + PdfOutline parentOutline = outlines; + + Map nextUnprocessedChildForParentMap = new HashMap<>(); + Set alreadyVisitedOutlinesSet = new HashSet<>(); + + while (current != null) { + PdfDictionary parent = current.getAsDictionary(PdfName.Parent); + if (null == parent && !isLenientLevel) { + throw new PdfException( + MessageFormatUtil.format( + KernelExceptionMessageConstant.CORRUPTED_OUTLINE_NO_PARENT_ENTRY, + current.indirectReference)); + } + PdfString title = current.getAsString(PdfName.Title); + if (null == title) { + throw new PdfException( + MessageFormatUtil.format( + KernelExceptionMessageConstant.CORRUPTED_OUTLINE_NO_TITLE_ENTRY, + current.indirectReference)); + } + PdfOutline currentOutline = new PdfOutline(title.toUnicodeString(), current, parentOutline); + alreadyVisitedOutlinesSet.add(current); + addOutlineToPage(currentOutline, current, names); + parentOutline.getAllChildren().add(currentOutline); + + PdfDictionary first = current.getAsDictionary(PdfName.First); + PdfDictionary next = current.getAsDictionary(PdfName.Next); + if (first != null) { + if (alreadyVisitedOutlinesSet.contains(first)) { + if (!isLenientLevel) { + throw new PdfException(MessageFormatUtil.format( + KernelExceptionMessageConstant.CORRUPTED_OUTLINE_DICTIONARY_HAS_INFINITE_LOOP, first)); + } + LOGGER.warn(MessageFormatUtil.format( + KernelLogMessageConstant.CORRUPTED_OUTLINE_DICTIONARY_HAS_INFINITE_LOOP, first)); + return; + } + // Down in hierarchy; when returning up, process `next`. + nextUnprocessedChildForParentMap.put(parentOutline, next); + parentOutline = currentOutline; + current = first; + } else if (next != null) { + if (alreadyVisitedOutlinesSet.contains(next)) { + if (!isLenientLevel) { + throw new PdfException(MessageFormatUtil.format( + KernelExceptionMessageConstant.CORRUPTED_OUTLINE_DICTIONARY_HAS_INFINITE_LOOP, next)); + } + LOGGER.warn(MessageFormatUtil.format( + KernelLogMessageConstant.CORRUPTED_OUTLINE_DICTIONARY_HAS_INFINITE_LOOP, next)); + return; + } + // Next sibling in hierarchy + current = next; + } else { + // Up in hierarchy using 'nextUnprocessedChildForParentMap'. + current = null; + while (current == null && parentOutline != null) { + parentOutline = parentOutline.getParent(); + if (parentOutline != null) { + current = nextUnprocessedChildForParentMap.get(parentOutline); + } + } + } + } + } + PdfDestination copyDestination(PdfObject dest, Map page2page, PdfDocument toDocument) { if (null == dest) { return null; @@ -658,46 +745,6 @@ private void addOutlineToPage(PdfOutline outline, Map names) } } - /** - * Get the next outline of the current node in the outline tree by looking for a child or sibling node. - * If there is no child or sibling of the current node {@link PdfCatalog#getParentNextOutline(PdfDictionary)} is called to get a hierarchical parent's next node. {@code null} is returned if one does not exist. - * - * @return the {@link PdfDictionary} object of the next outline if one exists, {@code null} otherwise. - */ - private PdfDictionary getNextOutline(PdfDictionary first, PdfDictionary next, PdfDictionary parent) { - if (first != null) { - return first; - } else if (next != null) { - return next; - } else { - return getParentNextOutline(parent); - } - - } - - /** - * Gets the parent's next outline of the current node. - * If the parent does not have a next we look at the grand parent, great-grand parent, etc until we find a next node or reach the root at which point {@code null} is returned to signify there is no next node present. - * - * @return the {@link PdfDictionary} object of the next outline if one exists, {@code null} otherwise. - */ - private PdfDictionary getParentNextOutline(PdfDictionary parent) { - if (parent == null) { - return null; - } - PdfDictionary current = null; - while (current == null) { - current = parent.getAsDictionary(PdfName.Next); - if (current == null) { - parent = parent.getAsDictionary(PdfName.Parent); - if (parent == null) { - return null; - } - } - } - return current; - } - private void addOutlineToPage(PdfOutline outline, PdfDictionary item, Map names) { PdfObject dest = item.get(PdfName.Dest); if (dest != null) { @@ -723,48 +770,4 @@ private void addOutlineToPage(PdfOutline outline, PdfDictionary item, Map names) { - if (outlineRoot == null) { - return; - } - PdfDictionary first = outlineRoot.getAsDictionary(PdfName.First); - PdfDictionary current = first; - HashMap parentOutlineMap = new HashMap<>(); - - outlines = new PdfOutline(OutlineRoot, outlineRoot, getDocument()); - PdfOutline parentOutline = outlines; - parentOutlineMap.put(outlineRoot, parentOutline); - - while (current != null) { - first = current.getAsDictionary(PdfName.First); - PdfDictionary next = current.getAsDictionary(PdfName.Next); - PdfDictionary parent = current.getAsDictionary(PdfName.Parent); - if (null == parent) { - throw new PdfException( - MessageFormatUtil.format( - KernelExceptionMessageConstant.CORRUPTED_OUTLINE_NO_PARENT_ENTRY, - current.indirectReference)); - } - PdfString title = current.getAsString(PdfName.Title); - if (null == title) { - throw new PdfException( - MessageFormatUtil.format( - KernelExceptionMessageConstant.CORRUPTED_OUTLINE_NO_TITLE_ENTRY, - current.indirectReference)); - } - parentOutline = parentOutlineMap.get(parent); - PdfOutline currentOutline = new PdfOutline(title.toUnicodeString(), current, parentOutline); - addOutlineToPage(currentOutline, current, names); - parentOutline.getAllChildren().add(currentOutline); - - if (first != null) { - parentOutlineMap.put(current, currentOutline); - } - current = getNextOutline(first, next, parent); - } - } } diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfDocument.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfDocument.java index fb446d59f2..bd506debf8 100644 --- a/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfDocument.java +++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfDocument.java @@ -55,6 +55,7 @@ This file is part of the iText (R) project. import com.itextpdf.kernel.actions.data.ITextCoreProductData; import com.itextpdf.kernel.actions.events.FlushPdfDocumentEvent; import com.itextpdf.kernel.actions.events.ITextCoreProductEvent; +import com.itextpdf.kernel.colors.Color; import com.itextpdf.kernel.events.EventDispatcher; import com.itextpdf.kernel.events.IEventDispatcher; import com.itextpdf.kernel.events.PdfDocumentEvent; @@ -954,7 +955,10 @@ public void close() { } for (int pageNum = 1; pageNum <= getNumberOfPages(); pageNum++) { - getPage(pageNum).flush(); + PdfPage page = getPage(pageNum); + if (page != null) { + page.flush(); + } } if (structTreeRoot != null) { tryFlushTagStructure(false); @@ -2405,6 +2409,15 @@ private void cloneOutlines(Set outlinesToCopy, PdfOutline newParent, if (copiedDest != null) { child.addDestination(copiedDest); } + Integer copiedStyle = outline.getStyle(); + if (copiedStyle != null) { + child.setStyle(copiedStyle.intValue()); + } + Color copiedColor = outline.getColor(); + if (copiedColor != null) { + child.setColor(copiedColor); + } + child.setOpen(outline.isOpen()); cloneOutlines(outlinesToCopy, child, outline, page2page, toDocument); } diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfOutline.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfOutline.java index 2efd532298..8200fe2280 100644 --- a/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfOutline.java +++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfOutline.java @@ -46,6 +46,7 @@ This file is part of the iText (R) project. import com.itextpdf.io.font.PdfEncodings; import com.itextpdf.kernel.colors.Color; import com.itextpdf.kernel.pdf.action.PdfAction; +import com.itextpdf.kernel.pdf.colorspace.PdfColorSpace; import com.itextpdf.kernel.pdf.navigation.PdfDestination; import java.util.ArrayList; @@ -143,6 +144,21 @@ public void setColor(Color color) { content.put(PdfName.C, new PdfArray(color.getColorValue())); } + /** + * Gets color for the outline entry's text, {@code C} key. + * + * @return color {@link Color}. + */ + public Color getColor() { + PdfArray colorArray = content.getAsArray(PdfName.C); + if (colorArray == null) { + return null; + } else { + return Color.makeColor(PdfColorSpace.makeColorSpace(PdfName.DeviceRGB), + colorArray.toFloatArray()); + } + } + /** * Sets text style for the outline entry’s text, {@code F} key. * @@ -154,6 +170,15 @@ public void setStyle(int style) { } } + /** + * Gets text style for the outline entry's text, {@code F} key. + * + * @return style value. + */ + public Integer getStyle() { + return content.getAsInt(PdfName.F); + } + /** * Gets content dictionary. * @@ -224,6 +249,16 @@ else if (children.size() > 0) content.remove(PdfName.Count); } + /** + * Defines if the outline is open or closed. + * + * @return true if open,false otherwise. + */ + public boolean isOpen() { + Integer count = content.getAsInt(PdfName.Count); + return count == null || count >= 0; + } + /** * Adds a new {@code PdfOutline} with specified parameters as a child to existing {@code PdfOutline} * and put it to specified position in the existing {@code PdfOutline} children list. diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfPagesTree.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfPagesTree.java index 6eb592ce69..b034d6cfb9 100644 --- a/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfPagesTree.java +++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfPagesTree.java @@ -47,6 +47,9 @@ This file is part of the iText (R) project. import com.itextpdf.commons.utils.MessageFormatUtil; import com.itextpdf.kernel.exceptions.PdfException; import com.itextpdf.kernel.exceptions.KernelExceptionMessageConstant; + +import java.util.HashSet; +import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -337,6 +340,17 @@ protected PdfPages findPageParent(PdfPage pdfPage) { } private void loadPage(int pageNum) { + loadPage(pageNum, new HashSet<>()); + } + + /** + * Load page from pages tree node structure + * + * @param pageNum page number to load + * @param processedParents set with already processed parents object reference numbers + * if this method was called recursively to avoid infinite recursion. + */ + private void loadPage(int pageNum, Set processedParents) { PdfIndirectReference targetPage = pageRefs.get(pageNum); if (targetPage != null) return; @@ -344,6 +358,15 @@ private void loadPage(int pageNum) { //if we go here, we have to split PdfPages that contains pageNum int parentIndex = findPageParent(pageNum); PdfPages parent = parents.get(parentIndex); + PdfIndirectReference parentIndirectReference = parent.getPdfObject().getIndirectReference(); + if (parentIndirectReference != null) { + if (processedParents.contains(parentIndirectReference)) { + throw new PdfException(KernelExceptionMessageConstant.INVALID_PAGE_STRUCTURE) + .setMessageParams(pageNum + 1); + } else { + processedParents.add(parentIndirectReference); + } + } PdfArray kids = parent.getKids(); if (kids == null) { throw new PdfException(KernelExceptionMessageConstant.INVALID_PAGE_STRUCTURE).setMessageParams(pageNum + 1); @@ -430,7 +453,7 @@ private void loadPage(int pageNum) { // recursive call, to load needed pageRef. // NOTE optimization? add to loadPage startParentIndex. - loadPage(pageNum); + loadPage(pageNum, processedParents); } else { int from = parent.getFrom(); diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/canvas/parser/listener/LocationTextExtractionStrategy.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/canvas/parser/listener/LocationTextExtractionStrategy.java index febe1b78dd..15b0a9a3a0 100644 --- a/kernel/src/main/java/com/itextpdf/kernel/pdf/canvas/parser/listener/LocationTextExtractionStrategy.java +++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/canvas/parser/listener/LocationTextExtractionStrategy.java @@ -82,11 +82,7 @@ public class LocationTextExtractionStrategy implements ITextExtractionStrategy { * Creates a new text extraction renderer. */ public LocationTextExtractionStrategy() { - this(new ITextChunkLocationStrategy() { - public ITextChunkLocation createLocation(TextRenderInfo renderInfo, LineSegment baseline) { - return new TextChunkLocationDefaultImp(baseline.getStartPoint(), baseline.getEndPoint(), renderInfo.getSingleSpaceWidth()); - } - }); + this(new ITextChunkLocationStrategyImpl()); } /** @@ -349,4 +345,14 @@ private static class TextChunkMarks { List succeeding = new ArrayList<>(); } + private static final class ITextChunkLocationStrategyImpl + implements LocationTextExtractionStrategy.ITextChunkLocationStrategy { + + @Override + public ITextChunkLocation createLocation(TextRenderInfo renderInfo, LineSegment baseline) { + return new TextChunkLocationDefaultImp(baseline.getStartPoint(), baseline.getEndPoint(), + renderInfo.getSingleSpaceWidth()); + } + } + } diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/canvas/parser/listener/RegexBasedLocationExtractionStrategy.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/canvas/parser/listener/RegexBasedLocationExtractionStrategy.java index 352afed9cf..80b284d21f 100644 --- a/kernel/src/main/java/com/itextpdf/kernel/pdf/canvas/parser/listener/RegexBasedLocationExtractionStrategy.java +++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/canvas/parser/listener/RegexBasedLocationExtractionStrategy.java @@ -62,7 +62,7 @@ This file is part of the iText (R) project. * This class is designed to search for the occurrences of a regular expression and return the resultant rectangles. */ public class RegexBasedLocationExtractionStrategy implements ILocationExtractionStrategy { - + private static final float EPS = 1.0E-4F; private Pattern pattern; private List parseResult = new ArrayList<>(); @@ -100,18 +100,7 @@ public Collection getResultantLocations() { * This is to ensure that tests that use this functionality (for instance to generate pdf with * areas of interest highlighted) will not break when compared. */ - java.util.Collections.sort(retval, new Comparator() { - @Override - public int compare(IPdfTextLocation l1, IPdfTextLocation l2) { - Rectangle o1 = l1.getRectangle(); - Rectangle o2 = l2.getRectangle(); - if (o1.getY() == o2.getY()) { - return o1.getX() == o2.getX() ? 0 : (o1.getX() < o2.getX() ? -1 : 1); - } else { - return o1.getY() < o2.getY() ? -1 : 1; - } - } - }); + Collections.sort(retval, new PdfTextLocationComparator()); // ligatures can produces same rectangle removeDuplicates(retval); @@ -214,4 +203,19 @@ private static Integer getEndIndex(Map indexMap, int index) { } return indexMap.get(index); } + + private static final class PdfTextLocationComparator + implements Comparator { + @Override + public int compare(com.itextpdf.kernel.pdf.canvas.parser.listener.IPdfTextLocation l1, + com.itextpdf.kernel.pdf.canvas.parser.listener.IPdfTextLocation l2) { + Rectangle o1 = l1.getRectangle(); + Rectangle o2 = l2.getRectangle(); + if (Math.abs(o1.getY() - o2.getY()) < EPS) { + return Math.abs(o1.getX() - o2.getX()) < EPS ? 0 : ((o2.getX() - o1.getX()) > EPS ? -1 : 1); + } else { + return (o2.getY() - o1.getY()) > EPS ? -1 : 1; + } + } + } } diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/tagging/StandardNamespaces.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/tagging/StandardNamespaces.java index 8d53d763ac..7c9afee927 100644 --- a/kernel/src/main/java/com/itextpdf/kernel/pdf/tagging/StandardNamespaces.java +++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/tagging/StandardNamespaces.java @@ -130,6 +130,8 @@ public final class StandardNamespaces { StandardRoles.DOCUMENT, StandardRoles.DOCUMENTFRAGMENT, StandardRoles.PART, + StandardRoles.SECT, + StandardRoles.NONSTRUCT, StandardRoles.DIV, StandardRoles.ASIDE, StandardRoles.TITLE, diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/tagging/StructureTreeCopier.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/tagging/StructureTreeCopier.java index 41ce9b42c2..da9ca70fd6 100644 --- a/kernel/src/main/java/com/itextpdf/kernel/pdf/tagging/StructureTreeCopier.java +++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/tagging/StructureTreeCopier.java @@ -353,7 +353,6 @@ private static CopyStructureResult copyStructure(PdfDocument destDocument, Map

excludeKeys = Collections.singletonList(PdfName.RoleMapNS); PdfDocument toDocument = copyingParams.getToDocument(); diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/tagutils/AccessibilityProperties.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/tagutils/AccessibilityProperties.java index 644b37e2f6..95b9bccad9 100644 --- a/kernel/src/main/java/com/itextpdf/kernel/pdf/tagutils/AccessibilityProperties.java +++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/tagutils/AccessibilityProperties.java @@ -42,101 +42,290 @@ This file is part of the iText (R) project. */ package com.itextpdf.kernel.pdf.tagutils; +import com.itextpdf.kernel.pdf.PdfName; +import com.itextpdf.kernel.pdf.PdfString; import com.itextpdf.kernel.pdf.tagging.PdfNamespace; +import com.itextpdf.kernel.pdf.tagging.PdfStructElem; import com.itextpdf.kernel.pdf.tagging.PdfStructureAttributes; +import com.itextpdf.kernel.pdf.tagging.StandardRoles; import java.util.Collections; import java.util.List; +/** + * The accessibility properties are used to define properties of {@link PdfStructElem structure elements} + * in Tagged PDF documents via {@link TagTreePointer} API. + */ public abstract class AccessibilityProperties { + /** + * Gets the role of element. + * + *

+ * See also {@link StandardRoles}. + * + * @return the role + */ public String getRole() { return null; } + /** + * Sets the role of element. + * + *

+ * See also {@link StandardRoles}. + * + * @param role the role to be set + * + * @return this {@link AccessibilityProperties} instance + */ public AccessibilityProperties setRole(String role) { return this; } + /** + * Gets the language identifier of element. Should be in format xy-ZK (for example en-US). + * + *

+ * For more information see PDF Specification ISO 32000-1 section 14.9.2. + * + * @return the language + */ public String getLanguage() { return null; } + /** + * Sets the language identifier of element. Should be in format xy-ZK (for example en-US). + * + *

+ * For more information see PDF Specification ISO 32000-1 section 14.9.2. + * + * @param language the language to be set + * + * @return this {@link AccessibilityProperties} instance + */ public AccessibilityProperties setLanguage(String language) { return this; } + /** + * Gets the actual text of element. + * + * @return the actual text + */ public String getActualText() { return null; } + /** + * Sets the actual text of element. + * + * @param actualText the actual text to be set + * + * @return this {@link AccessibilityProperties} instance + */ public AccessibilityProperties setActualText(String actualText) { return this; } + /** + * Gets the alternate description of element. + * + * @return the alternate description + */ public String getAlternateDescription() { return null; } + /** + * Sets the alternate description of element. + * + * @param alternateDescription the alternation description to be set + * + * @return this {@link AccessibilityProperties} instance + */ public AccessibilityProperties setAlternateDescription(String alternateDescription) { return this; } + /** + * Gets the expansion of element. + * + *

+ * Expansion it is the expanded form of an abbreviation of structure element. + * + * @return the expansion + */ public String getExpansion() { return null; } + /** + * Sets the expansion of element. + * + *

+ * Expansion it is the expanded form of an abbreviation of structure element. + * + * @param expansion the expansion to be set + * + * @return this {@link AccessibilityProperties} instance + */ public AccessibilityProperties setExpansion(String expansion) { return this; } + /** + * Gets the phoneme of element. + * + *

+ * For more information see {@link PdfStructElem#setPhoneme(PdfString)}. + * + * @return the phoneme + */ public String getPhoneme() { return null; } + /** + * Sets the phoneme of element. + * + *

+ * For more information see {@link PdfStructElem#setPhoneme(PdfString)}. + * + * @param phoneme the phoneme to be set + * + * @return this {@link AccessibilityProperties} instance + */ public AccessibilityProperties setPhoneme(String phoneme) { return this; } + /** + * Gets the phonetic alphabet of element. + * + *

+ * For more information see {@link PdfStructElem#setPhoneticAlphabet(PdfName)}. + * + * @return the phonetic alphabet + */ public String getPhoneticAlphabet() { return null; } + /** + * Sets the phonetic alphabet of element. + * + *

+ * For more information see {@link PdfStructElem#setPhoneticAlphabet(PdfName)}. + * + * @param phoneticAlphabet the phonetic alphabet to be set + * + * @return this {@link AccessibilityProperties} instance + */ public AccessibilityProperties setPhoneticAlphabet(String phoneticAlphabet) { return this; } + /** + * Gets the namespace of element. + * + * @return the namespace + */ public PdfNamespace getNamespace() { return null; } + /** + * Sets the namespace of element. + * + * @param namespace the namespace to be set + * + * @return this {@link AccessibilityProperties} instance + */ public AccessibilityProperties setNamespace(PdfNamespace namespace) { return this; } + /** + * Adds the reference to other tagged element. + * + *

+ * For more information see {@link PdfStructElem#addRef(PdfStructElem)}. + * + * @param treePointer the reference to be set + * + * @return this {@link AccessibilityProperties} instance + */ public AccessibilityProperties addRef(TagTreePointer treePointer) { return this; } + /** + * Gets the list of references to other tagged elements. + * + *

+ * For more information see {@link PdfStructElem#addRef(PdfStructElem)}. + * + * @return the list of references + */ public List getRefsList() { return Collections.emptyList(); } + /** + * Clears the list of references to other tagged elements. + * + *

+ * For more information see {@link PdfStructElem#addRef(PdfStructElem)}. + * + * @return this {@link AccessibilityProperties} instance + */ public AccessibilityProperties clearRefs() { return this; } + /** + * Adds the attributes to the element. + * + * @param attributes the attributes to be added + * + * @return this {@link AccessibilityProperties} instance + */ public AccessibilityProperties addAttributes(PdfStructureAttributes attributes) { return this; } + /** + * Adds the attributes to the element with specified index. + * + *

+ * If an attribute with the same O and NS entries is specified more than once, the later (in array order) + * entry shall take precedence. For more information see PDF Specification ISO-32000 section 14.7.6. + * + * @param index the attributes index + * @param attributes the attributes to be added + * + * @return this {@link AccessibilityProperties} instance + */ public AccessibilityProperties addAttributes(int index, PdfStructureAttributes attributes) { return this; } + /** + * Clears the list of attributes. + * + * @return this {@link AccessibilityProperties} instance + */ public AccessibilityProperties clearAttributes() { return this; } + /** + * Gets the attributes list. + * + * @return the attributes list + */ public List getAttributesList() { return Collections.emptyList(); } diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/tagutils/DefaultAccessibilityProperties.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/tagutils/DefaultAccessibilityProperties.java index ee539bc7b8..bcfd5ff4ea 100644 --- a/kernel/src/main/java/com/itextpdf/kernel/pdf/tagutils/DefaultAccessibilityProperties.java +++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/tagutils/DefaultAccessibilityProperties.java @@ -44,14 +44,19 @@ This file is part of the iText (R) project. package com.itextpdf.kernel.pdf.tagutils; import com.itextpdf.kernel.pdf.tagging.PdfNamespace; +import com.itextpdf.kernel.pdf.tagging.PdfStructElem; import com.itextpdf.kernel.pdf.tagging.PdfStructureAttributes; + import java.util.ArrayList; import java.util.Collections; import java.util.List; +/** + * The class represents a basic implementation of {@link AccessibilityProperties} that preserves specified + * accessibility properties. Accessibility properties are used to define properties of + * {@link PdfStructElem structure elements} in Tagged PDF documents via {@link TagTreePointer} API. + */ public class DefaultAccessibilityProperties extends AccessibilityProperties { - - protected String role; protected String language; protected String actualText; @@ -64,6 +69,11 @@ public class DefaultAccessibilityProperties extends AccessibilityProperties { protected PdfNamespace namespace; protected List refs = new ArrayList<>(); + /** + * Instantiates a new {@link DefaultAccessibilityProperties} instance based on structure element role. + * + * @param role the structure element role + */ public DefaultAccessibilityProperties(String role) { this.role = role; } diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/tagutils/TagReference.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/tagutils/TagReference.java index 762a05338e..3a89f38133 100644 --- a/kernel/src/main/java/com/itextpdf/kernel/pdf/tagutils/TagReference.java +++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/tagutils/TagReference.java @@ -46,8 +46,16 @@ This file is part of the iText (R) project. import com.itextpdf.kernel.pdf.PdfDictionary; import com.itextpdf.kernel.pdf.PdfName; import com.itextpdf.kernel.pdf.PdfObject; +import com.itextpdf.kernel.pdf.canvas.PdfCanvas; import com.itextpdf.kernel.pdf.tagging.PdfStructElem; +/** + * The class is used to provide connection between structure element of + * Tagged PDF document and marked content sequence in PDF stream. + * + *

+ * See {@link TagTreePointer#getTagReference(int)} and {@link PdfCanvas#openTag(TagReference)}. + */ public class TagReference { protected TagTreePointer tagPointer; protected int insertIndex; @@ -56,6 +64,15 @@ public class TagReference { protected PdfName role; protected PdfDictionary properties; + /** + * Creates a {@link TagReference} instance which represents a reference to {@link PdfStructElem}. + * + * @param referencedTag a structure element to which marked content will link (if insertIndex is -1, + * otherwise to MC will link to kid with insertIndex of passed structure element) + * @param tagPointer the tag pointer to structure element + * @param insertIndex if insertIndex is -1, the referencedTag will be used as a + * source of reference, otherwise the kid will be used + */ protected TagReference(PdfStructElem referencedTag, TagTreePointer tagPointer, int insertIndex) { this.role = referencedTag.getRole(); this.referencedTag = referencedTag; @@ -63,14 +80,32 @@ protected TagReference(PdfStructElem referencedTag, TagTreePointer tagPointer, i this.insertIndex = insertIndex; } + /** + * Gets role of structure element. + * + * @return the role of structure element + */ public PdfName getRole() { return role; } + /** + * Creates next marked content identifier, which will be used to mark content in PDF stream. + * + * @return the marked content identifier + */ public int createNextMcid() { return tagPointer.createNextMcidForStructElem(referencedTag, insertIndex); } + /** + * Adds property, which will be associated with marked-content sequence. + * + * @param name the name of the property + * @param value the value of the property + * + * @return the {@link TagReference} instance + */ public TagReference addProperty(PdfName name, PdfObject value) { if (properties == null) { properties = new PdfDictionary(); @@ -80,6 +115,13 @@ public TagReference addProperty(PdfName name, PdfObject value) { return this; } + /** + * Removes property. The property will not be associated with marked-content sequence. + * + * @param name the name of property to be deleted + * + * @return the {@link TagReference} instance + */ public TagReference removeProperty(PdfName name) { if (properties != null) { properties.remove(name); @@ -87,6 +129,13 @@ public TagReference removeProperty(PdfName name) { return this; } + /** + * Gets property which related to specified name. + * + * @param name the name of the property + * + * @return the value of the property + */ public PdfObject getProperty(PdfName name) { if (properties == null) { return null; @@ -94,6 +143,11 @@ public PdfObject getProperty(PdfName name) { return properties.get(name); } + /** + * Gets properties, which will be associated with marked-content sequence as {@link PdfDictionary}. + * + * @return the properties + */ public PdfDictionary getProperties() { return properties; } diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/tagutils/TagStructureContext.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/tagutils/TagStructureContext.java index 46798c604b..6e26b15a4d 100644 --- a/kernel/src/main/java/com/itextpdf/kernel/pdf/tagutils/TagStructureContext.java +++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/tagutils/TagStructureContext.java @@ -44,8 +44,8 @@ This file is part of the iText (R) project. package com.itextpdf.kernel.pdf.tagutils; import com.itextpdf.io.logs.IoLogMessageConstant; -import com.itextpdf.kernel.exceptions.PdfException; import com.itextpdf.kernel.exceptions.KernelExceptionMessageConstant; +import com.itextpdf.kernel.exceptions.PdfException; import com.itextpdf.kernel.pdf.PdfArray; import com.itextpdf.kernel.pdf.PdfDictionary; import com.itextpdf.kernel.pdf.PdfDocument; @@ -64,7 +64,6 @@ This file is part of the iText (R) project. import com.itextpdf.kernel.pdf.tagging.StandardNamespaces; import com.itextpdf.kernel.pdf.tagging.StandardRoles; - import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; @@ -119,6 +118,7 @@ public class TagStructureContext { *
* Creates {@code TagStructureContext} for document. There shall be only one instance of this * class per {@code PdfDocument}. + * * @param document the document which tag structure will be manipulated with this class. */ public TagStructureContext(PdfDocument document) { @@ -128,9 +128,11 @@ public TagStructureContext(PdfDocument document) { /** * Do not use this constructor, instead use {@link PdfDocument#getTagStructureContext()} * method. + * *

* Creates {@code TagStructureContext} for document. There shall be only one instance of this * class per {@code PdfDocument}. + * * @param document the document which tag structure will be manipulated with this class. * @param tagStructureTargetVersion the version of the pdf standard to which the tag structure shall adhere. */ @@ -156,7 +158,9 @@ public TagStructureContext(PdfDocument document, PdfVersion tagStructureTargetVe * If forbidUnknownRoles is set to true, then if you would try to add new tag which has not a standard role and * it's role is not mapped through RoleMap, an exception will be raised. * Default value - true. + * * @param forbidUnknownRoles new value of the flag + * * @return current {@link TagStructureContext} instance. */ public TagStructureContext setForbidUnknownRoles(boolean forbidUnknownRoles) { @@ -164,6 +168,11 @@ public TagStructureContext setForbidUnknownRoles(boolean forbidUnknownRoles) { return this; } + /** + * Gets the version of the PDF standard to which the tag structure shall adhere. + * + * @return the tag structure target version + */ public PdfVersion getTagStructureTargetVersion() { return tagStructureTargetVersion; } @@ -174,6 +183,7 @@ public PdfVersion getTagStructureTargetVersion() { * Typically it points at the root tag. This pointer also could be used to tweak auto tagging process * (e.g. move this pointer to the Section tag, which would result in placing all automatically tagged content * under Section tag). + * * @return the {@code TagTreePointer} which is used for all automatic tagging of the document. */ public TagTreePointer getAutoTaggingPointer() { @@ -186,6 +196,7 @@ public TagTreePointer getAutoTaggingPointer() { /** * Gets {@link WaitingTagsManager} for the current document. It allows to mark tags as waiting, * which would indicate that they are incomplete and are not ready to be flushed. + * * @return document's {@link WaitingTagsManager} class instance. */ public WaitingTagsManager getWaitingTagsManager() { @@ -199,8 +210,10 @@ public WaitingTagsManager getWaitingTagsManager() { *

* By default, this value is defined based on the PDF document version and the existing tag structure inside * a document. For the new empty PDF 2.0 documents this namespace is set to {@link StandardNamespaces#PDF_2_0}. + * *

* This value has meaning only for the PDF documents of version 2.0 and higher. + * * @return a {@link PdfNamespace} which is used as a default value for the document tagging. */ public PdfNamespace getDocumentDefaultNamespace() { @@ -210,16 +223,19 @@ public PdfNamespace getDocumentDefaultNamespace() { /** * Sets a namespace that will be used as a default value for the tagging for any new {@link TagTreePointer} created. * See {@link #getDocumentDefaultNamespace()} for more info. + * *

* Be careful when changing this property value. It is most recommended to do it right after the {@link PdfDocument} was * created, before any content was added. Changing this value after any content was added might result in the mingled * tag structure from the namespaces point of view. So in order to maintain the document consistent but in the namespace * different from default, set this value before any modifications to the document were made and before * {@link #getAutoTaggingPointer()} method was called for the first time. + * *

* This value has meaning only for the PDF documents of version 2.0 and higher. * * @param namespace a {@link PdfNamespace} which is to be used as a default value for the document tagging. + * * @return current {@link TagStructureContext} instance. */ public TagStructureContext setDocumentDefaultNamespace(PdfNamespace namespace) { @@ -229,6 +245,7 @@ public TagStructureContext setDocumentDefaultNamespace(PdfNamespace namespace) { /** * This method defines a recommended way to obtain {@link PdfNamespace} class instances. + * *

* Returns either a wrapper over an already existing namespace dictionary in the document or over a new one * if such namespace wasn't encountered before. Calling this method is considered as encountering a namespace, @@ -239,6 +256,7 @@ public TagStructureContext setDocumentDefaultNamespace(PdfNamespace namespace) { * {@link PdfName#Namespaces /Namespaces} array unless they were set to the certain element of the tag structure. * * @param namespaceName a {@link String} defining the namespace name (conventionally a uniform resource identifier, or URI). + * * @return {@link PdfNamespace} wrapper over either already existing namespace object or over the new one. */ public PdfNamespace fetchNamespace(String namespaceName) { @@ -254,7 +272,9 @@ public PdfNamespace fetchNamespace(String namespaceName) { /** * Gets an instance of the {@link IRoleMappingResolver} corresponding to the current tag structure target version. * This method implies that role is in the default standard structure namespace. + * * @param role a role in the default standard structure namespace which mapping is to be resolved. + * * @return a {@link IRoleMappingResolver} instance, with the giving role as current. */ public IRoleMappingResolver getRoleMappingResolver(String role) { @@ -263,8 +283,10 @@ public IRoleMappingResolver getRoleMappingResolver(String role) { /** * Gets an instance of the {@link IRoleMappingResolver} corresponding to the current tag structure target version. + * * @param role a role in the given namespace which mapping is to be resolved. * @param namespace a {@link PdfNamespace} which this role belongs to. + * * @return a {@link IRoleMappingResolver} instance, with the giving role in the given {@link PdfNamespace} as current. */ public IRoleMappingResolver getRoleMappingResolver(String role, PdfNamespace namespace) { @@ -278,9 +300,11 @@ public IRoleMappingResolver getRoleMappingResolver(String role, PdfNamespace nam /** * Checks if the given role and namespace are specified to be obligatory mapped to the standard structure namespace * in order to be a valid role in the Tagged PDF. + * * @param role a role in the given namespace which mapping necessity is to be checked. * @param namespace a {@link PdfNamespace} which this role belongs to, null value refers to the default standard * structure namespace. + * * @return true, if the given role in the given namespace is either mapped to the standard structure role or doesn't * have to; otherwise false. */ @@ -290,10 +314,13 @@ public boolean checkIfRoleShallBeMappedToStandardRole(String role, PdfNamespace /** * Gets an instance of the {@link IRoleMappingResolver} which is already in the "resolved" state: it returns - * role in the standard or domain-specific namespace for the {@link IRoleMappingResolver#getRole()} and {@link IRoleMappingResolver#getNamespace()} - * methods calls which correspond to the mapping of the given role; or null if the given role is not mapped to the standard or domain-specific one. + * role in the standard or domain-specific namespace for the {@link IRoleMappingResolver#getRole()} and + * {@link IRoleMappingResolver#getNamespace()} methods calls which correspond to the mapping of the given role; + * or null if the given role is not mapped to the standard or domain-specific one. + * * @param role a role in the given namespace which mapping is to be resolved. * @param namespace a {@link PdfNamespace} which this role belongs to. + * * @return an instance of the {@link IRoleMappingResolver} which returns false * for the {@link IRoleMappingResolver#currentRoleShallBeMappedToStandard()} method call; if mapping cannot be resolved * to this state, this method returns null, which means that the given role @@ -323,6 +350,7 @@ public IRoleMappingResolver resolveMappingToStandardOrDomainSpecificRole(String * If annotation is not added to the document or is not tagged, nothing will happen. * * @param annotation the {@link PdfAnnotation} that will be removed from the tag structure + * * @return {@link TagTreePointer} instance which points at annotation tag parent if annotation was removed, * otherwise returns null */ @@ -353,8 +381,10 @@ public TagTreePointer removeAnnotationTag(PdfAnnotation annotation) { * Removes content item from the tag structure. *
* Nothing happens if there is no such mcid on given page. + * * @param page page, which contains this content item * @param mcid marked content id of this content item + * * @return {@code TagTreePointer} which points at the parent of the removed content item, or null if there is no * such mcid on given page. */ @@ -374,6 +404,7 @@ public TagTreePointer removeContentItem(PdfPage page, int mcid) { * at {@link #flushPageTags(PdfPage)}. * * @param page page that defines which tags are to be removed + * * @return current {@link TagStructureContext} instance */ public TagStructureContext removePageTags(PdfPage page) { @@ -402,6 +433,7 @@ public TagStructureContext removePageTags(PdfPage page) { * as not yet finished ones, and they and their children won't be flushed. * * @param page a page which tags will be flushed + * * @return current {@link TagStructureContext} instance */ public TagStructureContext flushPageTags(PdfPage page) { @@ -474,6 +506,7 @@ public void prepareToDocumentClosing() { * especially in conjunction with high level {@link TagTreePointer} and {@link TagStructureContext} classes. * * @param pointer a {@link TagTreePointer} which points at desired {@link PdfStructElem}. + * * @return a {@link PdfStructElem} at which given {@link TagTreePointer} points. */ public PdfStructElem getPointerStructElem(TagTreePointer pointer) { @@ -482,7 +515,9 @@ public PdfStructElem getPointerStructElem(TagTreePointer pointer) { /** * Creates a new {@link TagTreePointer} which points at given {@link PdfStructElem}. + * * @param structElem a {@link PdfStructElem} for which {@link TagTreePointer} will be created. + * * @return a new {@link TagTreePointer}. */ public TagTreePointer createPointerForStructElem(PdfStructElem structElem) { diff --git a/kernel/src/main/java/com/itextpdf/kernel/utils/PdfSplitter.java b/kernel/src/main/java/com/itextpdf/kernel/utils/PdfSplitter.java index 072c0ef2cd..de29bc9190 100644 --- a/kernel/src/main/java/com/itextpdf/kernel/utils/PdfSplitter.java +++ b/kernel/src/main/java/com/itextpdf/kernel/utils/PdfSplitter.java @@ -169,12 +169,7 @@ public void splitByPageNumbers(List pageNumbers, IDocumentReadyListener public List splitByPageNumbers(List pageNumbers) { final List splitDocuments = new ArrayList<>(); - splitByPageNumbers(pageNumbers, new IDocumentReadyListener() { - @Override - public void documentReady(PdfDocument pdfDocument, PageRange pageRange) { - splitDocuments.add(pdfDocument); - } - }); + splitByPageNumbers(pageNumbers, new SplitReadyListener(splitDocuments)); return splitDocuments; } @@ -206,12 +201,7 @@ public void splitByPageCount(int pageCount, IDocumentReadyListener documentReady public List splitByPageCount(int pageCount) { final List splitDocuments = new ArrayList<>(); - splitByPageCount(pageCount, new IDocumentReadyListener() { - @Override - public void documentReady(PdfDocument pdfDocument, PageRange pageRange) { - splitDocuments.add(pdfDocument); - } - }); + splitByPageCount(pageCount, new SplitReadyListener(splitDocuments)); return splitDocuments; } @@ -408,4 +398,18 @@ private PageRange getNextRange(int startPage, int endPage, long size) { private long xrefLength(int size) { return 20L * (size + 1); } + + private static final class SplitReadyListener implements IDocumentReadyListener { + + private List splitDocuments; + + public SplitReadyListener(List splitDocuments) { + this.splitDocuments = splitDocuments; + } + + @Override + public void documentReady(PdfDocument pdfDocument, PageRange pageRange) { + splitDocuments.add(pdfDocument); + } + } } diff --git a/kernel/src/main/java/com/itextpdf/kernel/xmp/XMPMetaFactory.java b/kernel/src/main/java/com/itextpdf/kernel/xmp/XMPMetaFactory.java index a4efa4d66a..acb6a57af2 100644 --- a/kernel/src/main/java/com/itextpdf/kernel/xmp/XMPMetaFactory.java +++ b/kernel/src/main/java/com/itextpdf/kernel/xmp/XMPMetaFactory.java @@ -262,43 +262,59 @@ public static XMPVersionInfo getVersionInfo() { // Adobe XMP Core 5.0-jc001 DEBUG-., 2009 Jan 28 15:22:38-CET final String message = "Adobe XMP Core 5.1.0-jc003"; + versionInfo = new XMPVersionInfoImpl(major, minor, micro, engBuild, debug, message); + } catch (Throwable e) { + // empty, severe error would be detected during the tests + System.out.println(e); + } + } + return versionInfo; + } + } - versionInfo = new XMPVersionInfo() { - public int getMajor() { - return major; - } + private static final class XMPVersionInfoImpl implements XMPVersionInfo { + private final int major; + private final int minor; + private final int micro; + private final int engBuild; + private final boolean debug; + private final String message; + + public XMPVersionInfoImpl(int major, int minor, int micro, int engBuild, boolean debug, String message) { + this.major = major; + this.minor = minor; + this.micro = micro; + this.engBuild = engBuild; + this.debug = debug; + this.message = message; + } - public int getMinor() { - return minor; - } + public int getMajor() { + return major; + } - public int getMicro() { - return micro; - } + public int getMinor() { + return minor; + } - public boolean isDebug() { - return debug; - } + public int getMicro() { + return micro; + } - public int getBuild() { - return engBuild; - } + public boolean isDebug() { + return debug; + } - public String getMessage() { - return message; - } + public int getBuild() { + return engBuild; + } - public String toString() { - return message; - } - }; + public String getMessage() { + return message; + } - } catch (Throwable e) { - // EMTPY, severe error would be detected during the tests - System.out.println(e); - } - } - return versionInfo; + public String toString() { + return message; } } } diff --git a/kernel/src/test/java/com/itextpdf/kernel/crypto/CryptoUtilTest.java b/kernel/src/test/java/com/itextpdf/kernel/crypto/CryptoUtilTest.java new file mode 100644 index 0000000000..1330ad08f3 --- /dev/null +++ b/kernel/src/test/java/com/itextpdf/kernel/crypto/CryptoUtilTest.java @@ -0,0 +1,62 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2021 iText Group NV + Authors: iText Software. + + This program is offered under a commercial and under the AGPL license. + For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + + AGPL licensing: + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +package com.itextpdf.kernel.crypto; + +import com.itextpdf.commons.utils.MessageFormatUtil; +import com.itextpdf.io.source.ByteArrayOutputStream; +import com.itextpdf.kernel.exceptions.KernelExceptionMessageConstant; +import com.itextpdf.test.ExtendedITextTest; +import com.itextpdf.test.annotations.type.UnitTest; + +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1OutputStream; +import org.junit.Assert; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +@Category(UnitTest.class) +public class CryptoUtilTest extends ExtendedITextTest { + @Test + public void createBerStreamTest() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ASN1OutputStream stream = CryptoUtil.createAsn1OutputStream(baos, ASN1Encoding.BER); + Assert.assertNotNull(stream); + } + + @Test + public void createDerStreamTest() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ASN1OutputStream stream = CryptoUtil.createAsn1OutputStream(baos, ASN1Encoding.DER); + Assert.assertNotNull(stream); + } + + @Test + public void createUnsupportedEncodingStreamTest() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + Exception e = Assert.assertThrows(UnsupportedOperationException.class, + () -> CryptoUtil.createAsn1OutputStream(baos, "DL") + ); + Assert.assertEquals(MessageFormatUtil.format(KernelExceptionMessageConstant.UNSUPPORTED_ASN1_ENCODING, "DL"), + e.getMessage()); + } +} diff --git a/kernel/src/test/java/com/itextpdf/kernel/font/PdfType0FontTest.java b/kernel/src/test/java/com/itextpdf/kernel/font/PdfType0FontTest.java index dcfa6020d1..9584908420 100644 --- a/kernel/src/test/java/com/itextpdf/kernel/font/PdfType0FontTest.java +++ b/kernel/src/test/java/com/itextpdf/kernel/font/PdfType0FontTest.java @@ -25,6 +25,7 @@ This file is part of the iText (R) project. import com.itextpdf.io.font.CMapEncoding; import com.itextpdf.io.font.PdfEncodings; import com.itextpdf.io.font.TrueTypeFont; +import com.itextpdf.io.font.otf.Glyph; import com.itextpdf.kernel.exceptions.PdfException; import com.itextpdf.kernel.exceptions.KernelExceptionMessageConstant; import com.itextpdf.kernel.pdf.PdfDictionary; @@ -35,6 +36,8 @@ This file is part of the iText (R) project. import com.itextpdf.test.annotations.type.UnitTest; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import org.junit.Assert; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -94,4 +97,16 @@ public void dictionaryConstructorTest() throws IOException { Assert.assertEquals(0, cmap.getSupplement()); Assert.assertEquals(PdfEncodings.IDENTITY_H, cmap.getCmapName()); } + + @Test + public void appendThreeSurrogatePairsTest() throws IOException { + // this text contains three successive surrogate pairs, which should result in three glyphs + String textWithThreeSurrogatePairs = "\uD800\uDF10\uD800\uDF00\uD800\uDF11"; + PdfFont type0Font = + PdfFontFactory.createFont(sourceFolder + "NotoSansOldItalic-Regular.ttf", PdfEncodings.IDENTITY_H); + + List glyphs = new ArrayList<>(); + type0Font.appendGlyphs(textWithThreeSurrogatePairs, 0, textWithThreeSurrogatePairs.length() - 1, glyphs); + Assert.assertEquals(3, glyphs.size()); + } } diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfDocumentTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfDocumentTest.java index b06ba7b5f9..232ab9eda7 100644 --- a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfDocumentTest.java +++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfDocumentTest.java @@ -483,7 +483,7 @@ public void addAssociatedFilesTest02() throws IOException, InterruptedException imageXObject.addAssociatedFile(PdfFileSpec .createEmbeddedFileSpec(pdfDocument, "Associated File 1".getBytes(), "af_1.txt", PdfName.Data)); - pageCanvas.addXObject(imageXObject, 40, 400); + pageCanvas.addXObjectAt(imageXObject, 40, 400); PdfFormXObject formXObject = new PdfFormXObject(new Rectangle(200, 200)); PdfCanvas formCanvas = new PdfCanvas(formXObject, pdfDocument); @@ -497,7 +497,7 @@ public void addAssociatedFilesTest02() throws IOException, InterruptedException formXObject.addAssociatedFile(PdfFileSpec .createEmbeddedFileSpec(pdfDocument, "Associated File 2".getBytes(), "af_2.txt", PdfName.Data)); - pageCanvas.addXObject(formXObject, 40, 100); + pageCanvas.addXObjectAt(formXObject, 40, 100); pdfDocument.close(); Assert.assertNull(new CompareTool().compareByContent(DESTINATION_FOLDER + "add_associated_files02.pdf", diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfOutlineTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfOutlineTest.java index e1088cd55f..cadb25445e 100644 --- a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfOutlineTest.java +++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfOutlineTest.java @@ -42,31 +42,36 @@ This file is part of the iText (R) project. */ package com.itextpdf.kernel.pdf; -import com.itextpdf.io.logs.IoLogMessageConstant; import com.itextpdf.commons.utils.MessageFormatUtil; -import com.itextpdf.kernel.exceptions.PdfException; +import com.itextpdf.io.font.PdfEncodings; +import com.itextpdf.io.logs.IoLogMessageConstant; +import com.itextpdf.kernel.colors.ColorConstants; import com.itextpdf.kernel.exceptions.KernelExceptionMessageConstant; +import com.itextpdf.kernel.exceptions.PdfException; +import com.itextpdf.kernel.logs.KernelLogMessageConstant; +import com.itextpdf.kernel.pdf.PdfReader.StrictnessLevel; import com.itextpdf.kernel.pdf.navigation.PdfDestination; import com.itextpdf.kernel.pdf.navigation.PdfExplicitDestination; import com.itextpdf.kernel.pdf.navigation.PdfStringDestination; import com.itextpdf.kernel.utils.CompareTool; +import com.itextpdf.test.AssertUtil; import com.itextpdf.test.ExtendedITextTest; import com.itextpdf.test.annotations.LogMessage; import com.itextpdf.test.annotations.LogMessages; import com.itextpdf.test.annotations.type.IntegrationTest; import java.io.ByteArrayOutputStream; -import java.util.HashMap; -import org.xml.sax.SAXException; -import javax.xml.parsers.ParserConfigurationException; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import javax.xml.parsers.ParserConfigurationException; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.xml.sax.SAXException; @Category(IntegrationTest.class) public class PdfOutlineTest extends ExtendedITextTest { @@ -99,7 +104,7 @@ public void createSimpleDocWithOutlines() throws IOException, InterruptedExcepti Assert.assertNull(new CompareTool().compareByContent(DESTINATION_FOLDER + filename, SOURCE_FOLDER + "cmp_" + filename, DESTINATION_FOLDER, "diff_")); } - + @Test public void outlinesTest() throws IOException { PdfDocument pdfDoc = new PdfDocument(new PdfReader(SOURCE_FOLDER + "iphone_user_guide.pdf")); @@ -225,10 +230,18 @@ public void getOutlinesInvalidParentLink() throws IOException { String filename = "updateOutlineTitleInvalidParentLink.pdf"; PdfWriter writer = new PdfWriter(DESTINATION_FOLDER + filename); PdfDocument pdfDoc = new PdfDocument(reader, writer); - - Assert.assertThrows(NullPointerException.class, - () -> pdfDoc.getOutlines(false) - ); + PdfOutline outlines = pdfDoc.getOutlines(true); + PdfOutline firstOutline = outlines.getAllChildren().get(0); + PdfOutline secondOutline = outlines.getAllChildren().get(1); + try { + Assert.assertEquals(2, outlines.getAllChildren().size()); + Assert.assertEquals("First Page", firstOutline.getTitle()); + Assert.assertEquals(outlines, firstOutline.getParent()); + Assert.assertEquals("Second Page", secondOutline.getTitle()); + Assert.assertEquals(outlines, secondOutline.getParent()); + } finally { + pdfDoc.close(); + } } @Test @@ -526,15 +539,11 @@ public void constructOutlinesNoParentTest() throws IOException { PdfDictionary outlineDictionary = new PdfDictionary(); outlineDictionary.put(PdfName.First, first); + outlineDictionary.put(PdfName.Title, new PdfString("title", PdfEncodings.UNICODE_BIG)); + first.put(PdfName.Title, new PdfString("title", PdfEncodings.UNICODE_BIG)); - Exception exception = Assert.assertThrows( - PdfException.class, - () -> pdfDocument.getCatalog().constructOutlines(outlineDictionary, new HashMap()) - ); - Assert.assertEquals( - MessageFormatUtil.format(KernelExceptionMessageConstant.CORRUPTED_OUTLINE_NO_PARENT_ENTRY, - first.indirectReference), - exception.getMessage()); + AssertUtil.doesNotThrow(() -> pdfDocument.getCatalog() + .constructOutlines(outlineDictionary, new HashMap())); } } @@ -565,4 +574,242 @@ public void constructOutlinesNoTitleTest() throws IOException { exception.getMessage()); } } + + @Test + public void checkParentOfOutlinesTest() throws IOException { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PdfDocument pdfDocument = new PdfDocument(new PdfWriter(baos))) { + pdfDocument.getCatalog().setPageMode(PdfName.UseOutlines); + + PdfPage firstPage = pdfDocument.addNewPage(); + + PdfOutline rootOutline = pdfDocument.getOutlines(false); + PdfOutline firstOutline = rootOutline.addOutline("First outline"); + PdfOutline firstSubOutline = firstOutline.addOutline("First suboutline"); + PdfOutline secondSubOutline = firstOutline.addOutline("Second suboutline"); + PdfOutline secondOutline = rootOutline.addOutline("SecondOutline"); + + firstOutline.addDestination(PdfExplicitDestination.createFit(firstPage)); + + PdfOutline resultedRoot = pdfDocument.getOutlines(true); + Assert.assertEquals(2, resultedRoot.getAllChildren().size()); + Assert.assertEquals(resultedRoot, resultedRoot.getAllChildren().get(0).getParent()); + Assert.assertEquals(resultedRoot, resultedRoot.getAllChildren().get(1).getParent()); + + PdfOutline resultedFirstOutline = resultedRoot.getAllChildren().get(0); + Assert.assertEquals(2, resultedFirstOutline.getAllChildren().size()); + Assert.assertEquals(resultedFirstOutline, resultedFirstOutline.getAllChildren().get(0).getParent()); + Assert.assertEquals(resultedFirstOutline, resultedFirstOutline.getAllChildren().get(1).getParent()); + } + } + + @Test + public void checkNestedOutlinesParentTest() throws IOException { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PdfDocument pdfDocument = new PdfDocument(new PdfWriter(baos))) { + pdfDocument.getCatalog().setPageMode(PdfName.UseOutlines); + + PdfPage firstPage = pdfDocument.addNewPage(); + PdfOutline rootOutline = pdfDocument.getOutlines(false); + PdfOutline firstOutline = rootOutline.addOutline("First outline"); + PdfOutline secondOutline = firstOutline.addOutline("Second outline"); + PdfOutline thirdOutline = secondOutline.addOutline("Third outline"); + + firstOutline.addDestination(PdfExplicitDestination.createFit(firstPage)); + + PdfOutline resultedRoot = pdfDocument.getOutlines(true); + Assert.assertEquals(1, resultedRoot.getAllChildren().size()); + Assert.assertEquals(resultedRoot, resultedRoot.getAllChildren().get(0).getParent()); + + PdfOutline resultedFirstOutline = resultedRoot.getAllChildren().get(0); + Assert.assertEquals(1, resultedFirstOutline.getAllChildren().size()); + Assert.assertEquals(resultedFirstOutline, resultedFirstOutline.getAllChildren().get(0).getParent()); + + PdfOutline resultedSecondOutline = resultedFirstOutline.getAllChildren().get(0); + Assert.assertEquals(1, resultedSecondOutline.getAllChildren().size()); + Assert.assertEquals(resultedSecondOutline, resultedSecondOutline.getAllChildren().get(0).getParent()); + } + } + + @Test + public void setOutlinePropertiesTest() throws IOException { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PdfDocument pdfDocument = new PdfDocument(new PdfWriter(baos))) { + + PdfPage firstPage = pdfDocument.addNewPage(); + + PdfOutline rootOutline = pdfDocument.getOutlines(true); + PdfOutline outline = rootOutline.addOutline("Outline"); + + Assert.assertTrue(outline.isOpen()); + Assert.assertNull(outline.getStyle()); + Assert.assertNull(outline.getColor()); + + outline.getContent().put(PdfName.C, new PdfArray(ColorConstants.BLACK.getColorValue())); + outline.getContent().put(PdfName.F, new PdfNumber(2)); + outline.getContent().put(PdfName.Count, new PdfNumber(4)); + + Assert.assertTrue(outline.isOpen()); + Assert.assertEquals(new Integer(2), outline.getStyle()); + Assert.assertEquals(ColorConstants.BLACK, outline.getColor()); + + outline.getContent().put(PdfName.Count, new PdfNumber(0)); + Assert.assertTrue(outline.isOpen()); + + outline.getContent().put(PdfName.Count, new PdfNumber(-5)); + Assert.assertFalse(outline.isOpen()); + } + } + + @Test + @LogMessages(messages = @LogMessage(messageTemplate = + KernelLogMessageConstant.CORRUPTED_OUTLINE_DICTIONARY_HAS_INFINITE_LOOP)) + public void checkPossibleInfiniteLoopWithSameNextAndPrevLinkTest() throws IOException { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PdfDocument pdfDocument = new PdfDocument(new PdfWriter(baos))) { + + pdfDocument.addNewPage(); + + PdfDictionary first = new PdfDictionary(); + first.makeIndirect(pdfDocument); + PdfDictionary second = new PdfDictionary(); + second.makeIndirect(pdfDocument); + + PdfDictionary outlineDictionary = new PdfDictionary(); + outlineDictionary.makeIndirect(pdfDocument); + + outlineDictionary.put(PdfName.First, first); + outlineDictionary.put(PdfName.Last, second); + first.put(PdfName.Parent, outlineDictionary); + second.put(PdfName.Parent, outlineDictionary); + first.put(PdfName.Next, second); + first.put(PdfName.Prev, second); + second.put(PdfName.Next, first); + second.put(PdfName.Prev, first); + outlineDictionary.put(PdfName.Title, new PdfString("title", PdfEncodings.UNICODE_BIG)); + first.put(PdfName.Title, new PdfString("title", PdfEncodings.UNICODE_BIG)); + second.put(PdfName.Title, new PdfString("title", PdfEncodings.UNICODE_BIG)); + + AssertUtil.doesNotThrow(() -> pdfDocument.getCatalog() + .constructOutlines(outlineDictionary, new HashMap())); + PdfOutline resultedOutline = pdfDocument.getOutlines(false); + Assert.assertEquals(2, resultedOutline.getAllChildren().size()); + Assert.assertEquals(resultedOutline.getAllChildren().get(1).getParent(), + resultedOutline.getAllChildren().get(0).getParent()); + } + } + + @Test + @LogMessages(messages = @LogMessage(messageTemplate = + KernelLogMessageConstant.CORRUPTED_OUTLINE_DICTIONARY_HAS_INFINITE_LOOP)) + public void checkPossibleInfiniteLoopWithSameFirstAndLastLinkTest() throws IOException { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PdfDocument pdfDocument = new PdfDocument(new PdfWriter(baos))) { + + pdfDocument.addNewPage(); + + PdfDictionary first = new PdfDictionary(); + first.makeIndirect(pdfDocument); + + PdfDictionary outlineDictionary = new PdfDictionary(); + outlineDictionary.makeIndirect(pdfDocument); + + outlineDictionary.put(PdfName.First, first); + first.put(PdfName.Parent, outlineDictionary); + first.put(PdfName.First, outlineDictionary); + first.put(PdfName.Last, outlineDictionary); + outlineDictionary.put(PdfName.Title, new PdfString("title", PdfEncodings.UNICODE_BIG)); + first.put(PdfName.Title, new PdfString("title", PdfEncodings.UNICODE_BIG)); + + AssertUtil.doesNotThrow(() -> pdfDocument.getCatalog() + .constructOutlines(outlineDictionary, new HashMap())); + PdfOutline resultedOutline = pdfDocument.getOutlines(false); + Assert.assertEquals(1, resultedOutline.getAllChildren().size()); + Assert.assertEquals(resultedOutline, + resultedOutline.getAllChildren().get(0).getParent()); + } + } + + @Test + public void outlineNoParentLinkInConservativeModeTest() throws IOException { + try ( + PdfDocument pdfDocument = new PdfDocument( + new PdfReader(SOURCE_FOLDER + "outlinesNoParentLink.pdf"))) { + pdfDocument.getReader().setStrictnessLevel(StrictnessLevel.CONSERVATIVE); + Exception exception = Assert.assertThrows(PdfException.class, () -> pdfDocument.getOutlines(true)); + + //Hardcode indirectReference, cause there is no option to get this outline due to #getOutlines method + // will be thrown an exception. + Assert.assertEquals( + MessageFormatUtil.format(KernelExceptionMessageConstant.CORRUPTED_OUTLINE_NO_PARENT_ENTRY, "9 0 R"), + exception.getMessage()); + } + } + + @Test + public void outlineHasInfiniteLoopInConservativeModeTest() throws IOException { + try ( + PdfDocument pdfDocument = new PdfDocument( + new PdfReader(SOURCE_FOLDER + "outlinesHaveInfiniteLoop.pdf"))) { + pdfDocument.getReader().setStrictnessLevel(StrictnessLevel.CONSERVATIVE); + Exception exception = Assert.assertThrows(PdfException.class, () -> pdfDocument.getOutlines(true)); + + //Hardcode indirectReference, cause there is no option to get this outline due to #getOutlines method + // will be thrown an exception. + Assert.assertEquals( + MessageFormatUtil.format( + KernelExceptionMessageConstant.CORRUPTED_OUTLINE_DICTIONARY_HAS_INFINITE_LOOP, + "<> /Prev 10 0 R /Title First Page >>"), + exception.getMessage()); + } + } + + @Test + public void createOutlinesWithDifferentVariantsOfChildrenTest() throws IOException { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PdfDocument pdfDocument = new PdfDocument(new PdfWriter(baos))) { + pdfDocument.getCatalog().setPageMode(PdfName.UseOutlines); + + PdfPage firstPage = pdfDocument.addNewPage(); + + PdfOutline a = pdfDocument.getOutlines(false); + PdfOutline b = a.addOutline("B"); + PdfOutline e = b.addOutline("E"); + PdfOutline f = e.addOutline("F"); + PdfOutline d = b.addOutline("D"); + PdfOutline c = a.addOutline("C"); + PdfOutline g = f.addOutline("G"); + PdfOutline h = f.addOutline("H"); + + a.addDestination(PdfExplicitDestination.createFit(firstPage)); + + PdfOutline resultedA = pdfDocument.getOutlines(true); + + // Asserting children of root outline. + Assert.assertEquals(2, resultedA.getAllChildren().size()); + Assert.assertEquals(resultedA, resultedA.getAllChildren().get(0).getParent()); + Assert.assertEquals(resultedA, resultedA.getAllChildren().get(1).getParent()); + Assert.assertTrue(resultedA.getAllChildren().get(1).getAllChildren().isEmpty()); + Assert.assertEquals(2, resultedA.getAllChildren().get(0).getAllChildren().size()); + + //Asserting children of B outline after reconstructing. + PdfOutline resultedB = resultedA.getAllChildren().get(0); + Assert.assertEquals(resultedB, resultedB.getAllChildren().get(0).getParent()); + Assert.assertEquals(resultedB, resultedB.getAllChildren().get(1).getParent()); + Assert.assertTrue(resultedB.getAllChildren().get(1).getAllChildren().isEmpty()); + Assert.assertEquals(1, resultedB.getAllChildren().get(0).getAllChildren().size()); + + //Asserting children of E outline after reconstructing. + PdfOutline resultedE = resultedB.getAllChildren().get(0); + Assert.assertEquals(resultedE, resultedE.getAllChildren().get(0).getParent()); + Assert.assertEquals(2, resultedE.getAllChildren().get(0).getAllChildren().size()); + + //Asserting children of F outline after reconstructing. + PdfOutline resultedF = resultedE.getAllChildren().get(0); + Assert.assertEquals(resultedF, resultedF.getAllChildren().get(0).getParent()); + Assert.assertEquals(resultedF, resultedF.getAllChildren().get(1).getParent()); + Assert.assertTrue(resultedF.getAllChildren().get(0).getAllChildren().isEmpty()); + Assert.assertTrue(resultedF.getAllChildren().get(1).getAllChildren().isEmpty()); + } + } } diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfPagesTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfPagesTest.java index e0c3e2b2d7..77359b49d1 100644 --- a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfPagesTest.java +++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfPagesTest.java @@ -57,6 +57,7 @@ This file is part of the iText (R) project. import com.itextpdf.kernel.pdf.xobject.PdfFormXObject; import com.itextpdf.kernel.pdf.xobject.PdfImageXObject; import com.itextpdf.kernel.utils.CompareTool; +import com.itextpdf.test.AssertUtil; import com.itextpdf.test.ExtendedITextTest; import com.itextpdf.test.annotations.LogMessage; import com.itextpdf.test.annotations.LogMessages; @@ -549,6 +550,40 @@ public void pageGetMediaBoxTooManyArgumentsTest() throws IOException { } + @Test + public void closeDocumentWithRecursivePagesNodeReferencesThrowsExTest() throws IOException { + try (PdfReader reader = new PdfReader(sourceFolder + "recursivePagesNodeReference.pdf"); + PdfWriter writer = new PdfWriter(new ByteArrayOutputStream()); + ) { + PdfDocument pdfDocument = new PdfDocument(reader, writer); + Exception e = Assert.assertThrows(PdfException.class, () -> pdfDocument.close()); + Assert.assertEquals(MessageFormatUtil.format(KernelExceptionMessageConstant.INVALID_PAGE_STRUCTURE, 2), e.getMessage()); + } + } + + @Test + public void getPageWithRecursivePagesNodeReferenceInAppendModeThrowExTest() throws IOException { + try (PdfReader reader = new PdfReader(sourceFolder + "recursivePagesNodeReference.pdf"); + PdfWriter writer = new PdfWriter(new ByteArrayOutputStream()); + PdfDocument pdfDocument = new PdfDocument(reader, writer, new StampingProperties().useAppendMode()); + ) { + Assert.assertEquals(2, pdfDocument.getNumberOfPages()); + Assert.assertNotNull(pdfDocument.getPage(1)); + Exception e = Assert.assertThrows(PdfException.class, () -> pdfDocument.getPage(2)); + Assert.assertEquals(MessageFormatUtil.format(KernelExceptionMessageConstant.INVALID_PAGE_STRUCTURE, 2), e.getMessage()); + } + } + + @Test + public void closeDocumentWithRecursivePagesNodeInAppendModeDoesNotThrowsTest() throws IOException { + try (PdfReader reader = new PdfReader(sourceFolder + "recursivePagesNodeReference.pdf"); + PdfWriter writer = new PdfWriter(new ByteArrayOutputStream()); + PdfDocument pdfDocument = new PdfDocument(reader, writer, new StampingProperties().useAppendMode()); + ) { + AssertUtil.doesNotThrow(() -> pdfDocument.close()); + } + } + @Test public void pageGetMediaBoxNotEnoughArgumentsTest() throws IOException { PdfReader reader = new PdfReader(sourceFolder + "helloWorldMediaboxNotEnoughArguments.pdf"); diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfXObjectTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfXObjectTest.java index d9cdd9c04f..1664bfa5db 100644 --- a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfXObjectTest.java +++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfXObjectTest.java @@ -164,7 +164,7 @@ public void createDocumentWithForms() throws IOException, InterruptedException //Create page1 and add forms to the page. PdfPage page1 = document.addNewPage(); canvas = new PdfCanvas(page1); - canvas.addXObject(form, 0, 0).addXObject(form, 50, 0).addXObject(form, 0, 50).addXObject(form, 50, 50); + canvas.addXObjectAt(form, 0, 0).addXObjectAt(form, 50, 0).addXObjectAt(form, 0, 50).addXObjectAt(form, 50, 50); canvas.release(); //Create form from the page1 and flush it. @@ -177,10 +177,10 @@ public void createDocumentWithForms() throws IOException, InterruptedException //Create page2 and add forms to the page. PdfPage page2 = document.addNewPage(); canvas = new PdfCanvas(page2); - canvas.addXObject(form, 0, 0); - canvas.addXObject(form, 0, 200); - canvas.addXObject(form, 200, 0); - canvas.addXObject(form, 200, 200); + canvas.addXObjectAt(form, 0, 0); + canvas.addXObjectAt(form, 0, 200); + canvas.addXObjectAt(form, 200, 0); + canvas.addXObjectAt(form, 200, 200); canvas.release(); page2.flush(); diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/SmartModeTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/SmartModeTest.java index 31613a8e3f..5bf98cf3b5 100644 --- a/kernel/src/test/java/com/itextpdf/kernel/pdf/SmartModeTest.java +++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/SmartModeTest.java @@ -231,7 +231,7 @@ public void pageCopyAsFormXObjectWithInheritedResourcesTest() throws IOException PdfPage page = copyPdfX.addNewPage(new PageSize(ps)); PdfCanvas canvas = new PdfCanvas(page); PdfFormXObject pageCopy = origPage.copyAsFormXObject(copyPdfX); - canvas.addXObject(pageCopy, 0, 0); + canvas.addXObjectAt(pageCopy, 0, 0); } } diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/TextExtractIllegalDifferencesTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/TextExtractIllegalDifferencesTest.java index 8d848707fe..9e18e4c49d 100644 --- a/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/TextExtractIllegalDifferencesTest.java +++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/TextExtractIllegalDifferencesTest.java @@ -45,6 +45,7 @@ This file is part of the iText (R) project. import com.itextpdf.io.logs.IoLogMessageConstant; import com.itextpdf.kernel.pdf.PdfDocument; import com.itextpdf.kernel.pdf.PdfReader; +import com.itextpdf.test.AssertUtil; import com.itextpdf.test.ExtendedITextTest; import com.itextpdf.test.annotations.LogMessage; import com.itextpdf.test.annotations.LogMessages; @@ -59,10 +60,20 @@ This file is part of the iText (R) project. public class TextExtractIllegalDifferencesTest extends ExtendedITextTest { private static final String sourceFolder = "./src/test/resources/com/itextpdf/kernel/parser/TextExtractIllegalDifferencesTest/"; + @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.DOCFONT_HAS_ILLEGAL_DIFFERENCES, count = 1)) + @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.DOCFONT_HAS_ILLEGAL_DIFFERENCES)) public void illegalDifference() throws IOException { - PdfDocument pdf = new PdfDocument(new PdfReader(sourceFolder + "illegalDifference.pdf")); - PdfTextExtractor.getTextFromPage(pdf.getFirstPage()); + try (PdfDocument pdf = new PdfDocument(new PdfReader(sourceFolder + "illegalDifference.pdf"))) { + AssertUtil.doesNotThrow(() -> PdfTextExtractor.getTextFromPage(pdf.getFirstPage())); + } + } + + @Test + @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.DOCFONT_HAS_ILLEGAL_DIFFERENCES, count = 2)) + public void illegalDifferenceType3Font() throws IOException { + try (PdfDocument pdf = new PdfDocument(new PdfReader(sourceFolder + "illegalDifferenceType3Font.pdf"))) { + AssertUtil.doesNotThrow(() -> PdfTextExtractor.getTextFromPage(pdf.getFirstPage())); + } } } diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/listener/RegexBasedLocationExtractionStrategyTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/listener/RegexBasedLocationExtractionStrategyTest.java index 668e0d24d9..99b52faf4d 100644 --- a/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/listener/RegexBasedLocationExtractionStrategyTest.java +++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/listener/RegexBasedLocationExtractionStrategyTest.java @@ -333,4 +333,16 @@ public void regexWithOnlyWhiteSpace() throws IOException { Assert.assertEquals(0, locations.size()); } + + @Test + public void sortCompareTest() throws IOException { + try (PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + "sortCompare.pdf"))) { + RegexBasedLocationExtractionStrategy extractionStrategy = new RegexBasedLocationExtractionStrategy("a"); + PdfCanvasProcessor pdfCanvasProcessor = new PdfCanvasProcessor(extractionStrategy); + pdfCanvasProcessor.processPageContent(pdfDocument.getPage(1)); + pdfCanvasProcessor.processPageContent(pdfDocument.getPage(2)); + List locations = new ArrayList<>(extractionStrategy.getResultantLocations()); + Assert.assertEquals(13, locations.size()); + } + } } diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/tagging/StructureTreeCopierUnitTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/tagging/StructureTreeCopierUnitTest.java new file mode 100644 index 0000000000..587330a3a5 --- /dev/null +++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/tagging/StructureTreeCopierUnitTest.java @@ -0,0 +1,97 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2021 iText Group NV + Authors: iText Software. + + This program is offered under a commercial and under the AGPL license. + For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + + AGPL licensing: + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +package com.itextpdf.kernel.pdf.tagging; + +import com.itextpdf.kernel.pdf.PdfDictionary; +import com.itextpdf.kernel.pdf.PdfName; +import com.itextpdf.kernel.pdf.PdfObject; +import com.itextpdf.test.ExtendedITextTest; +import com.itextpdf.test.annotations.type.UnitTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.util.HashMap; +import java.util.Map; + +@Category(UnitTest.class) +public class StructureTreeCopierUnitTest extends ExtendedITextTest { + + private static final Map td = new HashMap<>(); + private static final Map tr = new HashMap<>(); + private static final Map th = new HashMap<>(); + + static { + td.put(PdfName.S, PdfName.TD); + tr.put(PdfName.S, PdfName.TR); + th.put(PdfName.S, PdfName.TH); + } + + @Test + public void shouldTableElementBeCopiedTdTrTest() { + PdfDictionary obj = new PdfDictionary(td); + PdfDictionary parent = new PdfDictionary(tr); + + Assert.assertTrue(StructureTreeCopier.shouldTableElementBeCopied(obj, parent)); + } + + @Test + public void shouldTableElementBeCopiedThTrTest() { + PdfDictionary obj = new PdfDictionary(th); + PdfDictionary parent = new PdfDictionary(tr); + + Assert.assertTrue(StructureTreeCopier.shouldTableElementBeCopied(obj, parent)); + } + + @Test + public void shouldTableElementBeCopiedTdTdTest() { + PdfDictionary obj = new PdfDictionary(td); + PdfDictionary parent = new PdfDictionary(td); + + Assert.assertFalse(StructureTreeCopier.shouldTableElementBeCopied(obj, parent)); + } + + @Test + public void shouldTableElementBeCopiedTrTdTest() { + PdfDictionary obj = new PdfDictionary(tr); + PdfDictionary parent = new PdfDictionary(td); + + Assert.assertFalse(StructureTreeCopier.shouldTableElementBeCopied(obj, parent)); + } + + @Test + public void shouldTableElementBeCopiedTrTrTest() { + PdfDictionary obj = new PdfDictionary(tr); + PdfDictionary parent = new PdfDictionary(tr); + + Assert.assertFalse(StructureTreeCopier.shouldTableElementBeCopied(obj, parent)); + } + + @Test + public void shouldTableElementBeCopiedThThTest() { + PdfDictionary obj = new PdfDictionary(th); + PdfDictionary parent = new PdfDictionary(th); + + Assert.assertFalse(StructureTreeCopier.shouldTableElementBeCopied(obj, parent)); + } +} diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/xobject/ImageFromLanguageStandardLibraryTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/xobject/ImageFromLanguageStandardLibraryTest.java index 4c4f107896..c53c7c8a7a 100644 --- a/kernel/src/test/java/com/itextpdf/kernel/pdf/xobject/ImageFromLanguageStandardLibraryTest.java +++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/xobject/ImageFromLanguageStandardLibraryTest.java @@ -98,7 +98,7 @@ public void imageBinaryTransparencySameColorTest() throws java.io.IOException { .setFontAndSize(PdfFontFactory.createFont(), 12) .showText("Invisible image (both opaque and non opaque pixels have the same color)") .endText(); - canvas.addXObject(new PdfImageXObject( + canvas.addXObjectAt(new PdfImageXObject( ImageDataFactory.create(createBinaryTransparentAWTImage(null), null)), 36, 580); PdfDocument cmpDoc = new PdfDocument(new PdfReader(cmpFile)); @@ -135,7 +135,7 @@ public void imageBinaryTransparencyDifferentColorsTest() throws java.io.IOExcept .setFontAndSize(PdfFontFactory.createFont(), 12) .showText("Invisible image (both opaque and non opaque pixels have different colors)") .endText(); - canvas.addXObject(new PdfImageXObject( + canvas.addXObjectAt(new PdfImageXObject( ImageDataFactory.create(createBinaryTransparentAWTImage(Color.red), null)), 36, 580); PdfDocument cmpDoc = new PdfDocument(new PdfReader(cmpFile)); diff --git a/kernel/src/test/java/com/itextpdf/kernel/utils/PdfMergerTest.java b/kernel/src/test/java/com/itextpdf/kernel/utils/PdfMergerTest.java index 34446d3bb1..0d2ccfb946 100644 --- a/kernel/src/test/java/com/itextpdf/kernel/utils/PdfMergerTest.java +++ b/kernel/src/test/java/com/itextpdf/kernel/utils/PdfMergerTest.java @@ -43,15 +43,21 @@ This file is part of the iText (R) project. package com.itextpdf.kernel.utils; import com.itextpdf.io.logs.IoLogMessageConstant; +import com.itextpdf.kernel.colors.ColorConstants; import com.itextpdf.kernel.pdf.PdfDocument; +import com.itextpdf.kernel.pdf.PdfName; +import com.itextpdf.kernel.pdf.PdfOutline; +import com.itextpdf.kernel.pdf.PdfPage; import com.itextpdf.kernel.pdf.PdfReader; import com.itextpdf.kernel.pdf.PdfWriter; +import com.itextpdf.kernel.pdf.navigation.PdfExplicitDestination; import com.itextpdf.test.ExtendedITextTest; import com.itextpdf.test.annotations.LogMessage; import com.itextpdf.test.annotations.LogMessages; import com.itextpdf.test.annotations.type.IntegrationTest; import java.io.File; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; @@ -102,11 +108,7 @@ public void mergeDocumentTest01() throws IOException, InterruptedException { pdfDoc3.close(); - CompareTool compareTool = new CompareTool(); - String errorMessage = compareTool.compareByContent(resultFile, sourceFolder + "cmp_mergedResult01.pdf", destinationFolder, "diff_"); - if (errorMessage != null) { - Assert.fail(errorMessage); - } + Assert.assertNull(new CompareTool().compareByContent(resultFile, sourceFolder + "cmp_mergedResult01.pdf", destinationFolder, "diff_")); } @Test @@ -123,11 +125,7 @@ public void mergeDocumentOutlinesWithNullDestinationTest01() throws IOException, resultDocument.close(); sourceDocument.close(); - CompareTool compareTool = new CompareTool(); - String errorMessage = compareTool.compareByContent(resultFile, sourceFolder + "cmp_mergeDocumentOutlinesWithNullDestinationTest01.pdf", destinationFolder, "diff_"); - if (errorMessage != null) { - Assert.fail(errorMessage); - } + Assert.assertNull(new CompareTool().compareByContent(resultFile, sourceFolder + "cmp_mergeDocumentOutlinesWithNullDestinationTest01.pdf", destinationFolder, "diff_")); } @Test @@ -151,11 +149,7 @@ public void mergeDocumentTest02() throws IOException, InterruptedException { merger.merge(pdfDoc, 1, 1).merge(pdfDoc1, 1, 1).merge(pdfDoc2, 1, 1).close(); - CompareTool compareTool = new CompareTool(); - String errorMessage = compareTool.compareByContent(resultFile, sourceFolder + "cmp_mergedResult02.pdf", destinationFolder, "diff_"); - if (errorMessage != null) { - Assert.fail(errorMessage); - } + Assert.assertNull(new CompareTool().compareByContent(resultFile, sourceFolder + "cmp_mergedResult02.pdf", destinationFolder, "diff_")); } @Test @@ -246,29 +240,35 @@ public void mergeDocumentTest04() throws IOException, InterruptedException, Pars } @Test - public void mergeTableWithEmptyTdTest() throws IOException, ParserConfigurationException, SAXException { - String filename = sourceFolder + "tableWithEmptyTd.pdf"; - String resultFile = destinationFolder + "tableWithEmptyTdResult.pdf"; + public void mergeTableWithEmptyTdTest() throws IOException, ParserConfigurationException, SAXException, InterruptedException { + mergeAndCompareTagStructures("tableWithEmptyTd.pdf", 1, 1); + } - PdfReader reader = new PdfReader(filename); + @Test + public void mergeSplitTableWithEmptyTdTest() throws IOException, ParserConfigurationException, SAXException, InterruptedException { + mergeAndCompareTagStructures("splitTableWithEmptyTd.pdf", 2, 2); + } - PdfDocument sourceDoc = new PdfDocument(reader); - PdfDocument output = new PdfDocument(new PdfWriter(resultFile)); - output.setTagged(); - PdfMerger merger = new PdfMerger(output).setCloseSourceDocuments(true); - merger.merge(sourceDoc, 1, sourceDoc.getNumberOfPages()); - sourceDoc.close(); - reader.close(); - merger.close(); - output.close(); + @Test + public void mergeEmptyRowWithTagsTest() throws IOException, ParserConfigurationException, SAXException, InterruptedException { + mergeAndCompareTagStructures("emptyRowWithTags.pdf", 1, 1); + } - CompareTool compareTool = new CompareTool(); - String tagStructErrorMessage = compareTool.compareTagStructures(resultFile, sourceFolder + "cmp_tableWithEmptyTd.pdf"); + @Test + @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.SOURCE_DOCUMENT_HAS_ACROFORM_DICTIONARY)) + public void trInsideTdTableTest() throws ParserConfigurationException, SAXException, IOException, InterruptedException { + mergeAndCompareTagStructures("trInsideTdTable.pdf", 1, 1); + } - String errorMessage = tagStructErrorMessage == null ? "" : tagStructErrorMessage + "\n"; - if (!errorMessage.isEmpty()) { - Assert.fail(errorMessage); - } + @Test + public void tdInsideTdTableTest() throws ParserConfigurationException, SAXException, IOException, InterruptedException { + mergeAndCompareTagStructures("tdInsideTdTable.pdf", 1, 1); + } + + @Test + // TODO DEVSIX-5974 Empty tr isn't copied. + public void emptyTrTableTest() throws ParserConfigurationException, SAXException, IOException, InterruptedException { + mergeAndCompareTagStructures("emptyTrTable.pdf", 1, 1); } @Test @@ -401,7 +401,25 @@ public void mergePdfWithComplexOCGTwiceTest() throws IOException, InterruptedExc } @Test - @Ignore ("TODO: DEVSIX-5064 (when doing merge with outlines infinite loop occurs )") + public void stackOverflowErrorCycleReferenceOcgMergeTest() throws IOException, InterruptedException { + String outPdf = destinationFolder + "cycleReferenceMerged.pdf"; + String cmpPdf = sourceFolder + "cmp_stackOverflowErrorCycleReferenceOcrMerge.pdf"; + + PdfDocument pdfWithOCG = new PdfDocument(new PdfReader(sourceFolder + "sourceOCG1.pdf"), + new PdfWriter(outPdf)); + PdfDocument pdfWithOCGToMerge = new PdfDocument + (new PdfReader( sourceFolder + "stackOverflowErrorCycleReferenceOcgMerge.pdf")); // problem file + PdfMerger merger = new PdfMerger(pdfWithOCG); + merger.merge(pdfWithOCGToMerge, 1, pdfWithOCGToMerge.getNumberOfPages()); + pdfWithOCGToMerge.close(); + pdfWithOCG.close(); + Assert.assertNull(new CompareTool().compareByContent(outPdf, cmpPdf, destinationFolder)); + } + + @Test + @LogMessages(messages = { + @LogMessage(messageTemplate = IoLogMessageConstant.SOURCE_DOCUMENT_HAS_ACROFORM_DICTIONARY) + }) public void mergeOutlinesWithWrongStructureTest() throws IOException, InterruptedException { PdfDocument inputDoc = new PdfDocument(new PdfReader( sourceFolder + "infiniteLoopInOutlineStructure.pdf")); @@ -420,6 +438,87 @@ public void mergeOutlinesWithWrongStructureTest() throws IOException, Interrupte sourceFolder + "cmp_infiniteLoopInOutlineStructure.pdf", destinationFolder)); } + private static void mergeAndCompareTagStructures(String testName, int fromPage, int toPage) + throws IOException, ParserConfigurationException, SAXException, InterruptedException { + String src = sourceFolder + testName; + String dest = destinationFolder + testName; + String cmp = sourceFolder + "cmp_" + testName; + + PdfReader reader = new PdfReader(src); + + PdfDocument sourceDoc = new PdfDocument(reader); + PdfDocument output = new PdfDocument(new PdfWriter(dest)); + output.setTagged(); + PdfMerger merger = new PdfMerger(output).setCloseSourceDocuments(true); + merger.merge(sourceDoc, fromPage, toPage); + sourceDoc.close(); + reader.close(); + merger.close(); + output.close(); + + Assert.assertNull(new CompareTool().compareTagStructures(dest, cmp)); + } + + @Test + public void mergeDocumentWithColorPropertyInOutlineTest() throws IOException, InterruptedException { + String firstDocument = sourceFolder + "firstDocumentWithColorPropertyInOutline.pdf"; + String secondDocument = sourceFolder + "SecondDocumentWithColorPropertyInOutline.pdf"; + String cmpDocument = sourceFolder + "cmp_mergeOutlinesWithColorProperty.pdf"; + String mergedPdf = destinationFolder + "mergeOutlinesWithColorProperty.pdf"; + try (PdfDocument merged = new PdfDocument(new PdfWriter(mergedPdf)); + PdfDocument fileA = new PdfDocument(new PdfReader(firstDocument)); + PdfDocument fileB = new PdfDocument(new PdfReader(secondDocument))) { + PdfMerger merger = new PdfMerger(merged, false, true); + + merger.merge(fileA, 1, fileA.getNumberOfPages()); + merger.merge(fileB, 1, fileB.getNumberOfPages()); + + merger.close(); + } + + Assert.assertNull(new CompareTool().compareByContent(mergedPdf, cmpDocument, destinationFolder)); + } + + @Test + public void mergeDocumentWithStylePropertyInOutlineTest() throws IOException, InterruptedException { + String firstDocument = sourceFolder + "firstDocumentWithStylePropertyInOutline.pdf"; + String secondDocument = sourceFolder + "secondDocumentWithStylePropertyInOutline.pdf"; + String cmpPdf = sourceFolder + "cmp_mergeOutlineWithStyleProperty.pdf"; + String mergedPdf = destinationFolder + "mergeOutlineWithStyleProperty.pdf"; + + try (PdfDocument documentA = new PdfDocument(new PdfReader(firstDocument)); + PdfDocument documentB = new PdfDocument(new PdfReader(secondDocument)); + PdfDocument merged = new PdfDocument(new PdfWriter(mergedPdf))) { + PdfMerger merger = new PdfMerger(merged, false, true); + + merger.merge(documentA, 1, documentA.getNumberOfPages()); + merger.merge(documentB, 1, documentB.getNumberOfPages()); + merger.close(); + } + + Assert.assertNull(new CompareTool().compareByContent(mergedPdf, cmpPdf, destinationFolder)); + } + + @Test + public void mergePdfDocumentsWithCopingOutlinesTest() throws IOException, InterruptedException { + String firstPdfDocument = sourceFolder + "firstDocumentWithOutlines.pdf"; + String secondPdfDocument = sourceFolder + "secondDocumentWithOutlines.pdf"; + String cmpDocument = sourceFolder + "cmp_mergeDocumentsWithOutlines.pdf"; + String mergedDocument = destinationFolder + "mergeDocumentsWithOutlines.pdf"; + + try (PdfDocument documentA = new PdfDocument(new PdfReader(firstPdfDocument)); + PdfDocument documentB = new PdfDocument(new PdfReader(secondPdfDocument)); + PdfDocument mergedPdf = new PdfDocument(new PdfWriter(mergedDocument))) { + PdfMerger merger = new PdfMerger(mergedPdf, false, true); + merger.merge(documentA, 1, documentA.getNumberOfPages()); + merger.merge(documentB, 1, documentB.getNumberOfPages()); + + merger.close(); + } + + Assert.assertNull(new CompareTool().compareByContent(mergedDocument, cmpDocument, destinationFolder)); + } + private void mergePdfs(List sources, String destination) throws IOException { PdfDocument mergedDoc = new PdfDocument(new PdfWriter(destination)); PdfMerger merger = new PdfMerger(mergedDoc); diff --git a/kernel/src/test/java/com/itextpdf/kernel/utils/PdfSplitterTest.java b/kernel/src/test/java/com/itextpdf/kernel/utils/PdfSplitterTest.java index 93f32a019e..c6c2bfc409 100644 --- a/kernel/src/test/java/com/itextpdf/kernel/utils/PdfSplitterTest.java +++ b/kernel/src/test/java/com/itextpdf/kernel/utils/PdfSplitterTest.java @@ -256,4 +256,26 @@ protected PdfWriter getNextPdfWriter(PageRange documentPageRange) { sourceFolder + "cmp/" + "cmp_splitBySize_part" + i + ".pdf", destinationFolder, "diff_")); } } + + @Test + @LogMessages(messages = { + @LogMessage(messageTemplate = IoLogMessageConstant.SOURCE_DOCUMENT_HAS_ACROFORM_DICTIONARY , count = 10) + }) + public void splitByPageCountTest() throws IOException { + String inputFileName = sourceFolder + "iphone_user_guide.pdf"; + try (PdfDocument inputPdfDoc = new PdfDocument(new PdfReader(inputFileName))) { + PdfSplitter splitter = new PdfSplitter(inputPdfDoc); + + int pagesCount = inputPdfDoc.getNumberOfPages(); + int pagesCountInSplitDoc = 13; + + List splitDocuments = splitter.splitByPageCount(pagesCountInSplitDoc); + + for (PdfDocument doc : splitDocuments) { + doc.close(); + } + + Assert.assertEquals(pagesCount / pagesCountInSplitDoc, splitDocuments.size()); + } + } } diff --git a/kernel/src/test/resources/com/itextpdf/kernel/LICENSE-OFL-1.1.txt b/kernel/src/test/resources/com/itextpdf/kernel/LICENSE-OFL-1.1.txt new file mode 100644 index 0000000000..d952d62c06 --- /dev/null +++ b/kernel/src/test/resources/com/itextpdf/kernel/LICENSE-OFL-1.1.txt @@ -0,0 +1,92 @@ +This Font Software is licensed under the SIL Open Font License, +Version 1.1. + +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font +creation efforts of academic and linguistic communities, and to +provide a free and open framework in which fonts may be shared and +improved in partnership with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply to +any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software +components as distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, +deleting, or substituting -- in part or in whole -- any of the +components of the Original Version, by changing formats or by porting +the Font Software to a new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, +modify, redistribute, and sell modified and unmodified copies of the +Font Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, in +Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the +corresponding Copyright Holder. This restriction only applies to the +primary font name as presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created using +the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/kernel/src/test/resources/com/itextpdf/kernel/NOTICE.txt b/kernel/src/test/resources/com/itextpdf/kernel/NOTICE.txt new file mode 100644 index 0000000000..5f9909f1e4 --- /dev/null +++ b/kernel/src/test/resources/com/itextpdf/kernel/NOTICE.txt @@ -0,0 +1,2 @@ +This software uses the following test resources under the following licenses: +| NotoSansOldItalic-Regular.ttf | OFL-1.1 | LICENSE-OFL-1.1.txt | In development version of font based on commit 4cdde035fd5138d6653a2176ba728b5b6f8cc533 (30.10.2019) from repository: "https://github.com/googlefonts/noto-fonts" diff --git a/kernel/src/test/resources/com/itextpdf/kernel/font/PdfType0FontTest/NotoSansOldItalic-Regular.ttf b/kernel/src/test/resources/com/itextpdf/kernel/font/PdfType0FontTest/NotoSansOldItalic-Regular.ttf new file mode 100644 index 0000000000..83ff12fe2d Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/font/PdfType0FontTest/NotoSansOldItalic-Regular.ttf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/parser/RegexBasedLocationExtractionStrategyTest/sortCompare.pdf b/kernel/src/test/resources/com/itextpdf/kernel/parser/RegexBasedLocationExtractionStrategyTest/sortCompare.pdf new file mode 100644 index 0000000000..b021d30a9c Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/parser/RegexBasedLocationExtractionStrategyTest/sortCompare.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/parser/TextExtractIllegalDifferencesTest/illegalDifferenceType3Font.pdf b/kernel/src/test/resources/com/itextpdf/kernel/parser/TextExtractIllegalDifferencesTest/illegalDifferenceType3Font.pdf new file mode 100644 index 0000000000..e178b4f8b4 Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/parser/TextExtractIllegalDifferencesTest/illegalDifferenceType3Font.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfOutlineTest/outlinesHaveInfiniteLoop.pdf b/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfOutlineTest/outlinesHaveInfiniteLoop.pdf new file mode 100644 index 0000000000..333ba62f85 Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfOutlineTest/outlinesHaveInfiniteLoop.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfOutlineTest/outlinesNoParentLink.pdf b/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfOutlineTest/outlinesNoParentLink.pdf new file mode 100644 index 0000000000..f1ff14ed38 Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfOutlineTest/outlinesNoParentLink.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfPagesTest/recursivePagesNodeReference.pdf b/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfPagesTest/recursivePagesNodeReference.pdf new file mode 100644 index 0000000000..7185254aa8 Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfPagesTest/recursivePagesNodeReference.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfStructElemTest/cmp_structTreeCopyingTest01.pdf b/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfStructElemTest/cmp_structTreeCopyingTest01.pdf index c7fcffe880..e5a21f5fac 100644 Binary files a/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfStructElemTest/cmp_structTreeCopyingTest01.pdf and b/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfStructElemTest/cmp_structTreeCopyingTest01.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfStructElemTest/cmp_structTreeCopyingTest02.pdf b/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfStructElemTest/cmp_structTreeCopyingTest02.pdf index bcbe2ceab0..8d18fef5a8 100644 Binary files a/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfStructElemTest/cmp_structTreeCopyingTest02.pdf and b/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfStructElemTest/cmp_structTreeCopyingTest02.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfStructElemTest/cmp_structTreeCopyingTest03.pdf b/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfStructElemTest/cmp_structTreeCopyingTest03.pdf index 78836e7f9a..202c3e93f8 100644 Binary files a/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfStructElemTest/cmp_structTreeCopyingTest03.pdf and b/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfStructElemTest/cmp_structTreeCopyingTest03.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfStructElemTest/cmp_structTreeCopyingTest04.pdf b/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfStructElemTest/cmp_structTreeCopyingTest04.pdf index 6ec3dc2eb3..81fc95e570 100644 Binary files a/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfStructElemTest/cmp_structTreeCopyingTest04.pdf and b/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfStructElemTest/cmp_structTreeCopyingTest04.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfStructElemTest/cmp_structTreeCopyingTest06.pdf b/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfStructElemTest/cmp_structTreeCopyingTest06.pdf index 7509180be7..876c213778 100644 Binary files a/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfStructElemTest/cmp_structTreeCopyingTest06.pdf and b/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfStructElemTest/cmp_structTreeCopyingTest06.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfXObjectTest/cmp_documentWithForms1.pdf b/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfXObjectTest/cmp_documentWithForms1.pdf index 7775092002..1b4d0d7b49 100644 Binary files a/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfXObjectTest/cmp_documentWithForms1.pdf and b/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfXObjectTest/cmp_documentWithForms1.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/pdf/SmartModeTest/cmp_pageCopyAsFormXObjectWithInheritedResourcesTest.pdf b/kernel/src/test/resources/com/itextpdf/kernel/pdf/SmartModeTest/cmp_pageCopyAsFormXObjectWithInheritedResourcesTest.pdf index c99d141a14..408b7d333a 100644 Binary files a/kernel/src/test/resources/com/itextpdf/kernel/pdf/SmartModeTest/cmp_pageCopyAsFormXObjectWithInheritedResourcesTest.pdf and b/kernel/src/test/resources/com/itextpdf/kernel/pdf/SmartModeTest/cmp_pageCopyAsFormXObjectWithInheritedResourcesTest.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/SecondDocumentWithColorPropertyInOutline.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/SecondDocumentWithColorPropertyInOutline.pdf new file mode 100644 index 0000000000..8b49345354 Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/SecondDocumentWithColorPropertyInOutline.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_emptyRowWithTags.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_emptyRowWithTags.pdf new file mode 100644 index 0000000000..9da1545ba8 Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_emptyRowWithTags.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_emptyTrTable.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_emptyTrTable.pdf new file mode 100644 index 0000000000..69190ea2a4 Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_emptyTrTable.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_infiniteLoopInOutlineStructure.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_infiniteLoopInOutlineStructure.pdf new file mode 100644 index 0000000000..3abdf93c53 Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_infiniteLoopInOutlineStructure.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_mergeDocumentsWithOutlines.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_mergeDocumentsWithOutlines.pdf new file mode 100644 index 0000000000..a5ac075937 Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_mergeDocumentsWithOutlines.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_mergeOutlineWithStyleProperty.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_mergeOutlineWithStyleProperty.pdf new file mode 100644 index 0000000000..37402db81d Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_mergeOutlineWithStyleProperty.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_mergeOutlinesWithColorProperty.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_mergeOutlinesWithColorProperty.pdf new file mode 100644 index 0000000000..c9f417d1ee Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_mergeOutlinesWithColorProperty.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_mergedResult03.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_mergedResult03.pdf index 25896c31e6..6af763b90f 100644 Binary files a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_mergedResult03.pdf and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_mergedResult03.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_mergedResult04.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_mergedResult04.pdf index e29f19d068..f362958bff 100644 Binary files a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_mergedResult04.pdf and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_mergedResult04.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_splitTableWithEmptyTd.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_splitTableWithEmptyTd.pdf new file mode 100644 index 0000000000..ecb9409696 Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_splitTableWithEmptyTd.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_stackOverflowErrorCycleReferenceOcrMerge.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_stackOverflowErrorCycleReferenceOcrMerge.pdf new file mode 100644 index 0000000000..a5d73f83dc Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_stackOverflowErrorCycleReferenceOcrMerge.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_tableWithEmptyTd.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_tableWithEmptyTd.pdf index 84e16d7352..a1b56027b7 100644 Binary files a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_tableWithEmptyTd.pdf and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_tableWithEmptyTd.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_tdInsideTdTable.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_tdInsideTdTable.pdf new file mode 100644 index 0000000000..e9348b5dc5 Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_tdInsideTdTable.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_trInsideTdTable.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_trInsideTdTable.pdf new file mode 100644 index 0000000000..8076713366 Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/cmp_trInsideTdTable.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/emptyRowWithTags.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/emptyRowWithTags.pdf new file mode 100644 index 0000000000..60902297da Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/emptyRowWithTags.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/emptyTrTable.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/emptyTrTable.pdf new file mode 100644 index 0000000000..7130771cf9 Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/emptyTrTable.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/firstDocumentWithColorPropertyInOutline.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/firstDocumentWithColorPropertyInOutline.pdf new file mode 100644 index 0000000000..f4239c215f Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/firstDocumentWithColorPropertyInOutline.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/firstDocumentWithOutlines.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/firstDocumentWithOutlines.pdf new file mode 100644 index 0000000000..8f746e17aa Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/firstDocumentWithOutlines.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/firstDocumentWithStylePropertyInOutline.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/firstDocumentWithStylePropertyInOutline.pdf new file mode 100644 index 0000000000..81fb035767 Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/firstDocumentWithStylePropertyInOutline.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/secondDocumentWithOutlines.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/secondDocumentWithOutlines.pdf new file mode 100644 index 0000000000..4a497363ac Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/secondDocumentWithOutlines.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/secondDocumentWithStylePropertyInOutline.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/secondDocumentWithStylePropertyInOutline.pdf new file mode 100644 index 0000000000..a2bd50332e Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/secondDocumentWithStylePropertyInOutline.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/splitTableWithEmptyTd.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/splitTableWithEmptyTd.pdf new file mode 100644 index 0000000000..246efa644f Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/splitTableWithEmptyTd.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/stackOverflowErrorCycleReferenceOcgMerge.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/stackOverflowErrorCycleReferenceOcgMerge.pdf new file mode 100644 index 0000000000..9c92896635 Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/stackOverflowErrorCycleReferenceOcgMerge.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/tdInsideTdTable.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/tdInsideTdTable.pdf new file mode 100644 index 0000000000..f0dec670bc Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/tdInsideTdTable.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/trInsideTdTable.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/trInsideTdTable.pdf new file mode 100644 index 0000000000..78f5667477 Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfMergerTest/trInsideTdTable.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument1_1.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument1_1.pdf index aeeab3800e..b279fe39a1 100644 Binary files a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument1_1.pdf and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument1_1.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument1_2.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument1_2.pdf index adae0d9911..b0a8fba077 100644 Binary files a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument1_2.pdf and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument1_2.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument1_3.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument1_3.pdf index 52b80e8451..8f03e39f17 100644 Binary files a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument1_3.pdf and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument1_3.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument2_1.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument2_1.pdf index ec642d8832..91ac094652 100644 Binary files a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument2_1.pdf and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument2_1.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument2_2.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument2_2.pdf index 5ed0194333..c5614e113f 100644 Binary files a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument2_2.pdf and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument2_2.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument3_1.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument3_1.pdf index 4d3b2901b1..46e56162f9 100644 Binary files a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument3_1.pdf and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument3_1.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument3_2.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument3_2.pdf index e7866d3ff3..e4d87449c2 100644 Binary files a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument3_2.pdf and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument3_2.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument4_1.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument4_1.pdf index 29e78a6165..8666246166 100644 Binary files a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument4_1.pdf and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument4_1.pdf differ diff --git a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument4_2.pdf b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument4_2.pdf index 5535ad7b51..c56f9f751d 100644 Binary files a/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument4_2.pdf and b/kernel/src/test/resources/com/itextpdf/kernel/utils/PdfSplitterTest/cmp/cmp_splitDocument4_2.pdf differ diff --git a/layout/pom.xml b/layout/pom.xml index 9f44a1e938..c2e71edee7 100644 --- a/layout/pom.xml +++ b/layout/pom.xml @@ -4,7 +4,7 @@ com.itextpdf root - 7.2.0 + 7.2.1 layout iText 7 - layout diff --git a/layout/src/main/java/com/itextpdf/layout/element/Table.java b/layout/src/main/java/com/itextpdf/layout/element/Table.java index 86ee4f6348..6fba6a517f 100644 --- a/layout/src/main/java/com/itextpdf/layout/element/Table.java +++ b/layout/src/main/java/com/itextpdf/layout/element/Table.java @@ -576,7 +576,6 @@ public Table startNewRow() { rows.add(new Cell[columnWidths.length]); } return this; - //TODO when rendering starts, make sure, that last row is not empty. } /** diff --git a/layout/src/main/java/com/itextpdf/layout/logs/LayoutLogMessageConstant.java b/layout/src/main/java/com/itextpdf/layout/logs/LayoutLogMessageConstant.java new file mode 100644 index 0000000000..5efd7a5197 --- /dev/null +++ b/layout/src/main/java/com/itextpdf/layout/logs/LayoutLogMessageConstant.java @@ -0,0 +1,35 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2021 iText Group NV + Authors: iText Software. + + This program is offered under a commercial and under the AGPL license. + For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + + AGPL licensing: + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +package com.itextpdf.layout.logs; + +/** + * Class containing constants to be used in layout. + */ +public final class LayoutLogMessageConstant { + + public static final String ELEMENT_DOES_NOT_FIT_AREA = "Element does not fit current area. {0}"; + + private LayoutLogMessageConstant() { + //Private constructor will prevent the instantiation of this class directly + } +} diff --git a/layout/src/main/java/com/itextpdf/layout/margincollapse/MarginsCollapseHandler.java b/layout/src/main/java/com/itextpdf/layout/margincollapse/MarginsCollapseHandler.java index efbbf5c6f9..cbddee1b97 100644 --- a/layout/src/main/java/com/itextpdf/layout/margincollapse/MarginsCollapseHandler.java +++ b/layout/src/main/java/com/itextpdf/layout/margincollapse/MarginsCollapseHandler.java @@ -207,8 +207,8 @@ public void endChildMarginsHandling(Rectangle layoutBox) { } public void startMarginsCollapse(Rectangle parentBBox) { - collapseInfo.getCollapseBefore().joinMargin(getModelTopMargin(renderer)); - collapseInfo.getCollapseAfter().joinMargin(getModelBottomMargin(renderer)); + collapseInfo.getCollapseBefore().joinMargin(defineTopMarginValueForCollapse(renderer)); + collapseInfo.getCollapseAfter().joinMargin(defineBottomMarginValueForCollapse(renderer)); if (!firstChildMarginAdjoinedToParent(renderer)) { float topIndent = collapseInfo.getCollapseBefore().getCollapsedMarginsSize(); @@ -253,7 +253,7 @@ public void endMarginsCollapse(Rectangle layoutBox) { } else { ownCollapseAfter = new MarginsCollapse(); } - ownCollapseAfter.joinMargin(getModelBottomMargin(renderer)); + ownCollapseAfter.joinMargin(defineBottomMarginValueForCollapse(renderer)); collapseInfo.setOwnCollapseAfter(ownCollapseAfter); if (collapseInfo.isSelfCollapsing()) { @@ -544,33 +544,19 @@ private static boolean hasPositiveHeight(IRenderer renderer) { } private static boolean hasTopPadding(IRenderer renderer) { - UnitValue padding = renderer.getModelElement().getProperty(Property.PADDING_TOP); - if (null != padding && !padding.isPointValue()) { - Logger logger = LoggerFactory.getLogger(MarginsCollapseHandler.class); - logger.error(MessageFormatUtil.format(IoLogMessageConstant.PROPERTY_IN_PERCENTS_NOT_SUPPORTED, - Property.PADDING_TOP)); - } - return padding != null && padding.getValue() > 0; + return MarginsCollapseHandler.hasPadding(renderer, Property.PADDING_TOP); } private static boolean hasBottomPadding(IRenderer renderer) { - UnitValue padding = renderer.getModelElement().getProperty(Property.PADDING_BOTTOM); - if (null != padding && !padding.isPointValue()) { - Logger logger = LoggerFactory.getLogger(MarginsCollapseHandler.class); - logger.error(MessageFormatUtil.format(IoLogMessageConstant.PROPERTY_IN_PERCENTS_NOT_SUPPORTED, - Property.PADDING_BOTTOM)); - } - return padding != null && padding.getValue() > 0; + return MarginsCollapseHandler.hasPadding(renderer, Property.PADDING_BOTTOM); } private static boolean hasTopBorders(IRenderer renderer) { - IPropertyContainer modelElement = renderer.getModelElement(); - return modelElement.hasProperty(Property.BORDER_TOP) || modelElement.hasProperty(Property.BORDER); + return MarginsCollapseHandler.hasBorders(renderer, Property.BORDER_TOP); } private static boolean hasBottomBorders(IRenderer renderer) { - IPropertyContainer modelElement = renderer.getModelElement(); - return modelElement.hasProperty(Property.BORDER_BOTTOM) || modelElement.hasProperty(Property.BORDER); + return MarginsCollapseHandler.hasBorders(renderer, Property.BORDER_BOTTOM); } private static boolean rendererIsFloated(IRenderer renderer) { @@ -581,41 +567,56 @@ private static boolean rendererIsFloated(IRenderer renderer) { return floatPropertyValue != null && !floatPropertyValue.equals(FloatPropertyValue.NONE); } - private static float getModelTopMargin(IRenderer renderer) { - UnitValue marginUV = renderer.getModelElement().getProperty(Property.MARGIN_TOP); - if (null != marginUV && !marginUV.isPointValue()) { - Logger logger = LoggerFactory.getLogger(MarginsCollapseHandler.class); - logger.error(MessageFormatUtil.format(IoLogMessageConstant.PROPERTY_IN_PERCENTS_NOT_SUPPORTED, - Property.MARGIN_TOP)); - } - // TODO Concerning "renderer instanceof CellRenderer" check: may be try to apply more general solution in future - return marginUV != null && !(renderer instanceof CellRenderer) ? marginUV.getValue() : 0; + private static float defineTopMarginValueForCollapse(IRenderer renderer) { + return MarginsCollapseHandler.defineMarginValueForCollapse(renderer, Property.MARGIN_TOP); } private static void ignoreModelTopMargin(IRenderer renderer) { - renderer.setProperty(Property.MARGIN_TOP, UnitValue.createPointValue(0f)); + MarginsCollapseHandler.overrideModelTopMargin(renderer, 0f); } private static void overrideModelTopMargin(IRenderer renderer, float collapsedMargins) { - renderer.setProperty(Property.MARGIN_TOP, UnitValue.createPointValue(collapsedMargins)); + MarginsCollapseHandler.overrideModelMargin(renderer, Property.MARGIN_TOP, collapsedMargins); } - private static float getModelBottomMargin(IRenderer renderer) { - UnitValue marginUV = renderer.getModelElement().getProperty(Property.MARGIN_BOTTOM); + private static float defineBottomMarginValueForCollapse(IRenderer renderer) { + return MarginsCollapseHandler.defineMarginValueForCollapse(renderer, Property.MARGIN_BOTTOM); + } + + private static void ignoreModelBottomMargin(IRenderer renderer) { + MarginsCollapseHandler.overrideModelBottomMargin(renderer, 0f); + } + + private static void overrideModelBottomMargin(IRenderer renderer, float collapsedMargins) { + MarginsCollapseHandler.overrideModelMargin(renderer, Property.MARGIN_BOTTOM, collapsedMargins); + } + + private static float defineMarginValueForCollapse(IRenderer renderer, int property) { + UnitValue marginUV = renderer.getModelElement().getProperty(property); if (null != marginUV && !marginUV.isPointValue()) { Logger logger = LoggerFactory.getLogger(MarginsCollapseHandler.class); logger.error(MessageFormatUtil.format(IoLogMessageConstant.PROPERTY_IN_PERCENTS_NOT_SUPPORTED, - Property.MARGIN_TOP)); + property)); } - // TODO Concerning "renderer instanceof CellRenderer" check: may be try to apply more general solution in future return marginUV != null && !(renderer instanceof CellRenderer) ? marginUV.getValue() : 0; } - private static void ignoreModelBottomMargin(IRenderer renderer) { - renderer.setProperty(Property.MARGIN_BOTTOM, UnitValue.createPointValue(0f)); + private static void overrideModelMargin(IRenderer renderer, int property, float collapsedMargins) { + renderer.setProperty(property, UnitValue.createPointValue(collapsedMargins)); } - private static void overrideModelBottomMargin(IRenderer renderer, float collapsedMargins) { - renderer.setProperty(Property.MARGIN_BOTTOM, UnitValue.createPointValue(collapsedMargins)); + private static boolean hasPadding(IRenderer renderer, int property) { + UnitValue padding = renderer.getModelElement().getProperty(property); + if (null != padding && !padding.isPointValue()) { + Logger logger = LoggerFactory.getLogger(MarginsCollapseHandler.class); + logger.error(MessageFormatUtil.format(IoLogMessageConstant.PROPERTY_IN_PERCENTS_NOT_SUPPORTED, + property)); + } + return padding != null && padding.getValue() > 0; + } + + private static boolean hasBorders(IRenderer renderer, int property) { + IPropertyContainer modelElement = renderer.getModelElement(); + return modelElement.hasProperty(property) || modelElement.hasProperty(Property.BORDER); } } diff --git a/layout/src/main/java/com/itextpdf/layout/renderer/BlockRenderer.java b/layout/src/main/java/com/itextpdf/layout/renderer/BlockRenderer.java index 974bcadf87..133b8d6628 100644 --- a/layout/src/main/java/com/itextpdf/layout/renderer/BlockRenderer.java +++ b/layout/src/main/java/com/itextpdf/layout/renderer/BlockRenderer.java @@ -58,6 +58,7 @@ This file is part of the iText (R) project. import com.itextpdf.layout.layout.LayoutResult; import com.itextpdf.layout.layout.MinMaxWidthLayoutResult; import com.itextpdf.layout.layout.PositionedLayoutContext; +import com.itextpdf.layout.logs.LayoutLogMessageConstant; import com.itextpdf.layout.margincollapse.MarginsCollapseHandler; import com.itextpdf.layout.margincollapse.MarginsCollapseInfo; import com.itextpdf.layout.minmaxwidth.MinMaxWidth; @@ -446,7 +447,7 @@ public LayoutResult layout(LayoutContext layoutContext) { if (isNotFittingLayoutArea(layoutContext.getArea())) { if (isNotFittingWidth(layoutContext.getArea()) && !isNotFittingHeight(layoutContext.getArea())) { LoggerFactory.getLogger(getClass()) - .warn(MessageFormatUtil.format(IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, + .warn(MessageFormatUtil.format(LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, "It fits by height so it will be forced placed")); } else if (!Boolean.TRUE.equals(getPropertyAsBoolean(Property.FORCED_PLACEMENT))) { floatRendererAreas.retainAll(nonChildFloatingRendererAreas); diff --git a/layout/src/main/java/com/itextpdf/layout/renderer/CollapsedTableBorders.java b/layout/src/main/java/com/itextpdf/layout/renderer/CollapsedTableBorders.java index 35d1391405..42e4ea46c6 100644 --- a/layout/src/main/java/com/itextpdf/layout/renderer/CollapsedTableBorders.java +++ b/layout/src/main/java/com/itextpdf/layout/renderer/CollapsedTableBorders.java @@ -50,21 +50,33 @@ This file is part of the iText (R) project. import com.itextpdf.layout.properties.Property; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; class CollapsedTableBorders extends TableBorders { /** - * The list of the cells' borders which should be collapsed - * with the first border of this TableRenderer instance, to be drawn on the area. + * Horizontal borders to be collapsed with + * the first-on-the-area row's cell top borders of this TableRenderer instance. */ private List topBorderCollapseWith = new ArrayList(); /** - * The list of the cells' borders which should be collapsed - * with the last border of this TableRenderer instance, to be drawn on the area. + * Horizontal borders to be collapsed with + * the last-on-the-area row's cell bottom borders of this TableRenderer instance. */ private List bottomBorderCollapseWith = new ArrayList(); + // NOTE: Currently body's top border is written at header level and footer's top border is written + // at body's level, hence there is no need in the same array for vertical top borders. + /** + * Vertical borders to be collapsed with + * the last-on-the-area row's cell bottom borders of this TableRenderer instance. + */ + private List verticalBottomBorderCollapseWith = null; + + private static Comparator borderComparator = new BorderComparator(); + // region constructors public CollapsedTableBorders(List rows, int numberOfColumns, Border[] tableBoundingBorders) { super(rows, numberOfColumns, tableBoundingBorders); @@ -124,12 +136,32 @@ public float[] getCellBorderIndents(int row, int col, int rowspan, int colspan) return indents; } + /** + * Gets vertical borders which cross the top horizontal border. + * + * @return vertical borders which cross the top horizontal border + */ + public List getVerticalBordersCrossingTopHorizontalBorder() { + List borders = new ArrayList<>(numberOfColumns + 1); + for (int i = 0; i <= numberOfColumns; i++) { + final List verticalBorder = getVerticalBorder(i); + // the passed index indicates the index of the border on the page, not in the entire document + Border borderToAdd = startRow - largeTableIndexOffset < verticalBorder.size() + ? verticalBorder.get(startRow - largeTableIndexOffset) : null; + borders.add(borderToAdd); + } + return borders; + } + + @Override public List getVerticalBorder(int index) { if (index == 0) { - List borderList = TableBorderUtil.createAndFillBorderList(null, tableBoundingBorders[3], verticalBorders.get(0).size()); + List borderList = TableBorderUtil + .createAndFillBorderList(null, tableBoundingBorders[3], verticalBorders.get(0).size()); return getCollapsedList(verticalBorders.get(0), borderList); } else if (index == numberOfColumns) { - List borderList = TableBorderUtil.createAndFillBorderList(null, tableBoundingBorders[1], verticalBorders.get(0).size()); + List borderList = TableBorderUtil.createAndFillBorderList(null, tableBoundingBorders[1], + verticalBorders.get(verticalBorders.size() - 1).size()); return getCollapsedList(verticalBorders.get(verticalBorders.size() - 1), borderList); } else { return verticalBorders.get(index); @@ -213,11 +245,16 @@ public CollapsedTableBorders setTopBorderCollapseWith(List topBorderColl return this; } - public CollapsedTableBorders setBottomBorderCollapseWith(List bottomBorderCollapseWith) { + public CollapsedTableBorders setBottomBorderCollapseWith(List bottomBorderCollapseWith, + List verticalBordersCrossingBottomBorder) { this.bottomBorderCollapseWith = new ArrayList(); if (null != bottomBorderCollapseWith) { this.bottomBorderCollapseWith.addAll(bottomBorderCollapseWith); } + this.verticalBottomBorderCollapseWith = null; + if (null != verticalBordersCrossingBottomBorder) { + this.verticalBottomBorderCollapseWith = new ArrayList(verticalBordersCrossingBottomBorder); + } return this; } //endregion @@ -329,28 +366,7 @@ protected void buildBordersArrays(CellRenderer cell, int row, boolean isNeighbou // region lowlevel protected boolean checkAndReplaceBorderInArray(List> borderArray, int i, int j, Border borderToAdd, boolean hasPriority) { -// if (borderArray.size() <= i) { -// for (int count = borderArray.size(); count <= i; count++) { -// borderArray.add(new ArrayList()); -// } -// } List borders = borderArray.get(i); -// if (borders.isEmpty()) { -// for (int count = 0; count < j; count++) { -// borders.add(null); -// } -// borders.add(borderToAdd); -// return true; -// } -// if (borders.size() == j) { -// borders.add(borderToAdd); -// return true; -// } -// if (borders.size() < j) { -// for (int count = borders.size(); count <= j; count++) { -// borders.add(count, null); -// } -// } Border neighbour = borders.get(j); if (neighbour == null) { borders.set(j, borderToAdd); @@ -372,85 +388,132 @@ protected boolean checkAndReplaceBorderInArray(List> borderArray, i // endregion // region draw - protected TableBorders drawHorizontalBorder(int i, float startX, float y1, PdfCanvas canvas, float[] countedColumnWidth) { - List borders = getHorizontalBorder(startRow /*- largeTableIndexOffset*/ + i); + protected TableBorders drawHorizontalBorder(PdfCanvas canvas, TableBorderDescriptor borderDescriptor) { + int i = borderDescriptor.getBorderIndex(); + float startX = borderDescriptor.getMainCoordinateStart(); + float y1 = borderDescriptor.getCrossCoordinate(); + float[] countedColumnWidth = borderDescriptor.getMainCoordinateWidths(); + + List horizontalBorder = getHorizontalBorder(startRow + i); float x1 = startX; float x2 = x1 + countedColumnWidth[0]; - if (i == 0) { - Border firstBorder = getFirstVerticalBorder().get(startRow - largeTableIndexOffset); - if (firstBorder != null) { - x1 -= firstBorder.getWidth() / 2; - } - } else if (i == finishRow - startRow + 1) { - Border firstBorder = getFirstVerticalBorder().get(startRow - largeTableIndexOffset + finishRow - startRow + 1 - 1); - if (firstBorder != null) { - x1 -= firstBorder.getWidth() / 2; - } - } - int j; - for (j = 1; j < borders.size(); j++) { - Border prevBorder = borders.get(j - 1); - Border curBorder = borders.get(j); - if (prevBorder != null) { - if (!prevBorder.equals(curBorder)) { - prevBorder.drawCellBorder(canvas, x1, y1, x2, y1, Border.Side.NONE); - x1 = x2; + for (int j = 1; j <= horizontalBorder.size(); j++) { + Border currentBorder = horizontalBorder.get(j - 1); + Border nextBorder = j < horizontalBorder.size() ? horizontalBorder.get(j) : null; + if (currentBorder != null) { + List crossingBordersAtStart = getCrossingBorders(i, j - 1); + float startCornerWidth = getWidestBorderWidth(crossingBordersAtStart.get(1), + crossingBordersAtStart.get(3)); + List crossingBordersAtEnd = getCrossingBorders(i, j); + float endCornerWidth = getWidestBorderWidth(crossingBordersAtEnd.get(1), crossingBordersAtEnd.get(3)); + + // TODO DEVSIX-5962 Once the ticket is done, remove this workaround, which allows + // horizontal borders to win at vertical-0. Bear in mind that this workaround helps + // in standard cases, when borders are of the same width. If they are not then + // this workaround doesn't help to improve corner collapsing + if (1 == j) { + crossingBordersAtStart.add(0, currentBorder); + } + if (0 == i) { + if (1 != j) { + crossingBordersAtStart.add(0, crossingBordersAtStart.get(3)); + } + crossingBordersAtEnd.add(0, crossingBordersAtEnd.get(3)); } + + Collections.sort(crossingBordersAtStart, borderComparator); + Collections.sort(crossingBordersAtEnd, borderComparator); + + float x1Offset = currentBorder.equals(crossingBordersAtStart.get(0)) + ? -startCornerWidth / 2 + : startCornerWidth / 2; + float x2Offset = currentBorder.equals(crossingBordersAtEnd.get(0)) + ? endCornerWidth / 2 + : -endCornerWidth / 2; + currentBorder.drawCellBorder(canvas, x1 + x1Offset, y1, x2 + x2Offset, y1, Border.Side.NONE); + x1 = x2; } else { + // if current border is null, then just skip it's processing. + // Border corners will be processed by borders which are not null. x1 += countedColumnWidth[j - 1]; x2 = x1; } - if (curBorder != null) { + if (nextBorder != null && j != horizontalBorder.size()) { x2 += countedColumnWidth[j]; } } - - Border lastBorder = borders.size() > j - 1 ? borders.get(j - 1) : null; - if (lastBorder != null) { - if (i == 0) { - if (getVerticalBorder(j).get(startRow - largeTableIndexOffset + i) != null) - x2 += getVerticalBorder(j).get(startRow - largeTableIndexOffset + i).getWidth() / 2; - } else if (i == finishRow - startRow + 1 && getVerticalBorder(j).size() > startRow - largeTableIndexOffset + i - 1 && getVerticalBorder(j).get(startRow - largeTableIndexOffset + i - 1) != null) { - x2 += getVerticalBorder(j).get(startRow - largeTableIndexOffset + i - 1).getWidth() / 2; - } - - lastBorder.drawCellBorder(canvas, x1, y1, x2, y1, Border.Side.NONE); - } return this; } - protected TableBorders drawVerticalBorder(int i, float startY, float x1, PdfCanvas canvas, List heights) { + protected TableBorders drawVerticalBorder(PdfCanvas canvas, TableBorderDescriptor borderDescriptor) { + int i = borderDescriptor.getBorderIndex(); + float startY = borderDescriptor.getMainCoordinateStart(); + float x1 = borderDescriptor.getCrossCoordinate(); + float[] heights = borderDescriptor.getMainCoordinateWidths(); + List borders = getVerticalBorder(i); float y1 = startY; float y2 = y1; - if (!heights.isEmpty()) { - y2 = y1 - (float) heights.get(0); - } - int j; - for (j = 1; j < heights.size(); j++) { - Border prevBorder = borders.get(startRow - largeTableIndexOffset + j - 1); - Border curBorder = borders.get(startRow - largeTableIndexOffset + j); - if (prevBorder != null) { - if (!prevBorder.equals(curBorder)) { - prevBorder.drawCellBorder(canvas, x1, y1, x1, y2, Border.Side.NONE); + if (0 != heights.length) { + y2 = y1 - heights[0]; + } + Float y1Offset = null; + for (int j = 1; j <= heights.length; j++) { + Border currentBorder = borders.get(startRow - largeTableIndexOffset + j - 1); + Border nextBorder = j < heights.length ? borders.get(startRow - largeTableIndexOffset + j) : null; + if (currentBorder != null) { + List crossingBordersAtStart = getCrossingBorders(j - 1, i); + float startCornerWidth = getWidestBorderWidth(crossingBordersAtStart.get(0), + crossingBordersAtStart.get(2)); + // TODO DEVSIX-5962 Once the ticket is done, remove this workaround, which allows + // vertical borders to win at horizontal-0. Bear in mind that this workaround helps + // in standard cases, when borders are of the same width. If they are not then + // this workaround doesn't help to improve corner collapsing + if (1 == j) { + crossingBordersAtStart.add(0, currentBorder); + } + Collections.sort(crossingBordersAtStart, borderComparator); + + List crossingBordersAtEnd = getCrossingBorders(j, i); + float endCornerWidth = getWidestBorderWidth(crossingBordersAtEnd.get(0), crossingBordersAtEnd.get(2)); + Collections.sort(crossingBordersAtEnd, borderComparator); + + // if all the borders are equal, we need to draw them at the end + if (!currentBorder.equals(nextBorder)) { + if (null == y1Offset) { + y1Offset = currentBorder.equals(crossingBordersAtStart.get(0)) + ? startCornerWidth / 2 + : -startCornerWidth / 2; + } + float y2Offset = currentBorder.equals(crossingBordersAtEnd.get(0)) + ? -endCornerWidth / 2 + : endCornerWidth / 2; + + currentBorder + .drawCellBorder(canvas, x1, y1 + (float) y1Offset, x1, y2 + y2Offset, Border.Side.NONE); y1 = y2; + y1Offset = null; + } else { + // if current border equal the next one, we apply an optimization here, which allows us + // to draw equal borders at once and not by part. Therefore for the first of such borders + // we store its start offset + if (null == y1Offset) { + y1Offset = currentBorder.equals(crossingBordersAtStart.get(0)) + ? startCornerWidth / 2 + : -startCornerWidth / 2; + } } } else { - y1 -= (float) heights.get(j - 1); + // if current border is null, then just skip it's processing. + // Border corners will be processed by borders which are not null. + y1 -= heights[j - 1]; y2 = y1; } - if (curBorder != null) { - y2 -= (float) heights.get(j); + if (nextBorder != null) { + y2 -= heights[j]; } } - if (borders.size() == 0) { - return this; - } - Border lastBorder = borders.get(startRow - largeTableIndexOffset + j - 1); - if (lastBorder != null) { - lastBorder.drawCellBorder(canvas, x1, y1, x1, y2, Border.Side.NONE); - } return this; } // endregion @@ -555,10 +618,11 @@ protected TableBorders updateBordersOnNewPage(boolean isOriginalNonSplitRenderer rightBorderMaxWidth = getMaxRightWidth(); leftBorderMaxWidth = getMaxLeftWidth(); } + // in case of large table and no content (Table#complete is called right after Table#flush) setTopBorderCollapseWith(((Table) currentRenderer.getModelElement()).getLastRowBottomBorder()); } else { setTopBorderCollapseWith(null); - setBottomBorderCollapseWith(null); + setBottomBorderCollapseWith(null, null); } } if (null != footerRenderer) { @@ -582,7 +646,7 @@ protected TableBorders updateBordersOnNewPage(boolean isOriginalNonSplitRenderer protected TableBorders skipFooter(Border[] borders) { setTableBoundingBorders(borders); - setBottomBorderCollapseWith(null); + setBottomBorderCollapseWith(null, null); return this; } @@ -593,15 +657,19 @@ protected TableBorders skipHeader(Border[] borders) { } protected TableBorders collapseTableWithFooter(TableBorders footerBordersHandler, boolean hasContent) { - ((CollapsedTableBorders) footerBordersHandler).setTopBorderCollapseWith(hasContent ? getLastHorizontalBorder() : getTopBorderCollapseWith()); - setBottomBorderCollapseWith(footerBordersHandler.getHorizontalBorder(0)); + ((CollapsedTableBorders) footerBordersHandler).setTopBorderCollapseWith( + hasContent ? getLastHorizontalBorder() : getTopBorderCollapseWith()); + setBottomBorderCollapseWith(footerBordersHandler.getHorizontalBorder(0), + ((CollapsedTableBorders) footerBordersHandler).getVerticalBordersCrossingTopHorizontalBorder()); return this; } protected TableBorders collapseTableWithHeader(TableBorders headerBordersHandler, boolean updateBordersHandler) { - ((CollapsedTableBorders) headerBordersHandler).setBottomBorderCollapseWith(getHorizontalBorder(startRow)); + ((CollapsedTableBorders) headerBordersHandler).setBottomBorderCollapseWith(getHorizontalBorder(startRow), + getVerticalBordersCrossingTopHorizontalBorder()); if (updateBordersHandler) { - setTopBorderCollapseWith(headerBordersHandler.getLastHorizontalBorder()); + setTopBorderCollapseWith( + headerBordersHandler.getLastHorizontalBorder()); } return this; } @@ -613,4 +681,113 @@ protected TableBorders fixHeaderOccupiedArea(Rectangle occupiedBox, Rectangle la return this; } // endregion + + /** + * Returns the {@link Border} instances, which intersect in the specified point. + * + *

+ * The order of the borders: first the left one, then the top, the right and the bottom ones. + * + * @param horizontalIndex index of horizontal border + * @param verticalIndex index of vertical border + * @return a list of {@link Border} instances, which intersect in the specified point + */ + List getCrossingBorders(int horizontalIndex, int verticalIndex) { + List horizontalBorder = getHorizontalBorder(startRow + horizontalIndex); + List verticalBorder = getVerticalBorder(verticalIndex); + + List crossingBorders = new ArrayList<>(4); + crossingBorders.add(verticalIndex > 0 ? horizontalBorder.get(verticalIndex - 1) : null); + crossingBorders.add(horizontalIndex > 0 + ? verticalBorder.get(startRow - largeTableIndexOffset + horizontalIndex - 1) : null); + crossingBorders.add(verticalIndex < numberOfColumns ? horizontalBorder.get(verticalIndex) : null); + crossingBorders.add(horizontalIndex <= finishRow - startRow + ? verticalBorder.get(startRow - largeTableIndexOffset + horizontalIndex) : null); + + // In case the last horizontal border on the page is specified, + // we need to consider a vertical border of the table's bottom part + // (f.e., for header it is table's body). + if (horizontalIndex == finishRow - startRow + 1 && null != verticalBottomBorderCollapseWith) { + if (isBorderWider(verticalBottomBorderCollapseWith.get(verticalIndex), crossingBorders.get(3))) { + crossingBorders.set(3, verticalBottomBorderCollapseWith.get(verticalIndex)); + } + } + return crossingBorders; + } + + /** + * A comparison function to compare two {@link Border} instances. + */ + private static class BorderComparator implements Comparator { + + @Override + /** + * Compares its two {@link Border} instances for order. Returns a negative integer, + * zero, or a positive integer as the first argument is wider than, of equal width, + * or more narrow than the second. + */ + public int compare(Border o1, Border o2) { + if (o1 == o2) { + return 0; + } else if (null == o1) { + return 1; + } else if (null == o2) { + return -1; + } else { + return Float.compare(o2.getWidth(), o1.getWidth()); + } + } + } + + /** + * Gets the width of the widest border in the specified list. + * + * @param borders the borders which widths should be considered + * @return the width of the widest border in the specified list + */ + private float getWidestBorderWidth(Border... borders) { + float maxWidth = 0; + for (Border border : borders) { + if (null != border && maxWidth < border.getWidth()) { + maxWidth = border.getWidth(); + } + } + return maxWidth; + } + + /** + * Compares borders and defines whether this border is wider than the other. + * + *

+ * Note that by default the comparison will be strict, e.g. if this border + * is of the same width as the other border, then false will be returned. + * + * @param thisBorder this border + * @param otherBorder the other border to be compared with + * @return whether this border is wider than the other + */ + private static boolean isBorderWider(Border thisBorder, Border otherBorder) { + return isBorderWider(thisBorder, otherBorder, true); + } + + /** + * Compares borders and defines whether this border is wider than the other. + * + * @param thisBorder this border + * @param otherBorder the other border to be compared with + * @param strict if true, then in case this border is of the same width as the other border, + * true will be returned. If false, it will be checked whether the width + * of this border is strictly greater than the other border's width + * @return whether this border is wider than the other + */ + private static boolean isBorderWider(Border thisBorder, Border otherBorder, boolean strict) { + if (null == thisBorder) { + return false; + } + if (null == otherBorder) { + return true; + } + int comparisonResult = Float.compare(thisBorder.getWidth(), otherBorder.getWidth()); + return strict ? comparisonResult > 0 : comparisonResult >= 0; + } } diff --git a/layout/src/main/java/com/itextpdf/layout/renderer/ListItemRenderer.java b/layout/src/main/java/com/itextpdf/layout/renderer/ListItemRenderer.java index b8bf85f609..f304ff43ef 100644 --- a/layout/src/main/java/com/itextpdf/layout/renderer/ListItemRenderer.java +++ b/layout/src/main/java/com/itextpdf/layout/renderer/ListItemRenderer.java @@ -45,7 +45,11 @@ This file is part of the iText (R) project. import com.itextpdf.io.logs.IoLogMessageConstant; import com.itextpdf.kernel.font.PdfFont; +import com.itextpdf.kernel.geom.Rectangle; +import com.itextpdf.kernel.pdf.PdfDocument; +import com.itextpdf.kernel.pdf.PdfPage; import com.itextpdf.kernel.pdf.tagging.StandardRoles; +import com.itextpdf.layout.Document; import com.itextpdf.layout.element.ListItem; import com.itextpdf.layout.element.Paragraph; import com.itextpdf.layout.layout.LayoutContext; @@ -135,7 +139,7 @@ public void draw(DrawContext drawContext) { // It will be null in case of overflow (only the "split" part will contain symbol renderer. if (symbolRenderer != null && !symbolAddedInside) { - boolean isRtl = BaseDirection.RIGHT_TO_LEFT.equals(this.getProperty(Property.BASE_DIRECTION)); + boolean isRtl = BaseDirection.RIGHT_TO_LEFT == this.getProperty(Property.BASE_DIRECTION); symbolRenderer.setParent(this); float x = isRtl ? occupiedArea.getBBox().getRight() : occupiedArea.getBBox().getLeft(); ListSymbolPosition symbolPosition = (ListSymbolPosition) ListRenderer.getListItemOrListProperty(this, parent, Property.LIST_SYMBOL_POSITION); @@ -223,7 +227,12 @@ public void draw(DrawContext drawContext) { symbolRenderer.move(dxPosition, 0); } - if (symbolRenderer.getOccupiedArea().getBBox().getRight() > parent.getOccupiedArea().getBBox().getLeft()) { + // consider page area without margins + Rectangle effectiveArea = obtainEffectiveArea(drawContext); + + // symbols are not drawn here, because they are in page margins + if (!isRtl && symbolRenderer.getOccupiedArea().getBBox().getRight() > effectiveArea.getLeft() + || isRtl && symbolRenderer.getOccupiedArea().getBBox().getLeft() < effectiveArea.getRight()) { beginElementOpacityApplying(drawContext); symbolRenderer.draw(drawContext); endElementOpacityApplying(drawContext); @@ -340,4 +349,23 @@ private float[] calculateAscenderDescender() { return new float[] {0, 0}; } + private Rectangle obtainEffectiveArea(DrawContext drawContext) { + PdfDocument pdfDocument = drawContext.getDocument(); + + // for the time being iText creates a single symbol renderer for a list. + // This renderer will be used for all the items across all the pages, which mean that it could + // be layouted at page i and used at page j, j>i. + int pageNumber = parent.getOccupiedArea().getPageNumber(); + Rectangle pageSize; + if (pageNumber != 0) { + PdfPage page = pdfDocument.getPage(pageNumber); + pageSize = page.getPageSize(); + } else { + pageSize = pdfDocument.getDefaultPageSize(); + } + + Document document = new Document(pdfDocument); + return new Rectangle(pageSize).applyMargins(document.getTopMargin(), document.getRightMargin(), document.getBottomMargin(), + document.getLeftMargin(), false); + } } diff --git a/layout/src/main/java/com/itextpdf/layout/renderer/ListRenderer.java b/layout/src/main/java/com/itextpdf/layout/renderer/ListRenderer.java index 7d7f8e4165..01d65e4e43 100644 --- a/layout/src/main/java/com/itextpdf/layout/renderer/ListRenderer.java +++ b/layout/src/main/java/com/itextpdf/layout/renderer/ListRenderer.java @@ -219,16 +219,7 @@ private IRenderer createListSymbolRenderer(int index, IRenderer renderer) { final String constantFont = (numberingType == ListNumberingType.GREEK_LOWER || numberingType == ListNumberingType.GREEK_UPPER) ? StandardFonts.SYMBOL : StandardFonts.ZAPFDINGBATS; - textRenderer = new TextRenderer(textElement) { - @Override - public void draw(DrawContext drawContext) { - try { - setProperty(Property.FONT, PdfFontFactory.createFont(constantFont)); - } catch (IOException ignored) { - } - super.draw(drawContext); - } - }; + textRenderer = new ConstantFontTextRenderer(textElement, constantFont); try { textRenderer.setProperty(Property.FONT, PdfFontFactory.createFont(constantFont)); } catch (IOException exc) { @@ -403,4 +394,23 @@ private LayoutResult initializeListSymbols(LayoutContext layoutContext) { } return null; } + + private static final class ConstantFontTextRenderer extends TextRenderer { + private String constantFontName; + + public ConstantFontTextRenderer(Text textElement, String font) { + super(textElement); + constantFontName = font; + } + + @Override + public void draw(DrawContext drawContext) { + try { + setProperty(Property.FONT, PdfFontFactory.createFont(constantFontName)); + } catch (IOException ignored) { + // Do nothing + } + super.draw(drawContext); + } + } } diff --git a/layout/src/main/java/com/itextpdf/layout/renderer/ParagraphRenderer.java b/layout/src/main/java/com/itextpdf/layout/renderer/ParagraphRenderer.java index 282faa42a6..c331058978 100644 --- a/layout/src/main/java/com/itextpdf/layout/renderer/ParagraphRenderer.java +++ b/layout/src/main/java/com/itextpdf/layout/renderer/ParagraphRenderer.java @@ -43,7 +43,6 @@ This file is part of the iText (R) project. */ package com.itextpdf.layout.renderer; -import com.itextpdf.io.logs.IoLogMessageConstant; import com.itextpdf.commons.utils.MessageFormatUtil; import com.itextpdf.kernel.geom.Rectangle; import com.itextpdf.layout.borders.Border; @@ -54,6 +53,7 @@ This file is part of the iText (R) project. import com.itextpdf.layout.layout.LineLayoutContext; import com.itextpdf.layout.layout.LineLayoutResult; import com.itextpdf.layout.layout.MinMaxWidthLayoutResult; +import com.itextpdf.layout.logs.LayoutLogMessageConstant; import com.itextpdf.layout.margincollapse.MarginsCollapseHandler; import com.itextpdf.layout.minmaxwidth.MinMaxWidth; import com.itextpdf.layout.minmaxwidth.MinMaxWidthUtils; @@ -484,7 +484,7 @@ protected LayoutResult directLayout(LayoutContext layoutContext) { if (isNotFittingLayoutArea(layoutContext.getArea())) { if(isNotFittingWidth(layoutContext.getArea()) && !isNotFittingHeight(layoutContext.getArea())) { LoggerFactory.getLogger(getClass()) - .warn(MessageFormatUtil.format(IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, + .warn(MessageFormatUtil.format(LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, "It fits by height so it will be forced placed")); } else if (!Boolean.TRUE.equals(getPropertyAsBoolean(Property.FORCED_PLACEMENT))) { floatRendererAreas.retainAll(nonChildFloatingRendererAreas); diff --git a/layout/src/main/java/com/itextpdf/layout/renderer/RootRenderer.java b/layout/src/main/java/com/itextpdf/layout/renderer/RootRenderer.java index c772084574..b0ec812026 100644 --- a/layout/src/main/java/com/itextpdf/layout/renderer/RootRenderer.java +++ b/layout/src/main/java/com/itextpdf/layout/renderer/RootRenderer.java @@ -57,6 +57,7 @@ This file is part of the iText (R) project. import com.itextpdf.layout.layout.LayoutResult; import com.itextpdf.layout.layout.PositionedLayoutContext; import com.itextpdf.layout.layout.RootLayoutArea; +import com.itextpdf.layout.logs.LayoutLogMessageConstant; import com.itextpdf.layout.margincollapse.MarginsCollapseHandler; import com.itextpdf.layout.margincollapse.MarginsCollapseInfo; import com.itextpdf.layout.properties.ClearPropertyValue; @@ -168,7 +169,7 @@ public void addChild(IRenderer renderer) { ((ImageRenderer) result.getOverflowRenderer()).autoScale(currentArea); result.getOverflowRenderer().setProperty(Property.FORCED_PLACEMENT, true); Logger logger = LoggerFactory.getLogger(RootRenderer.class); - logger.warn(MessageFormatUtil.format(IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, "")); + logger.warn(MessageFormatUtil.format(LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, "")); } } else { if (currentArea.isEmptyArea() && result.getAreaBreak() == null) { @@ -499,7 +500,7 @@ private boolean updateForcedPlacement(IRenderer currentRenderer, IRenderer overf overflowRenderer.setProperty(Property.FORCED_PLACEMENT, true); Logger logger = LoggerFactory.getLogger(RootRenderer.class); if (logger.isWarnEnabled()) { - logger.warn(MessageFormatUtil.format(IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, "")); + logger.warn(MessageFormatUtil.format(LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, "")); } return true; } @@ -530,7 +531,7 @@ private boolean tryDisableKeepTogether(LayoutResult result, Logger logger = LoggerFactory.getLogger(RootRenderer.class); if (logger.isWarnEnabled()) { logger.warn(MessageFormatUtil.format( - IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, + LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, "KeepTogether property will be ignored.")); } if (!rendererIsFloat) { diff --git a/layout/src/main/java/com/itextpdf/layout/renderer/SeparatedTableBorders.java b/layout/src/main/java/com/itextpdf/layout/renderer/SeparatedTableBorders.java index 9f16ff71b8..a6af26db26 100644 --- a/layout/src/main/java/com/itextpdf/layout/renderer/SeparatedTableBorders.java +++ b/layout/src/main/java/com/itextpdf/layout/renderer/SeparatedTableBorders.java @@ -64,12 +64,12 @@ public SeparatedTableBorders(List rows, int numberOfColumns, Bor } @Override - protected TableBorders drawHorizontalBorder(int i, float startX, float y1, PdfCanvas canvas, float[] countedColumnWidth) { + protected TableBorders drawHorizontalBorder(PdfCanvas canvas, TableBorderDescriptor borderDescriptor) { return this; } @Override - protected TableBorders drawVerticalBorder(int i, float startY, float x1, PdfCanvas canvas, List heights) { + protected TableBorders drawVerticalBorder(PdfCanvas canvas, TableBorderDescriptor borderDescriptor) { return this; } @@ -222,28 +222,7 @@ protected void buildBordersArrays(CellRenderer cell, int row, int col, int[] row } protected boolean checkAndReplaceBorderInArray(List> borderArray, int i, int j, Border borderToAdd, boolean hasPriority) { -// if (borderArray.size() <= i) { -// for (int count = borderArray.size(); count <= i; count++) { -// borderArray.add(new ArrayList()); -// } -// } List borders = borderArray.get(i); -// if (borders.isEmpty()) { -// for (int count = 0; count < j; count++) { -// borders.add(null); -// } -// borders.add(borderToAdd); -// return true; -// } -// if (borders.size() == j) { -// borders.add(borderToAdd); -// return true; -// } -// if (borders.size() < j) { -// for (int count = borders.size(); count <= j; count++) { -// borders.add(count, null); -// } -// } Border neighbour = borders.get(j); if (neighbour == null) { borders.set(j, borderToAdd); diff --git a/layout/src/main/java/com/itextpdf/layout/renderer/TableBorderDescriptor.java b/layout/src/main/java/com/itextpdf/layout/renderer/TableBorderDescriptor.java new file mode 100644 index 0000000000..174adbbd1f --- /dev/null +++ b/layout/src/main/java/com/itextpdf/layout/renderer/TableBorderDescriptor.java @@ -0,0 +1,83 @@ +/* + + This file is part of the iText (R) project. + Copyright (c) 1998-2021 iText Group NV + Authors: Bruno Lowagie, Paulo Soares, et al. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License version 3 + as published by the Free Software Foundation with the addition of the + following permission added to Section 15 as permitted in Section 7(a): + FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY + ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT + OF THIRD PARTY RIGHTS + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Affero General Public License for more details. + You should have received a copy of the GNU Affero General Public License + along with this program; if not, see http://www.gnu.org/licenses or write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA, 02110-1301 USA, or download the license from the following URL: + http://itextpdf.com/terms-of-use/ + + The interactive user interfaces in modified source and object code versions + of this program must display Appropriate Legal Notices, as required under + Section 5 of the GNU Affero General Public License. + + In accordance with Section 7(b) of the GNU Affero General Public License, + a covered work must retain the producer line in every PDF that is created + or manipulated using iText. + + You can be released from the requirements of the license by purchasing + a commercial license. Buying such a license is mandatory as soon as you + develop commercial activities involving the iText software without + disclosing the source code of your own applications. + These activities include: offering paid services to customers as an ASP, + serving PDFs on the fly in a web application, shipping iText with a closed + source product. + + For more information, please contact iText Software Corp. at this + address: sales@itextpdf.com + */ +package com.itextpdf.layout.renderer; + +class TableBorderDescriptor { + private int borderIndex; + private float mainCoordinateStart; + private float crossCoordinate; + private float[] mainCoordinateWidths; + + /** + * Creates a table border descriptor which will be used while drawing the described border. + * + * @param borderIndex the index of the described border + * @param mainCoordinateStart the border's start main-axis coordinate + * @param crossCoordinate fixed cross-axis coordinate of the whole border + * @param mainCoordinateWidths the sizes (widths or heights) of rows or columns depending on the type of main axis + */ + public TableBorderDescriptor(int borderIndex, float mainCoordinateStart, float crossCoordinate, + float[] mainCoordinateWidths) { + this.borderIndex = borderIndex; + this.mainCoordinateStart = mainCoordinateStart; + this.crossCoordinate = crossCoordinate; + this.mainCoordinateWidths = mainCoordinateWidths; + } + + public int getBorderIndex() { + return borderIndex; + } + + public float getMainCoordinateStart() { + return mainCoordinateStart; + } + + public float getCrossCoordinate() { + return crossCoordinate; + } + + public float[] getMainCoordinateWidths() { + return mainCoordinateWidths; + } +} diff --git a/layout/src/main/java/com/itextpdf/layout/renderer/TableBorders.java b/layout/src/main/java/com/itextpdf/layout/renderer/TableBorders.java index 9e860b4cdf..6f6f9e73a5 100644 --- a/layout/src/main/java/com/itextpdf/layout/renderer/TableBorders.java +++ b/layout/src/main/java/com/itextpdf/layout/renderer/TableBorders.java @@ -48,11 +48,11 @@ This file is part of the iText (R) project. import com.itextpdf.kernel.pdf.canvas.PdfCanvas; import com.itextpdf.layout.borders.Border; import com.itextpdf.layout.properties.Property; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; abstract class TableBorders { /** @@ -138,9 +138,9 @@ public TableBorders(List rows, int numberOfColumns, Border[] tab // region abstract // region draw - protected abstract TableBorders drawHorizontalBorder(int i, float startX, float y1, PdfCanvas canvas, float[] countedColumnWidth); + protected abstract TableBorders drawHorizontalBorder(PdfCanvas canvas, TableBorderDescriptor borderDescriptor); - protected abstract TableBorders drawVerticalBorder(int i, float startY, float x1, PdfCanvas canvas, List heights); + protected abstract TableBorders drawVerticalBorder(PdfCanvas canvas, TableBorderDescriptor borderDescriptor); // endregion // region area occupation diff --git a/layout/src/main/java/com/itextpdf/layout/renderer/TableRenderer.java b/layout/src/main/java/com/itextpdf/layout/renderer/TableRenderer.java index 60c696cdf4..2c90714add 100644 --- a/layout/src/main/java/com/itextpdf/layout/renderer/TableRenderer.java +++ b/layout/src/main/java/com/itextpdf/layout/renderer/TableRenderer.java @@ -43,8 +43,8 @@ This file is part of the iText (R) project. */ package com.itextpdf.layout.renderer; -import com.itextpdf.io.logs.IoLogMessageConstant; import com.itextpdf.commons.utils.MessageFormatUtil; +import com.itextpdf.io.logs.IoLogMessageConstant; import com.itextpdf.kernel.geom.Rectangle; import com.itextpdf.kernel.pdf.canvas.CanvasArtifact; import com.itextpdf.kernel.pdf.tagutils.TagTreePointer; @@ -65,8 +65,6 @@ This file is part of the iText (R) project. import com.itextpdf.layout.properties.UnitValue; import com.itextpdf.layout.properties.VerticalAlignment; import com.itextpdf.layout.tagging.LayoutTaggingHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.util.ArrayDeque; import java.util.ArrayList; @@ -75,6 +73,8 @@ This file is part of the iText (R) project. import java.util.HashMap; import java.util.List; import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * This class represents the {@link IRenderer renderer} object for a {@link Table} @@ -781,7 +781,7 @@ public LayoutResult layout(LayoutContext layoutContext) { // And now, when we possess such knowledge, we are performing the second attempt, but we need to nullify results // from the previous attempt if (bordersHandler instanceof CollapsedTableBorders) { - ((CollapsedTableBorders)bordersHandler).setBottomBorderCollapseWith(null); + ((CollapsedTableBorders) bordersHandler).setBottomBorderCollapseWith(null, null); } bordersHandler.collapseTableWithFooter(footerRenderer.bordersHandler, hasContent || 0 != childRenderers.size()); @@ -1050,10 +1050,6 @@ public LayoutResult layout(LayoutContext layoutContext) { } } } else { - // the bottom border should be processed and placed lately - if (0 != heights.size()) { - heights.set(heights.size() - 1, heights.get(heights.size() - 1) - bottomTableBorderWidth / 2); - } if (null == footerRenderer) { if (0 != childRenderers.size()) { bordersHandler.applyBottomTableBorder(occupiedArea.getBBox(), layoutBox, 0 == childRenderers.size(), false, true); @@ -1454,7 +1450,7 @@ private void drawBorders(DrawContext drawContext, boolean hasHeader, boolean has } - // process halves of the borders here + // process halves of horizontal bounding borders if (childRenderers.size() == 0) { Border[] borders = bordersHandler.tableBoundingBorders; if (null != borders[0]) { @@ -1486,56 +1482,60 @@ private void drawBorders(DrawContext drawContext, boolean hasHeader, boolean has if (bordersHandler instanceof CollapsedTableBorders) { if (hasFooter) { - ((CollapsedTableBorders) bordersHandler).setBottomBorderCollapseWith(footerRenderer.bordersHandler.getFirstHorizontalBorder()); + ((CollapsedTableBorders) bordersHandler).setBottomBorderCollapseWith( + footerRenderer.bordersHandler.getFirstHorizontalBorder(), + ((CollapsedTableBorders) footerRenderer.bordersHandler) + .getVerticalBordersCrossingTopHorizontalBorder()); } else if (isBottomTablePart) { - ((CollapsedTableBorders) bordersHandler).setBottomBorderCollapseWith(null); + ((CollapsedTableBorders) bordersHandler).setBottomBorderCollapseWith(null, null); } } // we do not need to fix top border, because either this is header or the top border has been already written float y1 = startY; - if (isFooterRendererOfLargeTable) { - bordersHandler.drawHorizontalBorder(0, startX, y1, drawContext.getCanvas(), countedColumnWidth); - } - if (0 != heights.size()) { - y1 -= (float) heights.get(0); - } - for (int i = 1; i < heights.size(); i++) { - bordersHandler.drawHorizontalBorder(i, startX, y1, drawContext.getCanvas(), countedColumnWidth); - if (i < heights.size()) { - y1 -= (float) heights.get(i); - } - } - if (!isBottomTablePart && isComplete) { - bordersHandler.drawHorizontalBorder(heights.size(), startX, y1, drawContext.getCanvas(), countedColumnWidth); + + float[] heightsArray = new float[heights.size()]; + for (int j = 0; j < heights.size(); j++) { + heightsArray[j] = heights.get(j); } + // draw vertical borders float x1 = startX; - if (countedColumnWidth.length > 0) { - x1 += countedColumnWidth[0]; - } - for (int i = 1; i < bordersHandler.getNumberOfColumns(); i++) { - bordersHandler.drawVerticalBorder(i, startY, x1, drawContext.getCanvas(), heights); + for (int i = 0; i <= bordersHandler.getNumberOfColumns(); i++) { + bordersHandler.drawVerticalBorder(drawContext.getCanvas(), + new TableBorderDescriptor(i, startY, x1, heightsArray)); if (i < countedColumnWidth.length) { x1 += countedColumnWidth[i]; } } - // Draw bounding borders. Vertical borders are the last to draw in order to collapse with header / footer - if (isTopTablePart) { - bordersHandler.drawHorizontalBorder(0, startX, startY, drawContext.getCanvas(), countedColumnWidth); + // draw horizontal borders + + boolean shouldDrawTopBorder = isFooterRendererOfLargeTable || isTopTablePart; + + // if top border is already drawn, we should decrease ordinate + if (!heights.isEmpty() && !shouldDrawTopBorder) { + y1 -= (float) heights.get(0); + } + for (int i = shouldDrawTopBorder ? 0 : 1; i < heights.size(); i++) { + bordersHandler.drawHorizontalBorder(drawContext.getCanvas(), + new TableBorderDescriptor(i, startX, y1, countedColumnWidth)); + y1 -= (float) heights.get(i); } + + // draw bottom border + + // Note for the second condition: //!isLastRendererForModelElement is a check that this is a split render. This is the case with the splitting of // one cell when part of the cell moves to the next page. Therefore, if such a splitting occurs, a bottom border // should be drawn. However, this should not be done for empty renderers that are also created during splitting, // but this splitting, if the table does not fit on the page and the next cell is added to the next page. // In this case, this code should not be processed, since the border in the above code has already been drawn. - if (isBottomTablePart && (isComplete || (!isLastRendererForModelElement && !isEmptyTableRenderer()))) { - bordersHandler.drawHorizontalBorder(heights.size(), startX, y1, drawContext.getCanvas(), countedColumnWidth); + // TODO DEVSIX-5867 Check hasFooter, so that two footers are not drawn + if ((!isBottomTablePart && isComplete) + || (isBottomTablePart && (isComplete || (!isLastRendererForModelElement && !isEmptyTableRenderer())))) { + bordersHandler.drawHorizontalBorder(drawContext.getCanvas(), + new TableBorderDescriptor(heights.size(), startX, y1, countedColumnWidth)); } - // draw left - bordersHandler.drawVerticalBorder(0, startY, startX, drawContext.getCanvas(), heights); - // draw right - bordersHandler.drawVerticalBorder(bordersHandler.getNumberOfColumns(), startY, x1, drawContext.getCanvas(), heights); if (isTagged) { drawContext.getCanvas().closeTag(); diff --git a/layout/src/main/java/com/itextpdf/layout/renderer/TableWidths.java b/layout/src/main/java/com/itextpdf/layout/renderer/TableWidths.java index 2a870d0dc1..1a31fbf007 100644 --- a/layout/src/main/java/com/itextpdf/layout/renderer/TableWidths.java +++ b/layout/src/main/java/com/itextpdf/layout/renderer/TableWidths.java @@ -837,12 +837,22 @@ public String toString() { static private final UnitValue ZeroWidth = UnitValue.createPointValue(0); + /** + * Gets width of the cell, adding paddings and extra spacing if necessary. + * + * @param cell renderer from which width will be taken. + * Note that this method will not change original width of the element. + * @param zeroIsValid defines if 0 width is valid + * @return increased width of the renderer + */ private UnitValue getCellWidth(CellRenderer cell, boolean zeroIsValid) { - UnitValue widthValue = cell.getProperty(Property.WIDTH); + UnitValue widthValue = new UnitValue(cell.getProperty(Property.WIDTH, UnitValue.createPointValue(-1))); //zero has special meaning in fixed layout, we shall not add padding to zero value - if (widthValue == null || widthValue.getValue() < 0) { + if (widthValue.getValue() < -AbstractRenderer.EPS) { return null; - } else if (widthValue.getValue() == 0) { + } + + if (widthValue.getValue() < AbstractRenderer.EPS) { return zeroIsValid ? ZeroWidth : null; } else if (widthValue.isPercentValue()) { return widthValue; diff --git a/layout/src/main/java/com/itextpdf/layout/renderer/TextRenderer.java b/layout/src/main/java/com/itextpdf/layout/renderer/TextRenderer.java index d1af43e540..aa6362ce73 100644 --- a/layout/src/main/java/com/itextpdf/layout/renderer/TextRenderer.java +++ b/layout/src/main/java/com/itextpdf/layout/renderer/TextRenderer.java @@ -961,12 +961,7 @@ public void draw(DrawContext drawContext) { canvas.setHorizontalScaling((float) horizontalScaling * 100); } - GlyphLine.IGlyphLineFilter filter = new GlyphLine.IGlyphLineFilter() { - @Override - public boolean accept(Glyph glyph) { - return !noPrint(glyph); - } - }; + GlyphLine.IGlyphLineFilter filter = new CustomGlyphLineFilter(); boolean appearanceStreamLayout = Boolean.TRUE.equals(getPropertyAsBoolean(Property.APPEARANCE_STREAM_LAYOUT)); @@ -1875,4 +1870,11 @@ private static class ScriptRange { this.rangeEnd = rangeEnd; } } + + private static final class CustomGlyphLineFilter implements GlyphLine.IGlyphLineFilter { + @Override + public boolean accept(Glyph glyph) { + return !noPrint(glyph); + } + } } diff --git a/layout/src/test/java/com/itextpdf/layout/BorderTest.java b/layout/src/test/java/com/itextpdf/layout/BorderTest.java index 469817f335..13efaa4b86 100644 --- a/layout/src/test/java/com/itextpdf/layout/BorderTest.java +++ b/layout/src/test/java/com/itextpdf/layout/BorderTest.java @@ -42,7 +42,6 @@ This file is part of the iText (R) project. */ package com.itextpdf.layout; -import com.itextpdf.io.logs.IoLogMessageConstant; import com.itextpdf.io.image.ImageDataFactory; import com.itextpdf.kernel.colors.ColorConstants; import com.itextpdf.kernel.colors.DeviceCmyk; @@ -67,6 +66,7 @@ This file is part of the iText (R) project. import com.itextpdf.layout.element.List; import com.itextpdf.layout.element.ListItem; import com.itextpdf.layout.element.Paragraph; +import com.itextpdf.layout.logs.LayoutLogMessageConstant; import com.itextpdf.test.ExtendedITextTest; import com.itextpdf.test.annotations.LogMessage; import com.itextpdf.test.annotations.LogMessages; @@ -313,7 +313,7 @@ public void borderBoxTest() throws IOException, InterruptedException { @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1) }) public void rotatedBordersTest() throws IOException, InterruptedException { fileName = "rotatedBordersTest.pdf"; diff --git a/layout/src/test/java/com/itextpdf/layout/DefaultLayoutTest.java b/layout/src/test/java/com/itextpdf/layout/DefaultLayoutTest.java index aa52f83823..a67044ff78 100644 --- a/layout/src/test/java/com/itextpdf/layout/DefaultLayoutTest.java +++ b/layout/src/test/java/com/itextpdf/layout/DefaultLayoutTest.java @@ -61,6 +61,7 @@ This file is part of the iText (R) project. import com.itextpdf.layout.element.AreaBreak; import com.itextpdf.layout.element.Paragraph; import com.itextpdf.layout.element.Text; +import com.itextpdf.layout.logs.LayoutLogMessageConstant; import com.itextpdf.test.AssertUtil; import com.itextpdf.test.ExtendedITextTest; import com.itextpdf.test.LogLevelConstants; @@ -188,7 +189,7 @@ public void textWithWhitespacesTest01() throws IOException, InterruptedException @Test @LogMessages(messages = { - @LogMessage(count = 1, messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(count = 1, messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void addParagraphOnShortPage1() throws IOException, InterruptedException { String outFileName = destinationFolder + "addParagraphOnShortPage1.pdf"; @@ -213,7 +214,7 @@ public void addParagraphOnShortPage1() throws IOException, InterruptedException @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void addParagraphOnShortPage2() throws IOException, InterruptedException { String outFileName = destinationFolder + "addParagraphOnShortPage2.pdf"; @@ -234,7 +235,7 @@ public void addParagraphOnShortPage2() throws IOException, InterruptedException @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void addWordOnShortPageTest01() throws IOException, InterruptedException { String outFileName = destinationFolder + "addWordOnShortPageTest01.pdf"; diff --git a/layout/src/test/java/com/itextpdf/layout/FloatTest.java b/layout/src/test/java/com/itextpdf/layout/FloatTest.java index a200f2d888..d22439bf37 100644 --- a/layout/src/test/java/com/itextpdf/layout/FloatTest.java +++ b/layout/src/test/java/com/itextpdf/layout/FloatTest.java @@ -62,6 +62,7 @@ This file is part of the iText (R) project. import com.itextpdf.layout.element.Paragraph; import com.itextpdf.layout.element.Table; import com.itextpdf.layout.element.Text; +import com.itextpdf.layout.logs.LayoutLogMessageConstant; import com.itextpdf.layout.properties.AreaBreakType; import com.itextpdf.layout.properties.ClearPropertyValue; import com.itextpdf.layout.properties.FloatPropertyValue; @@ -823,7 +824,7 @@ public void clearancePageSplitFloatPartialInBlock03() throws IOException, Interr } @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) + @LogMessages(messages = @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) public void clearancePageSplitFloatNothingInRoot01() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_clearancePageSplitFloatNothingInRoot01.pdf"; String outFile = destinationFolder + "clearancePageSplitFloatNothingInRoot01.pdf"; @@ -912,7 +913,7 @@ public void clearancePageSplitFloatNothingInRoot03() throws IOException, Interru } @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) + @LogMessages(messages = @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) public void clearancePageSplitFloatNothingInBlock01() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_clearancePageSplitFloatNothingInBlock01.pdf"; String outFile = destinationFolder + "clearancePageSplitFloatNothingInBlock01.pdf"; @@ -1073,7 +1074,7 @@ public void clearanceNoContentPageSplitFloatPartialInBlock01() throws IOExceptio } @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 2)) + @LogMessages(messages = @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 2)) public void floatsOnPageSplit01() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_floatsOnPageSplit01.pdf"; String outFile = destinationFolder + "floatsOnPageSplit01.pdf"; @@ -1140,7 +1141,7 @@ public void floatsOnPageSplit03() throws IOException, InterruptedException { } @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) + @LogMessages(messages = @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) public void floatsOnPageSplit04() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_floatsOnPageSplit04.pdf"; String outFile = destinationFolder + "floatsOnPageSplit04.pdf"; @@ -1246,7 +1247,7 @@ public void floatsOnPageSplit06_02() throws IOException, InterruptedException { } @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) + @LogMessages(messages = @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) public void floatsOnPageSplit06_03() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_floatsOnPageSplit06_03.pdf"; String outFile = destinationFolder + "floatsOnPageSplit06_03.pdf"; @@ -1332,7 +1333,7 @@ public void floatsOnPageSplit08_01() throws IOException, InterruptedException { } @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) + @LogMessages(messages = @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) public void floatsOnPageSplit08_02() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_floatsOnPageSplit08_02.pdf"; String outFile = destinationFolder + "floatsOnPageSplit08_02.pdf"; @@ -1365,7 +1366,7 @@ public void floatsOnPageSplit08_02() throws IOException, InterruptedException { } @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) + @LogMessages(messages = @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) public void floatsOnPageSplit08_03() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_floatsOnPageSplit08_03.pdf"; String outFile = destinationFolder + "floatsOnPageSplit08_03.pdf"; @@ -1422,7 +1423,7 @@ public void floatsOnPageSplit09() throws IOException, InterruptedException { } @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) + @LogMessages(messages = @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) public void floatsOnPageSplit10() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_floatsOnPageSplit10.pdf"; String outFile = destinationFolder + "floatsOnPageSplit10.pdf"; @@ -1446,7 +1447,7 @@ public void floatsOnPageSplit10() throws IOException, InterruptedException { } @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) + @LogMessages(messages = @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) public void floatsOnPageSplit11() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_floatsOnPageSplit11.pdf"; String outFile = destinationFolder + "floatsOnPageSplit11.pdf"; @@ -1695,7 +1696,7 @@ public void floatsOnPageSplit19() throws IOException, InterruptedException { } @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) + @LogMessages(messages = @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) public void floatsKeepTogetherOnPageSplit01() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_floatsKeepTogetherOnPageSplit01.pdf"; String outFile = destinationFolder + "floatsKeepTogetherOnPageSplit01.pdf"; @@ -1716,7 +1717,7 @@ public void floatsKeepTogetherOnPageSplit01() throws IOException, InterruptedExc } @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) + @LogMessages(messages = @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) public void floatsKeepTogetherOnPageSplit02() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_floatsKeepTogetherOnPageSplit02.pdf"; String outFile = destinationFolder + "floatsKeepTogetherOnPageSplit02.pdf"; @@ -1740,7 +1741,7 @@ public void floatsKeepTogetherOnPageSplit02() throws IOException, InterruptedExc } @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 2)) + @LogMessages(messages = @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 2)) public void floatsKeepTogetherOnPageSplit03() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_floatsKeepTogetherOnPageSplit03.pdf"; String outFile = destinationFolder + "floatsKeepTogetherOnPageSplit03.pdf"; @@ -2088,7 +2089,7 @@ public void floatingTextInParagraphPartialSplit03() throws IOException, Interrup } @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) + @LogMessages(messages = @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) public void floatsFirstOnPageNotFit01() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_floatsFirstOnPageNotFit01.pdf"; String outFile = destinationFolder + "floatsFirstOnPageNotFit01.pdf"; @@ -2115,7 +2116,7 @@ public void floatsFirstOnPageNotFit01() throws IOException, InterruptedException } @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) + @LogMessages(messages = @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) public void floatsFirstOnPageNotFit02() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_floatsFirstOnPageNotFit02.pdf"; String outFile = destinationFolder + "floatsFirstOnPageNotFit02.pdf"; @@ -2142,7 +2143,7 @@ public void floatsFirstOnPageNotFit02() throws IOException, InterruptedException } @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) + @LogMessages(messages = @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) public void floatsFirstOnPageNotFit03() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_floatsFirstOnPageNotFit03.pdf"; String outFile = destinationFolder + "floatsFirstOnPageNotFit03.pdf"; @@ -3118,7 +3119,7 @@ public void floatTableTest01() throws IOException, InterruptedException { } @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) + @LogMessages(messages = @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) public void keepTogetherEnoughSpaceOnNewPageWithFloatTest() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_keepTogetherEnoughSpaceOnNewPageWithFloatTest.pdf"; String outFile = destinationFolder + "keepTogetherEnoughSpaceOnNewPageWithFloatTest.pdf"; @@ -3133,7 +3134,7 @@ public void keepTogetherEnoughSpaceOnNewPageWithFloatTest() throws IOException, } @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) + @LogMessages(messages = @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) public void keepTogetherNotEnoughSpaceOnNewPageWithFloatEnoughOnEmptyTest() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_keepTogetherNotEnoughSpaceOnNewPageWithFloatEnoughOnEmptyTest.pdf"; @@ -3149,7 +3150,7 @@ public void keepTogetherNotEnoughSpaceOnNewPageWithFloatEnoughOnEmptyTest() } @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 2)) + @LogMessages(messages = @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 2)) public void keepTogetherNotEnoughSpaceOnNewEmptyPageTest() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_keepTogetherNotEnoughSpaceOnNewEmptyPageTest.pdf"; String outFile = destinationFolder + "keepTogetherNotEnoughSpaceOnNewEmptyPageTest.pdf"; @@ -3164,7 +3165,7 @@ public void keepTogetherNotEnoughSpaceOnNewEmptyPageTest() throws IOException, I } @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1)) + @LogMessages(messages = @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1)) public void keepTogetherNotEnoughSpaceOnNewEmptyPageShortFloatTest() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_keepTogetherNotEnoughSpaceOnNewEmptyPageShortFloatTest.pdf"; String outFile = destinationFolder + "keepTogetherNotEnoughSpaceOnNewEmptyPageShortFloatTest.pdf"; @@ -3180,7 +3181,7 @@ public void keepTogetherNotEnoughSpaceOnNewEmptyPageShortFloatTest() throws IOEx @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) + @LogMessages(messages = @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) public void innerKeepTogetherEnoughSpaceOnNewPageWithFloatTest() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_innerKeepTogetherEnoughSpaceOnNewPageWithFloatTest.pdf"; String outFile = destinationFolder + "innerKeepTogetherEnoughSpaceOnNewPageWithFloatTest.pdf"; @@ -3195,7 +3196,7 @@ public void innerKeepTogetherEnoughSpaceOnNewPageWithFloatTest() throws IOExcept } @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) + @LogMessages(messages = @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) public void innerKeepTogetherNotEnoughSpaceOnNewPageWithFloatEnoughOnEmptyTest() throws IOException, InterruptedException { String cmpFileName = @@ -3212,7 +3213,7 @@ public void innerKeepTogetherNotEnoughSpaceOnNewPageWithFloatEnoughOnEmptyTest() } @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 2)) + @LogMessages(messages = @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 2)) public void innerKeepTogetherNotEnoughSpaceOnNewEmptyPageTest() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_innerKeepTogetherNotEnoughSpaceOnNewEmptyPageTest.pdf"; String outFile = destinationFolder + "innerKeepTogetherNotEnoughSpaceOnNewEmptyPageTest.pdf"; diff --git a/layout/src/test/java/com/itextpdf/layout/FontSelectorTest.java b/layout/src/test/java/com/itextpdf/layout/FontSelectorTest.java index 0881e27e5f..3a7b37af1e 100644 --- a/layout/src/test/java/com/itextpdf/layout/FontSelectorTest.java +++ b/layout/src/test/java/com/itextpdf/layout/FontSelectorTest.java @@ -1063,6 +1063,24 @@ public void openSansOutOfNotBoldFontWeightTest() { new FontSelector(set.getFonts(), fontFamilies, fc).bestMatch().getDescriptor().getFontName()); } + @Test + //TODO DEVSIX-6077 FontSelector: iText checks monospaceness before looking at font-family + public void monospaceFontIsNotSelectedInPreferenceToTestFamilyTest() { + FontSet set = new FontSet(); + set.addFont(StandardFonts.COURIER); + set.addFont(StandardFonts.HELVETICA); + + List fontFamilies = new ArrayList<>(); + fontFamilies.add("test"); + fontFamilies.add("monospace"); + + FontCharacteristics fc = new FontCharacteristics(); + + //Expected font is Courier + Assert.assertEquals("Helvetica", + new FontSelector(set.getFonts(), fontFamilies, fc).bestMatch().getDescriptor().getFontName()); + } + private void checkSelector(Collection fontInfoCollection, String fontFamily, String expectedNormal, String expectedBold, String expectedItalic, String expectedBoldItalic) { List fontFamilies = new ArrayList<>(); diff --git a/layout/src/test/java/com/itextpdf/layout/ImageTest.java b/layout/src/test/java/com/itextpdf/layout/ImageTest.java index 2a6c6f6f78..591ba8f961 100644 --- a/layout/src/test/java/com/itextpdf/layout/ImageTest.java +++ b/layout/src/test/java/com/itextpdf/layout/ImageTest.java @@ -64,6 +64,7 @@ This file is part of the iText (R) project. import com.itextpdf.layout.element.Paragraph; import com.itextpdf.layout.element.Table; import com.itextpdf.layout.element.Text; +import com.itextpdf.layout.logs.LayoutLogMessageConstant; import com.itextpdf.layout.properties.BorderRadius; import com.itextpdf.layout.properties.HorizontalAlignment; import com.itextpdf.layout.properties.Property; @@ -254,7 +255,7 @@ public void imageTest06() throws IOException, InterruptedException { @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void imageTest07() throws IOException, InterruptedException { String outFileName = destinationFolder + "imageTest07.pdf"; @@ -277,7 +278,7 @@ public void imageTest07() throws IOException, InterruptedException { @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void imageTest08() throws IOException, InterruptedException { String outFileName = destinationFolder + "imageTest08.pdf"; @@ -302,7 +303,7 @@ public void imageTest08() throws IOException, InterruptedException { @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void imageTest09() throws IOException, InterruptedException { String outFileName = destinationFolder + "imageTest09.pdf"; @@ -416,7 +417,7 @@ public void imageTest14_HorizontalAlignment_LEFT() throws IOException, Interrupt @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void imageTest15() throws IOException, InterruptedException { String outFileName = destinationFolder + "imageTest15.pdf"; @@ -459,7 +460,7 @@ public void imageTest16() throws IOException, InterruptedException { @Test() @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 50) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 50) }) public void imageTest17() throws IOException, InterruptedException { String outFileName = destinationFolder + "imageTest17.pdf"; @@ -593,7 +594,7 @@ public void imageTest21() throws IOException, InterruptedException { } @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1)) + @LogMessages(messages = @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1)) public void imageTest22() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_imageTest22.pdf"; String outFile = destinationFolder + "imageTest22.pdf"; @@ -947,7 +948,7 @@ public void imageBorderRadiusTest01() throws IOException, InterruptedException { } @Test - @LogMessages(messages = {@LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 3)}) + @LogMessages(messages = {@LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 3)}) public void createTiffImageTest() throws IOException, InterruptedException { String outFileName = destinationFolder + "createTiffImageTest.pdf"; String cmpFileName = sourceFolder + "cmp_createTiffImageTest.pdf"; diff --git a/layout/src/test/java/com/itextpdf/layout/KeepTogetherTest.java b/layout/src/test/java/com/itextpdf/layout/KeepTogetherTest.java index c0cb8ddf5c..e9ab0f69c7 100644 --- a/layout/src/test/java/com/itextpdf/layout/KeepTogetherTest.java +++ b/layout/src/test/java/com/itextpdf/layout/KeepTogetherTest.java @@ -63,6 +63,7 @@ This file is part of the iText (R) project. import com.itextpdf.layout.element.List; import com.itextpdf.layout.element.Paragraph; import com.itextpdf.layout.element.Table; +import com.itextpdf.layout.logs.LayoutLogMessageConstant; import com.itextpdf.layout.properties.ClearPropertyValue; import com.itextpdf.layout.properties.FloatPropertyValue; import com.itextpdf.layout.properties.ListNumberingType; @@ -154,7 +155,7 @@ public void skipKeepTogetherInCaseOfAreaBreak() throws IOException, InterruptedE @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void keepTogetherParagraphTest02() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_keepTogetherParagraphTest02.pdf"; @@ -258,7 +259,7 @@ public void keepTogetherMinHeightTest() throws IOException, InterruptedException @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void keepTogetherDivTest02() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_keepTogetherDivTest02.pdf"; @@ -348,7 +349,7 @@ public void keepTogetherDivWithInnerClearDiv() throws IOException, InterruptedEx @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void keepTogetherDefaultTest01() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_keepTogetherDefaultTest01.pdf"; @@ -393,7 +394,7 @@ public void keepTogetherInlineDiv01() throws IOException, InterruptedException { @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void keepTogetherInlineDiv02() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_keepTogetherInlineDiv02.pdf"; @@ -532,7 +533,7 @@ public void narrowPageTest02A() throws IOException, InterruptedException { @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1) }) public void updateHeightTest01() throws IOException, InterruptedException { String testName = "updateHeightTest01.pdf"; @@ -594,7 +595,7 @@ public void partialTest01() throws IOException, InterruptedException { @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void fixedHeightOverflowTest01() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_fixedHeightOverflowTest01.pdf"; @@ -622,7 +623,7 @@ public void fixedHeightOverflowTest01() throws IOException, InterruptedException @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void marginCollapseKeptTogetherDivGoesBackTest01() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_marginCollapseKeptTogetherDivGoesBackTest01.pdf"; @@ -654,7 +655,7 @@ public void marginCollapseKeptTogetherDivGoesBackTest01() throws IOException, In @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) // TODO DEVSIX-3995 The margin between the divs occupies 100 points instead of 300. After a fix the cmp should be updated public void marginCollapseKeptTogetherDivGoesBackTest02() throws IOException, InterruptedException { @@ -686,7 +687,7 @@ public void marginCollapseKeptTogetherDivGoesBackTest02() throws IOException, In @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void keepTogetherNotEmptyPageTest() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_keepTogetherNotEmptyPageTest.pdf"; @@ -717,7 +718,7 @@ public void keepTogetherNotEmptyPageTest() throws IOException, InterruptedExcept @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void keepTogetherOnFirstInnerElementNotEmptyPageTest() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_keepTogetherOnFirstInnerElementNotEmptyPageTest.pdf"; @@ -809,7 +810,7 @@ public void marginCollapseKeptTogetherGoesOnNextAreaTest02() throws IOException, @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) // TODO DEVSIX-4023 cmp should be updated public void keepTogetherOnSecondInnerElementNotEmptyPageTest() throws IOException, InterruptedException { @@ -844,7 +845,7 @@ public void keepTogetherOnSecondInnerElementNotEmptyPageTest() throws IOExceptio @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void smallFloatInsideKeptTogetherDivTest01() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_smallFloatInsideKeptTogetherDivTest01.pdf"; @@ -863,7 +864,7 @@ public void smallFloatInsideKeptTogetherDivTest01() throws IOException, Interrup @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void smallFloatInsideKeptTogetherDivTest02() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_smallFloatInsideKeptTogetherDivTest02.pdf"; @@ -885,7 +886,7 @@ public void smallFloatInsideKeptTogetherDivTest02() throws IOException, Interrup @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void smallFloatInsideKeptTogetherParagraphTest01() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_smallFloatInsideKeptTogetherParagraphTest01.pdf"; @@ -904,7 +905,7 @@ public void smallFloatInsideKeptTogetherParagraphTest01() throws IOException, In @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void smallFloatInsideKeptTogetherParagraphTest02() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_smallFloatInsideKeptTogetherParagraphTest02.pdf"; @@ -926,7 +927,7 @@ public void smallFloatInsideKeptTogetherParagraphTest02() throws IOException, In @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) // TODO DEVSIX-4023 cmp should be updated public void keepTogetherOnInnerElementTestEmptyPageTest() throws IOException, InterruptedException { @@ -951,7 +952,7 @@ public void keepTogetherOnInnerElementTestEmptyPageTest() throws IOException, In @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) // TODO DEVSIX-4023 cmp should be updated public void keepTogetherOnInnerElementMargin01EmptyPageTest() throws IOException, InterruptedException { @@ -979,7 +980,7 @@ public void keepTogetherOnInnerElementMargin01EmptyPageTest() throws IOException @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) // TODO DEVSIX-4023 cmp should be updated public void keepTogetherOnInnerElementMargin02EmptyPageTest() throws IOException, InterruptedException { @@ -1007,7 +1008,7 @@ public void keepTogetherOnInnerElementMargin02EmptyPageTest() throws IOException @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) // TODO DEVSIX-1092 There should be no path of the 15th row on the first page, // since the layout box is only of 1 px height @@ -1029,7 +1030,7 @@ public void smallFloatInsideKeptTogetherTableTest01() throws IOException, Interr @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void smallFloatInsideKeptTogetherTableTest02() throws IOException, InterruptedException { String cmpFileName = sourceFolder + "cmp_smallFloatInsideKeptTogetherTableTest02.pdf"; @@ -1051,7 +1052,7 @@ public void smallFloatInsideKeptTogetherTableTest02() throws IOException, Interr @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void keepTogetherTreeWithParentNotFitOnDocumentTest() throws IOException, InterruptedException { String filename = "keepTogetherTreeWithParentNotFitOnDocument.pdf"; @@ -1083,7 +1084,7 @@ public void keepTogetherTreeWithParentNotFitOnDocumentTest() throws IOException, @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void keepTogetherSubTreeWithParentNotFitOnDocumentTest() throws IOException, InterruptedException { String filename = "keepTogetherSubTreeWithParentNotFitOnDocument.pdf"; @@ -1117,7 +1118,7 @@ public void keepTogetherSubTreeWithParentNotFitOnDocumentTest() throws IOExcepti @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void keepTogetherSubTreeWithChildKeepTogetherFalseAndParentNotFitOnDocumentTest() throws IOException, InterruptedException { @@ -1152,7 +1153,7 @@ public void keepTogetherSubTreeWithChildKeepTogetherFalseAndParentNotFitOnDocume @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void keepTogetherTreeWithParentNotFitOnPageCanvasTest() throws IOException, InterruptedException { String filename = "keepTogetherTreeWithParentNotFitOnPageCanvas.pdf"; @@ -1226,7 +1227,7 @@ public void keepTogetherInDivWithKidsFloatTest() throws IOException, Interrupted @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) //TODO: update cmp file when DEVSIX-4681 will be fixed public void floatingElementsInDivAndKeepTogetherElemTest() throws IOException, InterruptedException { @@ -1266,7 +1267,7 @@ public void floatingElementsInDivAndKeepTogetherElemTest() throws IOException, I @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) //TODO: update cmp file when DEVSIX-4681 will be fixed public void floatingEmptyElementsInDivAndKeepTogetherElemTest() throws IOException, InterruptedException { diff --git a/layout/src/test/java/com/itextpdf/layout/LargeElementTest.java b/layout/src/test/java/com/itextpdf/layout/LargeElementTest.java index 90cf101524..a1c40af29e 100644 --- a/layout/src/test/java/com/itextpdf/layout/LargeElementTest.java +++ b/layout/src/test/java/com/itextpdf/layout/LargeElementTest.java @@ -61,6 +61,7 @@ This file is part of the iText (R) project. import com.itextpdf.layout.layout.LayoutArea; import com.itextpdf.layout.layout.LayoutContext; import com.itextpdf.layout.layout.LayoutResult; +import com.itextpdf.layout.logs.LayoutLogMessageConstant; import com.itextpdf.layout.properties.BorderCollapsePropertyValue; import com.itextpdf.layout.properties.UnitValue; import com.itextpdf.layout.renderer.DocumentRenderer; @@ -148,6 +149,95 @@ public void largeTableTest02() throws IOException, InterruptedException { Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, testName + "_diff")); } + @Test + @LogMessages(messages = { + @LogMessage(messageTemplate = IoLogMessageConstant.LAST_ROW_IS_NOT_COMPLETE) + }) + public void largeTableWithEmptyLastRowTest() throws IOException, InterruptedException { + String testName = "largeTableWithEmptyLastRowTest.pdf"; + String outFileName = destinationFolder + testName; + String cmpFileName = sourceFolder + "cmp_" + testName; + + PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName)); + Document doc = new Document(pdfDoc); + + Table table = new Table(UnitValue.createPercentArray(5), true); + + doc.add(table); + for (int i = 0; i < 20; i++) { + for (int j = 0; j < 5; j++) { + table.addCell(new Cell().add(new Paragraph(MessageFormatUtil.format("Cell {0}, {1}", i + 1, j + 1)))); + } + if (i % 10 == 0) { + table.flush(); + } + } + table.startNewRow(); + table.complete(); + doc.add(new Table(UnitValue.createPercentArray(1)).useAllAvailableWidth().setBorder(new SolidBorder(ColorConstants.ORANGE, 2)).addCell("Is my occupied area correct?")); + + doc.close(); + Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, testName + "_diff")); + } + + @Test + //TODO DEVSIX-6025 Unexpected NPE, when trying to flush after starting new row + @LogMessages(messages = { + @LogMessage(messageTemplate = IoLogMessageConstant.LAST_ROW_IS_NOT_COMPLETE, count = 2) + }) + public void flushingLargeTableAfterStartingNewRowTest() throws IOException, InterruptedException { + String testName = "flushingLargeTableAfterStartingNewRowTest.pdf"; + String outFileName = destinationFolder + testName; + String cmpFileName = sourceFolder + "cmp_" + testName; + + PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName)); + Document doc = new Document(pdfDoc); + + Table table = new Table(UnitValue.createPercentArray(5), true); + + doc.add(table); + + table.addCell(new Cell().add(new Paragraph("Hello"))); + table.addCell(new Cell().add(new Paragraph("World"))); + table.startNewRow(); + Assert.assertThrows(NullPointerException.class, () -> table.flush()); + table.complete(); + doc.close(); + Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, testName + "_diff")); + } + + @Test + @LogMessages(messages = { + @LogMessage(messageTemplate = IoLogMessageConstant.LAST_ROW_IS_NOT_COMPLETE) + }) + public void largeTableWithCollapsedFooterTest() throws IOException, InterruptedException { + String testName = "largeTableWithCollapsedFooterTest.pdf"; + String outFileName = destinationFolder + testName; + String cmpFileName = sourceFolder + "cmp_" + testName; + + PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName)); + Document doc = new Document(pdfDoc); + + Table table = new Table(UnitValue.createPercentArray(5), true); + + doc.add(table); + for (int i = 0; i < 20; i++) { + for (int j = 0; j < 5; j++) { + table.addCell(new Cell().add(new Paragraph(MessageFormatUtil.format("Cell {0}, {1}", i + 1, j + 1)))); + } + if (i % 10 == 0) { + table.flush(); + } + } + table.startNewRow(); + Cell cell = new Cell(1, 5).add(new Paragraph("Collapsed footer")); + table.addFooterCell(cell); + table.complete(); + + doc.close(); + Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, testName + "_diff")); + } + @Test public void largeTableWithHeaderFooterTest01A() throws IOException, InterruptedException { String testName = "largeTableWithHeaderFooterTest01A.pdf"; @@ -252,6 +342,7 @@ public void largeTableWithHeaderFooterTest01B() throws IOException, InterruptedE } @Test + // TODO DEVSIX-5868 Look at page 2: large table's vertical borders are shorter in length than expected public void largeTableWithHeaderFooterTest01C() throws IOException, InterruptedException { String testName = "largeTableWithHeaderFooterTest01C.pdf"; String outFileName = destinationFolder + testName; @@ -620,7 +711,7 @@ public void tableWithLayoutResultNothingTest01() throws IOException, Interrupted @Test - @LogMessages(messages = {@LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1)}) + @LogMessages(messages = {@LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1)}) public void largeTableWithLayoutResultNothingTest02() throws IOException, InterruptedException { String testName = "largeTableWithLayoutResultNothingTest02.pdf"; String outFileName = destinationFolder + testName; @@ -777,6 +868,7 @@ private void largeTableSplitTest(String outFileName, float pageHeight, float row } @Test + // TODO DEVSIX-5865 Table last horizontal border is drawn twice: at final Table#flush and then at Table#complete public void largeTableWithTableBorderSplitTest() throws IOException, InterruptedException { String testName = "largeTableWithTableBorderSplitTest.pdf"; String outFileName = destinationFolder + testName; @@ -808,7 +900,68 @@ public void largeTableWithTableBorderSplitTest() throws IOException, Interrupted } @Test - @LogMessages(messages = {@LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)}) + // TODO DEVSIX-5865 Table last horizontal border is drawn twice: at final Table#flush and then at Table#complete + public void largeTableWithTableBorderSplitTest02() throws IOException, InterruptedException { + String testName = "largeTableWithTableBorderSplitTest02.pdf"; + String outFileName = destinationFolder + testName; + String cmpFileName = sourceFolder + "cmp_" + testName; + + PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName)); + Document doc = new Document(pdfDoc, new PageSize(595, 100)); + + Table table = new Table(2, true); + doc.add(table); + + table.setBorder(new SolidBorder(ColorConstants.BLUE, 2)); + + table.addCell(new Cell().setBackgroundColor(ColorConstants.RED).setHeight(50).setMargin(0).setPadding(0)); + table.addCell(new Cell().setBackgroundColor(ColorConstants.RED).setHeight(50).setMargin(0).setPadding(0)); + + table.flush(); + table.complete(); + + doc.close(); + Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder)); + } + + @Test + // TODO DEVSIX-5866 at #complete left border is initialized as null + public void largeTableWithCellBordersSplitTest1() throws IOException, InterruptedException { + String testName = "largeTableWithCellBordersSplitTest1.pdf"; + String outFileName = destinationFolder + testName; + String cmpFileName = sourceFolder + "cmp_" + testName; + + PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName)); + Document doc = new Document(pdfDoc); + + float[] colWidths = new float[]{30, 30, 30}; + + Table table = new Table(colWidths, true).setWidth(290); + doc.add(table); + + table.addCell(new Cell().add(new Paragraph("Cell" + 0)) + .setPadding(0).setMargin(0) + .setBorder(new SolidBorder(ColorConstants.MAGENTA, 50)) + .setBorderBottom(new SolidBorder(ColorConstants.BLUE, 50))); + table.addCell(new Cell().add(new Paragraph("Cell" + 1)) + .setPadding(0).setMargin(0) + .setBorder(new SolidBorder(ColorConstants.MAGENTA, 50)) + .setBorderBottom(new SolidBorder(ColorConstants.RED, 50))); + table.addCell(new Cell().add(new Paragraph("Cell" + 3)) + .setPadding(0).setMargin(0) + .setBorder(new SolidBorder(ColorConstants.MAGENTA, 50)) + .setBorderBottom(new SolidBorder(ColorConstants.BLUE, 50))); + + table.flush(); + table.complete(); + + doc.close(); + Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder)); + } + + @Test + @LogMessages(messages = {@LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)}) + // TODO DEVSIX-5866 at #complete left border is initialized as null public void largeTableWithCellBordersSplitTest() throws IOException, InterruptedException { String testName = "largeTableWithCellBordersSplitTest.pdf"; String outFileName = destinationFolder + testName; @@ -822,27 +975,79 @@ public void largeTableWithCellBordersSplitTest() throws IOException, Interrupted Table table = new Table(UnitValue.createPointArray(colWidths), true); doc.add(table); - for (int i = 0; i < 1; i++) { - table.addCell(new Cell().add(new Paragraph("Cell" + (i * 4 + 0))) - .setBorderBottom(new SolidBorder(ColorConstants.BLUE, 2))); - table.addCell(new Cell().add(new Paragraph("Cell" + (i * 4 + 1))) - .setBorderBottom(new SolidBorder(ColorConstants.RED, 5))); - table.addCell(new Cell().add(new Paragraph("Cell" + (i * 4 + 2))) - .setBorderBottom(new SolidBorder(ColorConstants.GREEN, 7))); - table.addCell(new Cell().add(new Paragraph("Cell" + (i * 4 + 3))) - .setBorderBottom(new SolidBorder(ColorConstants.BLUE, 10))); - - table.flush(); - } + table.addCell(new Cell().add(new Paragraph("Cell" + 0)) + .setBorderBottom(new SolidBorder(ColorConstants.BLUE, 2))); + table.addCell(new Cell().add(new Paragraph("Cell" + 1)) + .setBorderBottom(new SolidBorder(ColorConstants.RED, 5))); + table.addCell(new Cell().add(new Paragraph("Cell" + 2)) + .setBorderBottom(new SolidBorder(ColorConstants.GREEN, 7))); + table.addCell(new Cell().add(new Paragraph("Cell" + 3)) + .setBorderBottom(new SolidBorder(ColorConstants.BLUE, 10))); + table.flush(); table.complete(); doc.close(); Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder)); } + @Test + @LogMessages(messages = {@LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)}) + // TODO DEVSIX-5866 at #complete left border is initialized as null + public void largeTableWithCellBordersSplitTest02() throws IOException, InterruptedException { + String testName = "largeTableWithCellBordersSplitTest02.pdf"; + String outFileName = destinationFolder + testName; + String cmpFileName = sourceFolder + "cmp_" + testName; + + PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName)); + Document doc = new Document(pdfDoc, new PageSize(595, 100)); + + float[] colWidths = new float[]{200, 40}; + + Table table = new Table(UnitValue.createPointArray(colWidths), true); + doc.add(table); + + table.addCell(new Cell().add(new Paragraph("Cell" + 0)).setBackgroundColor(ColorConstants.YELLOW) + .setBorderBottom(new SolidBorder(ColorConstants.BLUE, 2))); + table.addCell(new Cell().add(new Paragraph("Cell" + 3)).setBackgroundColor(ColorConstants.YELLOW) + .setBorderBottom(new SolidBorder(ColorConstants.BLUE, 10))); + + table.flush(); + + doc.close(); + Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder)); + } @Test + // TODO DEVSIX-5866 at #complete left border is initialized as null + public void simpleLargeTableDifferentCellBottomBorderTest() throws IOException, InterruptedException { + String testName = "simpleLargeTableDifferentCellBottomBorderTest.pdf"; + String outFileName = destinationFolder + testName; + String cmpFileName = sourceFolder + "cmp_" + testName; + + PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName)); + Document doc = new Document(pdfDoc); + + Table table = new Table(2, true); + doc.add(table); + + table.addCell(new Cell().add(new Paragraph("Cell" + 0)).setHeight(30).setMargin(0).setPadding(0) + .setBackgroundColor(ColorConstants.RED).setBorder(new SolidBorder(ColorConstants.BLUE, 10))); + table.addCell(new Cell().add(new Paragraph("Cell" + 1)).setHeight(30).setMargin(0).setPadding(0) + .setBackgroundColor(ColorConstants.RED).setBorder(new SolidBorder(10)) + .setBorderBottom(new SolidBorder(ColorConstants.BLUE, 100))); + + table.flush(); + table.complete(); + + doc.close(); + Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder)); + } + + @Test + // TODO DEVSIX-5867 footer's top / table body's bottom border gets drawn twice at different coordinates + // (Look at yellow border at page 2: it might not be tat obvious, however, there are two yelow borders + // there which overlap each other a bit) public void largeTableSplitFooter2Test() throws IOException, InterruptedException { String testName = "largeTableSplitFooter2Test.pdf"; String outFileName = destinationFolder + testName; @@ -867,6 +1072,61 @@ public void largeTableSplitFooter2Test() throws IOException, InterruptedExceptio Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder)); } + @Test + // TODO DEVSIX-5867 footer's top / table body's bottom border gets drawn twice at different coordinates + // (Look at yellow border: it might not be tat obvious, however, there are two yelow borders + // there which overlap each other a bit) + public void largeTableSplitFooter2ATest() throws IOException, InterruptedException { + String testName = "largeTableSplitFooter2ATest.pdf"; + String outFileName = destinationFolder + testName; + String cmpFileName = sourceFolder + "cmp_" + testName; + + PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName)); + Document doc = new Document(pdfDoc); + + Table table = new Table(1, true); + doc.add(table); + table.addFooterCell(new Cell().add(new Paragraph("Footer")) + .setBorderTop(new SolidBorder(ColorConstants.YELLOW, 15)) + ); + + table.addCell(new Cell().add(new Paragraph("Cell1")).setHeight(50) + .setBorderBottom(new SolidBorder(ColorConstants.BLUE, 20))); + table.flush(); + table.addCell(new Cell().add(new Paragraph("Cell2")).setHeight(50)); + + table.complete(); + + doc.close(); + Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder)); + } + + @Test + // TODO DEVSIX-5869 large table's width should not change between flushes + public void largeTableSplitFooter2BTest() throws IOException, InterruptedException { + String testName = "largeTableSplitFooter2BTest.pdf"; + String outFileName = destinationFolder + testName; + String cmpFileName = sourceFolder + "cmp_" + testName; + + PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName)); + Document doc = new Document(pdfDoc, new PageSize(595, 900)); + + addSpecificTableConsideringFlushes(doc, false, false); + doc.add(new AreaBreak()); + + addSpecificTableConsideringFlushes(doc, true, false); + doc.add(new AreaBreak()); + + addSpecificTableConsideringFlushes(doc, false, true); + doc.add(new AreaBreak()); + + addSpecificTableConsideringFlushes(doc, true, true); + doc.add(new AreaBreak()); + + doc.close(); + Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder)); + } + @Test public void largeTableCollapsingSplitTest() throws IOException, InterruptedException { String testName = "largeTableCollapsingSplitTest.pdf"; @@ -1016,7 +1276,6 @@ public void tableOnDifferentPages02() throws IOException, InterruptedException { Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, testName + "_diff")); } - @Test @LogMessages(messages = {@LogMessage(messageTemplate = IoLogMessageConstant.LAST_ROW_IS_NOT_COMPLETE, count = 1)}) public void reuseLargeTableTest01() throws IOException, InterruptedException { @@ -1237,8 +1496,8 @@ public void largeEmptyTableTest02Separated() throws IOException, InterruptedExce } @Test - // TODO DEVSIX-3953 - @LogMessages(messages = {@LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 2)}) + // TODO DEVSIX-3953 Footer is not placed on the first page in case of large table, but fits the page for a usual table + @LogMessages(messages = {@LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)}) public void largeTableFooterNotFitTest() throws IOException, InterruptedException { String testName = "largeTableFooterNotFitTest.pdf"; String outFileName = destinationFolder + testName; @@ -1247,25 +1506,51 @@ public void largeTableFooterNotFitTest() throws IOException, InterruptedExceptio PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName)); Document doc = new Document(pdfDoc, new PageSize(595, 100)); - float[] colWidths = new float[]{200, -1, 40, 40}; - - Table table = new Table(UnitValue.createPointArray(colWidths), true); - Cell footerCell = new Cell(1, 4).add(new Paragraph("Table footer: continue on next page")); + Table table = new Table(1, true); + Cell footerCell = new Cell().add(new Paragraph("Table footer: continue on next page")); table.addFooterCell(footerCell); doc.add(table); - for (int i = 0; i < 2; i++) { - table.addCell(new Cell().add(new Paragraph("Cell" + (i * 4 + 0)))); - table.addCell(new Cell().add(new Paragraph("Cell" + (i * 4 + 1)))); - table.addCell(new Cell().add(new Paragraph("Cell" + (i * 4 + 2)))); - table.addCell(new Cell().add(new Paragraph("Cell" + (i * 4 + 3)))); + table.addCell(new Cell().add(new Paragraph("Cell")).setBackgroundColor(ColorConstants.RED)); - table.flush(); - } + // If one comments flush, then the table fits the page + table.flush(); table.complete(); doc.close(); Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, testName + "_diff")); } + + private static void addSpecificTableConsideringFlushes(Document doc, boolean flushFirst, boolean flushSecond) { + Table table = new Table(UnitValue.createPercentArray(1), true); + doc.add(table); + + table.addFooterCell(new Cell().add(new Paragraph("Footer")) + .setBorderTop(new SolidBorder(ColorConstants.YELLOW, 15)) + .setHeight(100).setMargin(0).setPadding(0) + ); + + table.addCell(new Cell().add(new Paragraph("Cell1")) + .setHeight(100).setMargin(0).setPadding(0) + .setBackgroundColor(ColorConstants.RED) + ); + + if (flushFirst) { + table.flush(); + } + + table.addCell(new Cell().add(new Paragraph("Cell2")) + .setHeight(100).setMargin(0).setPadding(0) + .setBackgroundColor(ColorConstants.RED) + .setBorderLeft(new SolidBorder(ColorConstants.GREEN, 50)) + .setBorderRight(new SolidBorder(ColorConstants.GREEN, 50)) + + .setBorderTop(new SolidBorder(ColorConstants.MAGENTA, 10))); + + if (flushSecond) { + table.flush(); + } + table.complete(); + } } diff --git a/layout/src/test/java/com/itextpdf/layout/LayoutTaggingPdf2Test.java b/layout/src/test/java/com/itextpdf/layout/LayoutTaggingPdf2Test.java index da69f9a97a..550683191d 100644 --- a/layout/src/test/java/com/itextpdf/layout/LayoutTaggingPdf2Test.java +++ b/layout/src/test/java/com/itextpdf/layout/LayoutTaggingPdf2Test.java @@ -58,6 +58,7 @@ This file is part of the iText (R) project. import com.itextpdf.kernel.utils.CompareTool; import com.itextpdf.layout.element.AreaBreak; import com.itextpdf.layout.element.Cell; +import com.itextpdf.layout.element.Div; import com.itextpdf.layout.element.Image; import com.itextpdf.layout.element.List; import com.itextpdf.layout.element.ListItem; @@ -651,6 +652,36 @@ public void copyTest01() throws IOException, InterruptedException, ParserConfigu compareResult("copyTest01"); } + @Test + public void docWithSectInPdf2() throws IOException, ParserConfigurationException, SAXException, + InterruptedException { + PdfDocument pdfDocument = new PdfDocument(new PdfWriter(destinationFolder + "docWithSectInPdf2.pdf", + new WriterProperties().setPdfVersion(PdfVersion.PDF_2_0))); + pdfDocument.setTagged(); + + Document document = new Document(pdfDocument); + + Div section = new Div(); + section.getAccessibilityProperties().setRole(StandardRoles.SECT); + Paragraph h1 = new Paragraph("This is a header"); + h1.getAccessibilityProperties().setRole("H1"); + section.add(h1); + + section.add(new Paragraph("This is a paragraph.")); + Paragraph para = new Paragraph("This is another paragraph, "); + + Text emphasised = new Text("with semantic emphasis!"); + emphasised.setUnderline(); + emphasised.getAccessibilityProperties().setRole(StandardRoles.EM); + para.add(emphasised); + section.add(para); + + document.add(section); + document.close(); + + compareResult("docWithSectInPdf2"); + } + @Test public void copyTest02() throws IOException, InterruptedException, ParserConfigurationException, SAXException { PdfDocument srcPdf = new PdfDocument(new PdfReader(sourceFolder + "docSeveralNs.pdf")); diff --git a/layout/src/test/java/com/itextpdf/layout/LayoutTaggingTest.java b/layout/src/test/java/com/itextpdf/layout/LayoutTaggingTest.java index df21800cf6..54666bacb2 100644 --- a/layout/src/test/java/com/itextpdf/layout/LayoutTaggingTest.java +++ b/layout/src/test/java/com/itextpdf/layout/LayoutTaggingTest.java @@ -83,6 +83,7 @@ This file is part of the iText (R) project. import com.itextpdf.layout.element.Table; import com.itextpdf.layout.element.Text; import com.itextpdf.layout.font.FontProvider; +import com.itextpdf.layout.logs.LayoutLogMessageConstant; import com.itextpdf.layout.properties.FloatPropertyValue; import com.itextpdf.layout.properties.ListNumberingType; import com.itextpdf.layout.properties.Property; @@ -138,7 +139,7 @@ public void textInParagraphTest01() throws IOException, InterruptedException, Pa @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void imageTest01() throws IOException, InterruptedException, ParserConfigurationException, SAXException { PdfDocument pdfDocument = new PdfDocument(new PdfWriter(destinationFolder + "imageTest01.pdf")); @@ -1034,7 +1035,7 @@ public void checkParentTreeIfFormXObjectTaggedTest() throws IOException, Interru canvas.add(new Paragraph(txt)); PdfCanvas canvas1 = new PdfCanvas(page1); - canvas1.addXObject(template, 10, 10); + canvas1.addXObjectAt(template, 10, 10); pdfDoc.close(); diff --git a/layout/src/test/java/com/itextpdf/layout/LinkTest.java b/layout/src/test/java/com/itextpdf/layout/LinkTest.java index 138be0ae8b..0959ffb1bb 100644 --- a/layout/src/test/java/com/itextpdf/layout/LinkTest.java +++ b/layout/src/test/java/com/itextpdf/layout/LinkTest.java @@ -62,6 +62,7 @@ This file is part of the iText (R) project. import com.itextpdf.layout.element.Link; import com.itextpdf.layout.element.Paragraph; import com.itextpdf.layout.element.Table; +import com.itextpdf.layout.logs.LayoutLogMessageConstant; import com.itextpdf.layout.properties.Property; import com.itextpdf.layout.properties.UnitValue; import com.itextpdf.test.ExtendedITextTest; @@ -224,7 +225,7 @@ public void rotatedLinkAtFixedPosition() throws IOException, InterruptedExceptio } @Test - @LogMessages(messages = {@LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)}) + @LogMessages(messages = {@LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)}) public void rotatedLinkInnerRotation() throws IOException, InterruptedException { String outFileName = destinationFolder + "rotatedLinkInnerRotation.pdf"; String cmpFileName = sourceFolder + "cmp_rotatedLinkInnerRotation.pdf"; diff --git a/layout/src/test/java/com/itextpdf/layout/ListItemPositionAlignmentTest.java b/layout/src/test/java/com/itextpdf/layout/ListItemPositionAlignmentTest.java new file mode 100644 index 0000000000..6aa94cb3dd --- /dev/null +++ b/layout/src/test/java/com/itextpdf/layout/ListItemPositionAlignmentTest.java @@ -0,0 +1,217 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2021 iText Group NV + Authors: iText Software. + + This program is offered under a commercial and under the AGPL license. + For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + + AGPL licensing: + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +package com.itextpdf.layout; + +import com.itextpdf.commons.utils.MessageFormatUtil; +import com.itextpdf.io.logs.IoLogMessageConstant; +import com.itextpdf.io.util.UrlUtil; +import com.itextpdf.kernel.colors.ColorConstants; +import com.itextpdf.kernel.pdf.PdfDocument; +import com.itextpdf.kernel.pdf.PdfWriter; +import com.itextpdf.kernel.utils.CompareTool; +import com.itextpdf.layout.element.List; +import com.itextpdf.layout.element.ListItem; +import com.itextpdf.layout.element.Paragraph; +import com.itextpdf.layout.properties.BaseDirection; +import com.itextpdf.layout.properties.ListSymbolAlignment; +import com.itextpdf.layout.properties.ListSymbolPosition; +import com.itextpdf.layout.properties.Property; +import com.itextpdf.test.ExtendedITextTest; +import com.itextpdf.test.annotations.LogMessage; +import com.itextpdf.test.annotations.LogMessages; +import com.itextpdf.test.annotations.type.IntegrationTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; + +@RunWith(Parameterized.class) +@Category(IntegrationTest.class) +public class ListItemPositionAlignmentTest extends ExtendedITextTest { + + public static final String SOURCE_FOLDER = "./src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/"; + public static final String DESTINATION_FOLDER = "./target/test/com/itextpdf/layout/ListItemPositionAlignmentTest/"; + + private static final String PARAMETERS_NAME_PATTERN = "{index}: list-base-direction: {0}; list-item-base-direction: {1};" + + " list-symbol-alignment: {2}; list-symbol-position: {3};"; + private static final String RESULTANT_FILE_NAME_PATTERN + = "list-dir-{0}_item-dir-{1}_symbol-align-{2}_symbol-position-{3}"; + + private static final String HTML_PATTERN = + "

    " + + "
  • Usual item
  • " + + "
  • Specific item
  • " + + "
"; + + private BaseDirection listBaseDirection; + private BaseDirection listItemBaseDirection; + private ListSymbolAlignment listSymbolAlignment; + private ListSymbolPosition listSymbolPosition; + private Integer comparisonPdfId; + + public ListItemPositionAlignmentTest(Object listBaseDirection, Object listItemBaseDirection, + Object listSymbolAlignment, Object listSymbolPosition, Object comparisonPdfId) throws IOException { + this.listBaseDirection = (BaseDirection) listBaseDirection; + this.listItemBaseDirection = (BaseDirection) listItemBaseDirection; + this.listSymbolAlignment = (ListSymbolAlignment) listSymbolAlignment; + this.listSymbolPosition = (ListSymbolPosition) listSymbolPosition; + this.comparisonPdfId = (Integer) comparisonPdfId; + + createOrClearDestinationFolder(DESTINATION_FOLDER); + // Create an HTML for this test + createHtml(); + } + + @Parameterized.Parameters(name = PARAMETERS_NAME_PATTERN) + public static Iterable baseDirectionAndSymbolAlignmentProperties() { + BaseDirection[] directionTestValues = new BaseDirection[]{BaseDirection.LEFT_TO_RIGHT, + BaseDirection.RIGHT_TO_LEFT}; + ListSymbolAlignment[] listSymbolAlignmentTestValues = new ListSymbolAlignment[]{ListSymbolAlignment.LEFT, + ListSymbolAlignment.RIGHT}; + ListSymbolPosition[] listSymbolPositionTestValues = new ListSymbolPosition[]{ListSymbolPosition.OUTSIDE, + ListSymbolPosition.INSIDE}; + java.util.List objectList = new ArrayList<>(); + int count = 0; + for (BaseDirection listBA : directionTestValues) { + for (BaseDirection itemBA : directionTestValues) { + for (ListSymbolAlignment listSA : listSymbolAlignmentTestValues) { + for (ListSymbolPosition listSP : listSymbolPositionTestValues) { + objectList.add(new Object[]{listBA, itemBA, listSA, listSP, count}); + count++; + } + } + } + } + return objectList; + } + + @Test + @LogMessages(messages = {@LogMessage(messageTemplate = IoLogMessageConstant.TYPOGRAPHY_NOT_FOUND, count = 8)}) + public void defaultListIemPositionAlignmentTest() throws IOException, InterruptedException { + String fileName = MessageFormatUtil.format( + RESULTANT_FILE_NAME_PATTERN, + formatSymbolPosition(listSymbolPosition), + formatSymbolAlignment(listSymbolAlignment), + formatBaseDirection(listItemBaseDirection), + formatBaseDirection(listBaseDirection)); + + String outFileName = DESTINATION_FOLDER + "defaultListItemTest" + comparisonPdfId + ".pdf"; + String cmpFileName = SOURCE_FOLDER + "cmp_defaultListItemTest" + comparisonPdfId + ".pdf"; + PdfDocument pdfDocument = new PdfDocument(new PdfWriter(outFileName)); + + Document document = new Document(pdfDocument); + List list = createTestList(); + document.add(list); + + document.close(); + + System.out.println("HTML: " + UrlUtil.getNormalizedFileUriString(DESTINATION_FOLDER + fileName + ".html") + "\n"); + Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, DESTINATION_FOLDER, "diff")); + } + + private List createTestList() { + List list = new List(); + list.setSymbolIndent(20); + list.setListSymbol("\u2022"); + list.setBackgroundColor(ColorConstants.GREEN); + + ListItem listItem1 = new ListItem(); + listItem1.add(new Paragraph("Usual item")); + listItem1.setBackgroundColor(ColorConstants.BLUE); + + list.add(listItem1); + + ListItem listItem2 = new ListItem(); + listItem2.add(new Paragraph("Specific item")); + listItem2.setBackgroundColor(ColorConstants.YELLOW); + listItem2.setProperty(Property.BASE_DIRECTION, listItemBaseDirection); + listItem2.setProperty(Property.LIST_SYMBOL_ALIGNMENT, listSymbolAlignment); + listItem2.setProperty(Property.LIST_SYMBOL_POSITION, listSymbolPosition); + list.add(listItem2); + list.setProperty(Property.BASE_DIRECTION, listBaseDirection); + return list; + } + + private void createHtml() throws IOException { + String fileName = MessageFormatUtil.format( + RESULTANT_FILE_NAME_PATTERN, + formatSymbolPosition(listSymbolPosition), + formatSymbolAlignment(listSymbolAlignment), + formatBaseDirection(listItemBaseDirection), + formatBaseDirection(listBaseDirection)); + + String htmlString = MessageFormatUtil.format( + HTML_PATTERN, + formatSymbolPosition(listSymbolPosition), + formatSymbolAlignment(listSymbolAlignment), + formatBaseDirection(listItemBaseDirection), + formatBaseDirection(listBaseDirection)); + try (FileOutputStream htmlFile = + new FileOutputStream(DESTINATION_FOLDER + fileName + ".html")) { + byte[] htmlBytes = htmlString.getBytes(StandardCharsets.UTF_8); + htmlFile.write(htmlBytes, 0, htmlBytes.length); + } + } + + private static String formatBaseDirection(BaseDirection direction) { + switch (direction) { + case LEFT_TO_RIGHT: + return "ltr"; + case RIGHT_TO_LEFT: + return "rtl"; + default: + Assert.fail("Unexpected base direction"); + return null; + } + } + + private static String formatSymbolAlignment(ListSymbolAlignment alignment) { + switch (alignment) { + case LEFT: + return "left"; + case RIGHT: + return "right"; + default: + Assert.fail("Unexpected symbol alignment"); + return null; + } + } + + private static String formatSymbolPosition(ListSymbolPosition position) { + switch (position) { + case OUTSIDE: + return "outside"; + case INSIDE: + return "inside"; + default: + Assert.fail("Unexpected symbol position"); + return null; + } + } +} diff --git a/layout/src/test/java/com/itextpdf/layout/ListTest.java b/layout/src/test/java/com/itextpdf/layout/ListTest.java index 1351e6f5e9..e0da8ed1bc 100644 --- a/layout/src/test/java/com/itextpdf/layout/ListTest.java +++ b/layout/src/test/java/com/itextpdf/layout/ListTest.java @@ -62,6 +62,7 @@ This file is part of the iText (R) project. import com.itextpdf.layout.element.Paragraph; import com.itextpdf.layout.element.Table; import com.itextpdf.layout.element.Text; +import com.itextpdf.layout.logs.LayoutLogMessageConstant; import com.itextpdf.layout.properties.ListNumberingType; import com.itextpdf.layout.properties.ListSymbolAlignment; import com.itextpdf.layout.properties.Property; @@ -194,7 +195,7 @@ public void listNumberingTest01() throws IOException, InterruptedException { @Test @LogMessages(messages = { - @LogMessage(count = 8, messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(count = 8, messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void addListOnShortPage1() throws IOException, InterruptedException { String outFileName = destinationFolder + "addListOnShortPage1.pdf"; @@ -230,7 +231,7 @@ public void addListOnShortPage1() throws IOException, InterruptedException { @Test @LogMessages(messages = { - @LogMessage(count = 3, messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA), + @LogMessage(count = 3, messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA), @LogMessage(count = 6, messageTemplate = IoLogMessageConstant.ATTEMPT_TO_CREATE_A_TAG_FOR_FINISHED_HINT) }) public void addListOnShortPage2() throws IOException, InterruptedException { @@ -592,7 +593,7 @@ public void listItemNullSymbol() throws Exception { } @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) + @LogMessages(messages = @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) public void listSymbolForcedPlacement01() throws Exception { String outFileName = destinationFolder + "listSymbolForcedPlacement01.pdf"; String cmpFileName = sourceFolder + "cmp_listSymbolForcedPlacement01.pdf"; diff --git a/layout/src/test/java/com/itextpdf/layout/ObjectFitTest.java b/layout/src/test/java/com/itextpdf/layout/ObjectFitTest.java index 8e781f2b52..b8f02611ed 100644 --- a/layout/src/test/java/com/itextpdf/layout/ObjectFitTest.java +++ b/layout/src/test/java/com/itextpdf/layout/ObjectFitTest.java @@ -22,7 +22,6 @@ This file is part of the iText (R) project. */ package com.itextpdf.layout; -import com.itextpdf.io.logs.IoLogMessageConstant; import com.itextpdf.io.image.ImageDataFactory; import com.itextpdf.kernel.colors.DeviceGray; import com.itextpdf.kernel.pdf.PdfDocument; @@ -32,6 +31,7 @@ This file is part of the iText (R) project. import com.itextpdf.layout.borders.SolidBorder; import com.itextpdf.layout.element.Image; import com.itextpdf.layout.element.Paragraph; +import com.itextpdf.layout.logs.LayoutLogMessageConstant; import com.itextpdf.layout.properties.BorderRadius; import com.itextpdf.layout.properties.ObjectFit; import com.itextpdf.test.ExtendedITextTest; @@ -195,7 +195,7 @@ public void containWithEffectsObjectsFitTest() throws IOException, InterruptedEx @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA), + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA), }) // TODO DEVSIX-4286 object-fit property combined with rotation is not processed correctly public void containWithRotationObjectsFitTest() throws IOException, InterruptedException { diff --git a/layout/src/test/java/com/itextpdf/layout/OrphansWidowsTest.java b/layout/src/test/java/com/itextpdf/layout/OrphansWidowsTest.java index 61560439bf..640774df14 100644 --- a/layout/src/test/java/com/itextpdf/layout/OrphansWidowsTest.java +++ b/layout/src/test/java/com/itextpdf/layout/OrphansWidowsTest.java @@ -31,6 +31,7 @@ This file is part of the iText (R) project. import com.itextpdf.layout.layout.LayoutArea; import com.itextpdf.layout.layout.LayoutContext; import com.itextpdf.layout.layout.LayoutResult; +import com.itextpdf.layout.logs.LayoutLogMessageConstant; import com.itextpdf.layout.properties.ParagraphOrphansControl; import com.itextpdf.layout.properties.ParagraphWidowsControl; import com.itextpdf.layout.properties.Property; @@ -250,13 +251,13 @@ public void keepTogetherWidows() throws IOException, InterruptedException { } @Test - @LogMessages(messages = {@LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)}) + @LogMessages(messages = {@LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)}) public void keepTogetherLargeParagraphOrphans() throws IOException, InterruptedException { runKeepTogether("keepTogetherLargeParagraphOrphans", true, true); } @Test - @LogMessages(messages = {@LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)}) + @LogMessages(messages = {@LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)}) public void keepTogetherLargeParagraphWidows() throws IOException, InterruptedException { runKeepTogether("keepTogetherLargeParagraphWidows", false, true); } @@ -272,13 +273,13 @@ public void inlineImageWidows() throws IOException, InterruptedException { } @Test - @LogMessages(messages = {@LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 2)}) + @LogMessages(messages = {@LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 2)}) public void hugeInlineImageOrphans() throws IOException, InterruptedException { runHugeInlineImage("hugeInlineImageOrphans", true); } @Test - @LogMessages(messages = {@LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 2), + @LogMessages(messages = {@LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 2), @LogMessage(messageTemplate = IoLogMessageConstant.WIDOWS_CONSTRAINT_VIOLATED)}) public void hugeInlineImageWidows() throws IOException, InterruptedException { runHugeInlineImage("hugeInlineImageWidows", false); diff --git a/layout/src/test/java/com/itextpdf/layout/RotationTest.java b/layout/src/test/java/com/itextpdf/layout/RotationTest.java index 7ceb5dc63f..76a68dcc58 100644 --- a/layout/src/test/java/com/itextpdf/layout/RotationTest.java +++ b/layout/src/test/java/com/itextpdf/layout/RotationTest.java @@ -60,6 +60,7 @@ This file is part of the iText (R) project. import com.itextpdf.layout.element.Paragraph; import com.itextpdf.layout.element.Table; import com.itextpdf.layout.element.Text; +import com.itextpdf.layout.logs.LayoutLogMessageConstant; import com.itextpdf.layout.properties.BoxSizingPropertyValue; import com.itextpdf.layout.properties.HorizontalAlignment; import com.itextpdf.layout.properties.Property; @@ -193,7 +194,7 @@ public void fixedTextRotationTest04() throws IOException, InterruptedException { } @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) @Test public void staticTextRotationTest01() throws IOException, InterruptedException { @@ -215,7 +216,7 @@ public void staticTextRotationTest01() throws IOException, InterruptedException } @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 2) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 2) }) @Test public void staticTextRotationTest02() throws IOException, InterruptedException { @@ -237,7 +238,7 @@ public void staticTextRotationTest02() throws IOException, InterruptedException } @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) @Test public void staticTextRotationTest03() throws IOException, InterruptedException { @@ -294,7 +295,7 @@ public void splitTextRotationTest01() throws IOException, InterruptedException { } @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 2) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 2) }) @Test public void splitTextRotationTest02() throws IOException, InterruptedException { @@ -339,7 +340,7 @@ public void rotationInfiniteLoopTest01() throws IOException, InterruptedExceptio } @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) @Test public void rotationInfiniteLoopTest02() throws IOException, InterruptedException { @@ -383,7 +384,7 @@ public void tableRotationTest02() throws IOException, InterruptedException { } @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) @Test public void tableRotationTest03() throws IOException, InterruptedException { @@ -555,7 +556,7 @@ public void divRotationTest01() throws IOException, InterruptedException { } @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 2) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 2) }) @Test public void divRotationTest02() throws IOException, InterruptedException { @@ -606,7 +607,7 @@ public void listRotationTest01() throws IOException, InterruptedException { @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) @Test public void listRotationTest02() throws IOException, InterruptedException { @@ -681,7 +682,7 @@ public void innerRotationTest01() throws IOException, InterruptedException { } @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 3) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 3) }) @Test public void innerRotationTest02() throws IOException, InterruptedException { diff --git a/layout/src/test/java/com/itextpdf/layout/TableBorderTest.java b/layout/src/test/java/com/itextpdf/layout/TableBorderTest.java index 40ff7dafaf..3dced81ad4 100644 --- a/layout/src/test/java/com/itextpdf/layout/TableBorderTest.java +++ b/layout/src/test/java/com/itextpdf/layout/TableBorderTest.java @@ -44,6 +44,7 @@ This file is part of the iText (R) project. import com.itextpdf.io.logs.IoLogMessageConstant; import com.itextpdf.commons.utils.MessageFormatUtil; +import com.itextpdf.kernel.colors.Color; import com.itextpdf.kernel.colors.ColorConstants; import com.itextpdf.kernel.colors.DeviceRgb; import com.itextpdf.kernel.geom.PageSize; @@ -57,6 +58,7 @@ This file is part of the iText (R) project. import com.itextpdf.layout.element.Cell; import com.itextpdf.layout.element.Paragraph; import com.itextpdf.layout.element.Table; +import com.itextpdf.layout.logs.LayoutLogMessageConstant; import com.itextpdf.layout.properties.BorderCollapsePropertyValue; import com.itextpdf.layout.properties.Property; import com.itextpdf.layout.properties.UnitValue; @@ -103,11 +105,10 @@ public void cellWithBigRowspanOnThreePagesTest() throws IOException, Interrupted closeDocumentAndCompareOutputs(doc); } + @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.LAST_ROW_IS_NOT_COMPLETE) + @LogMessage(messageTemplate = IoLogMessageConstant.LAST_ROW_IS_NOT_COMPLETE, count = 2) }) - @Test - @Ignore("DEVSIX-1124") public void incompleteTableTest01() throws IOException, InterruptedException { fileName = "incompleteTableTest01.pdf"; Document doc = createDocument(); @@ -124,12 +125,9 @@ public void incompleteTableTest01() throws IOException, InterruptedException { // row 2, cell 1 cell = new Cell().add(new Paragraph("Three")); table.addCell(cell); - // row 3, cell 1 cell = new Cell().add(new Paragraph("Four")); table.addCell(cell); - - doc.add(table); doc.add(new AreaBreak()); @@ -140,7 +138,6 @@ public void incompleteTableTest01() throws IOException, InterruptedException { } @Test - @Ignore("DEVSIX-1124") public void incompleteTableTest02() throws IOException, InterruptedException { fileName = "incompleteTableTest02.pdf"; Document doc = createDocument(); @@ -597,6 +594,40 @@ public void borderCollapseTest02() throws IOException, InterruptedException { closeDocumentAndCompareOutputs(doc); } + @Test + public void borderCollapseTest02A() throws IOException, InterruptedException { + fileName = "borderCollapseTest02A.pdf"; + outFileName = destinationFolder + fileName; + cmpFileName = sourceFolder + cmpPrefix + fileName; + + PdfDocument pdfDocument = new PdfDocument(new PdfWriter(outFileName)); + Document doc = new Document(pdfDocument); + + Cell cell; + Table table = new Table(UnitValue.createPercentArray(2)).useAllAvailableWidth(); + for (int i = 0; i < 3; i++) { + // column 1 + cell = new Cell().add(new Paragraph("1")); + cell.setBorder(Border.NO_BORDER); + cell.setPadding(0); + cell.setMargin(0); + cell.setHeight(50); + cell.setBackgroundColor(ColorConstants.RED); + table.addCell(cell); + // column 2 + cell = new Cell().add(new Paragraph("2")); + cell.setPadding(0); + cell.setMargin(0); + cell.setBackgroundColor(ColorConstants.RED); + cell.setHeight(50); + cell.setBorder(i % 2 == 1 ? Border.NO_BORDER : new SolidBorder(20)); + table.addCell(cell); + } + doc.add(table); + + closeDocumentAndCompareOutputs(doc); + } + @Test public void borderCollapseTest03() throws IOException, InterruptedException { fileName = "borderCollapseTest03.pdf"; @@ -703,7 +734,7 @@ public void separatedBorderTest01C() throws IOException, InterruptedException { @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void infiniteLoopTest01() throws IOException, InterruptedException { fileName = "infiniteLoopTest01.pdf"; @@ -851,7 +882,7 @@ public void splitCellsTest02() throws IOException, InterruptedException { } @Test - @LogMessages(messages = {@LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)}) + @LogMessages(messages = {@LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)}) public void splitCellsTest03() throws IOException, InterruptedException { fileName = "splitCellsTest03.pdf"; Document doc = createDocument(); @@ -1215,6 +1246,25 @@ public void splitCellsTest10C() throws IOException, InterruptedException { closeDocumentAndCompareOutputs(doc); } + @Test + // TODO DEVSIX-5834 Consider this test when deciding on the strategy: + // left-bottom corner could be magenta as in Chrome + public void tableAndCellBordersCollapseTest01() throws IOException, InterruptedException { + fileName = "tableAndCellBordersCollapseTest01.pdf"; + Document doc = createDocument(); + + Table table = new Table(UnitValue.createPercentArray(1)).useAllAvailableWidth(); + table.setBorder(new SolidBorder(ColorConstants.GREEN, 100)); + + table.addCell( + new Cell().add(new Paragraph("Hello World")) + .setBorderBottom(new SolidBorder(ColorConstants.MAGENTA, 100)) + ); + + doc.add(table); + closeDocumentAndCompareOutputs(doc); + } + @Test public void tableWithHeaderFooterTest01() throws IOException, InterruptedException { fileName = "tableWithHeaderFooterTest01.pdf"; @@ -1249,6 +1299,7 @@ public void tableWithHeaderFooterTest01() throws IOException, InterruptedExcepti } @Test + // TODO DEVSIX-5864 footer's top border / body's bottom border should be drawn by footer public void tableWithHeaderFooterTest02() throws IOException, InterruptedException { fileName = "tableWithHeaderFooterTest02.pdf"; Document doc = createDocument(); @@ -1283,6 +1334,29 @@ public void tableWithHeaderFooterTest02() throws IOException, InterruptedExcepti closeDocumentAndCompareOutputs(doc); } + @Test + // TODO DEVSIX-5864 footer's top border / body's bottom border should be drawn by footer + public void tableWithHeaderFooterTest02A() throws IOException, InterruptedException { + fileName = "tableWithHeaderFooterTest02A.pdf"; + Document doc = createDocument(); + doc.getPdfDocument().setDefaultPageSize(new PageSize(595, 1500)); + Table table = new Table(UnitValue.createPercentArray(2)).useAllAvailableWidth(); + + for (int i = 1; i < 2; i += 2) { + table.addCell(new Cell().setHeight(30).add(new Paragraph("Cell" + i)) + .setBorderBottom(new SolidBorder(ColorConstants.BLUE, 400)).setBorderRight(new SolidBorder(20))); + table.addCell(new Cell().setHeight(30).add(new Paragraph("Cell" + (i + 1))) + .setBorderBottom(new SolidBorder(ColorConstants.BLUE, 100)).setBorderLeft(new SolidBorder(20))); + } + table.addFooterCell(new Cell().setHeight(30).add(new Paragraph("Footer1")) + .setBorderTop(new SolidBorder(ColorConstants.RED, 100))); + table.addFooterCell(new Cell().setHeight(30).add(new Paragraph("Footer2")) + .setBorderTop(new SolidBorder(ColorConstants.RED, 200))); + + doc.add(table); + closeDocumentAndCompareOutputs(doc); + } + @Test public void tableWithHeaderFooterTest03() throws IOException, InterruptedException { fileName = "tableWithHeaderFooterTest03.pdf"; @@ -1373,7 +1447,7 @@ public void tableWithHeaderFooterTest05() throws IOException, InterruptedExcepti } @Test - @LogMessages(messages = {@LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 10)}) + @LogMessages(messages = {@LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 10)}) public void tableWithHeaderFooterTest06() throws IOException, InterruptedException { fileName = "tableWithHeaderFooterTest06.pdf"; Document doc = createDocument(); @@ -1400,7 +1474,7 @@ public void tableWithHeaderFooterTest06() throws IOException, InterruptedExcepti } @Test - @LogMessages(messages = {@LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 10)}) + @LogMessages(messages = {@LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 10)}) public void tableWithHeaderFooterTest06A() throws IOException, InterruptedException { fileName = "tableWithHeaderFooterTest06A.pdf"; outFileName = destinationFolder + fileName; @@ -1431,7 +1505,36 @@ public void tableWithHeaderFooterTest06A() throws IOException, InterruptedExcept } @Test - @LogMessages(messages = {@LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 10)}) + public void verticalBordersInfluenceHorizontalTopAndBottomBordersTest() throws IOException, InterruptedException { + fileName = "verticalBordersInfluenceHorizontalTopAndbottomBordersTest.pdf"; + outFileName = destinationFolder + fileName; + cmpFileName = sourceFolder + cmpPrefix + fileName; + + PdfDocument pdfDocument = new PdfDocument(new PdfWriter(outFileName)); + Document doc = new Document(pdfDocument, PageSize.A6.rotate()); + + Table table = new Table(UnitValue.createPercentArray(5)).useAllAvailableWidth(); + Cell cell = new Cell(1, 5).add(new Paragraph("Table XYZ (Continued)")).setHeight(30).setBorderBottom(new SolidBorder(ColorConstants.RED, 20)); + table.addHeaderCell(cell); + cell = new Cell(1, 5).add(new Paragraph("Continue on next page")).setHeight(30).setBorderTop(new SolidBorder(ColorConstants.MAGENTA, 1)); + table.addFooterCell(cell); + for (int i = 0; i < 10; i++) { + table.addCell(new Cell() + .setBorderLeft(new SolidBorder(ColorConstants.BLUE, 20)) + .setBorderRight(new SolidBorder(ColorConstants.BLUE, 20)) + .setHeight(30) + .setBorderBottom(new SolidBorder(ColorConstants.RED, 50 - 2 * i + 1)) + .setBorderTop(new SolidBorder(ColorConstants.GREEN,50 - 2 * i + 1)) + .add(new Paragraph(String.valueOf(i + 1)))); + } + doc.add(table); + addTableBelowToCheckThatOccupiedAreaIsCorrect(doc); + + closeDocumentAndCompareOutputs(doc); + } + + @Test + @LogMessages(messages = {@LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 10)}) public void tableWithHeaderFooterTest06B() throws IOException, InterruptedException { fileName = "tableWithHeaderFooterTest06B.pdf"; outFileName = destinationFolder + fileName; @@ -1981,7 +2084,7 @@ public void tableWithHeaderFooterTest19() throws IOException, InterruptedExcepti } @Test - @LogMessages(messages = {@LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)}) + @LogMessages(messages = {@LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)}) public void tableWithHeaderFooterTest20() throws IOException, InterruptedException { fileName = "tableWithHeaderFooterTest20.pdf"; Document doc = createDocument(); @@ -2003,7 +2106,103 @@ public void tableWithHeaderFooterTest20() throws IOException, InterruptedExcepti } @Test - @LogMessages(messages = {@LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)}) + public void cellBorderPriorityTest() throws IOException, InterruptedException { + fileName = "cellBorderPriorityTest.pdf"; + Document doc = createDocument(); + + Table table = new Table(UnitValue.createPercentArray(3)).useAllAvailableWidth(); + + Cell cell = new Cell().add(new Paragraph("Hello")); + cell.setBorderTop(new SolidBorder(ColorConstants.RED, 50)); + cell.setBorderRight(new SolidBorder(ColorConstants.GREEN, 50)); + cell.setBorderBottom(new SolidBorder(ColorConstants.BLUE, 50)); + cell.setBorderLeft(new SolidBorder(ColorConstants.BLACK, 50)); + cell.setHeight(100).setWidth(100); + + for (int i = 0; i < 9; i++) { + table.addCell(cell.clone(true)); + } + doc.add(table); + + closeDocumentAndCompareOutputs(doc); + } + + @Test + public void cellBorderPriorityTest02() throws IOException, InterruptedException { + fileName = "cellBorderPriorityTest02.pdf"; + Document doc = createDocument(); + + Table table = new Table(UnitValue.createPercentArray(3)).useAllAvailableWidth(); + + Color[] array = {ColorConstants.RED, ColorConstants.GREEN, ColorConstants.BLUE, ColorConstants.RED, + ColorConstants.GREEN, ColorConstants.BLUE}; + + for (int i = 0; i < 3; i++) { + Cell cell = new Cell().add(new Paragraph("Hello")); + cell.setBorder(new SolidBorder(array[i], 50)); + table.addCell(cell); + + cell = new Cell().add(new Paragraph("Hello")); + cell.setBorder(new SolidBorder(array[i+1], 50)); + table.addCell(cell); + + cell = new Cell().add(new Paragraph("Hello")); + cell.setBorder(new SolidBorder(array[i+2], 50)); + table.addCell(cell); + } + doc.add(table); + + closeDocumentAndCompareOutputs(doc); + } + + @Test + public void cellsBorderPriorityTest() throws IOException, InterruptedException { + fileName = "cellsBorderPriorityTest.pdf"; + Document doc = createDocument(); + + Table table = new Table(UnitValue.createPercentArray(2)); + + Cell cell = new Cell().add(new Paragraph("1")); + cell.setBorder(new SolidBorder(ColorConstants.RED, 20)); + table.addCell(cell); + + cell = new Cell().add(new Paragraph("2")); + cell.setBorder(new SolidBorder(ColorConstants.GREEN, 20)); + table.addCell(cell); + + cell = new Cell().add(new Paragraph("3")); + cell.setBorder(new SolidBorder(ColorConstants.BLUE, 20)); + table.addCell(cell); + + cell = new Cell().add(new Paragraph("4")); + cell.setBorder(new SolidBorder(ColorConstants.BLACK, 20)); + table.addCell(cell); + + doc.add(table); + + closeDocumentAndCompareOutputs(doc); + } + + @Test + public void tableBorderPriorityTest() throws IOException, InterruptedException { + fileName = "tableBorderPriorityTest.pdf"; + Document doc = createDocument(); + + Table table = new Table(UnitValue.createPercentArray(1)).useAllAvailableWidth(); + table.setBorderTop(new SolidBorder(ColorConstants.RED, 20)); + table.setBorderRight(new SolidBorder(ColorConstants.GREEN, 20)); + table.setBorderBottom(new SolidBorder(ColorConstants.BLUE, 20)); + table.setBorderLeft(new SolidBorder(ColorConstants.BLACK, 20)); + + Cell cell = new Cell().add(new Paragraph("Hello")); + table.addCell(cell); + doc.add(table); + + closeDocumentAndCompareOutputs(doc); + } + + @Test + @LogMessages(messages = {@LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)}) public void splitRowspanKeepTogetherTest() throws IOException, InterruptedException { fileName = "splitRowspanKeepTogetherTest.pdf"; Document doc = createDocument(); @@ -2044,7 +2243,7 @@ public void splitRowspanKeepTogetherTest() throws IOException, InterruptedExcept @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 4), + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 4), @LogMessage(messageTemplate = IoLogMessageConstant.RECTANGLE_HAS_NEGATIVE_SIZE, count = 2), }) @@ -2187,6 +2386,56 @@ public void headerTopBorderTest01() throws IOException, InterruptedException { closeDocumentAndCompareOutputs(doc); } + @Test + public void equalBordersSameInstancesTest() throws IOException, InterruptedException { + fileName = "equalBordersSameInstancesTest.pdf"; + Document doc = createDocument(); + + Border border = new SolidBorder(ColorConstants.RED, 20); + + int colNum = 4; + Table table = new Table(UnitValue.createPercentArray(colNum)).useAllAvailableWidth(); + + int rowNum = 4; + for (int i = 0; i < rowNum; i++) { + for (int j = 0; j < colNum; j++) { + table.addCell(new Cell().add(new Paragraph("Cell: " + i + ", " + j)).setBorder(border)); + } + } + + doc.add(table); + doc.add(new Table(UnitValue.createPercentArray(1)).useAllAvailableWidth() + .addCell(new Cell().add(new Paragraph("Hello"))).setBorder(new SolidBorder(ColorConstants.BLACK, 10))); + + closeDocumentAndCompareOutputs(doc); + } + + @Test + public void verticalMiddleBorderTest() throws IOException, InterruptedException { + String testName = "verticalMiddleBorderTest.pdf"; + String outFileName = destinationFolder + testName; + String cmpFileName = sourceFolder + "cmp_" + testName; + + PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName)); + Document doc = new Document(pdfDoc); + + Table table = new Table(UnitValue.createPercentArray(2)).useAllAvailableWidth(); + + for (int i = 0; i < 4; i++) { + if (i % 2 == 1) { + Cell cell = new Cell().add(new Paragraph("Left Cell " + i)) + .setBorderLeft(new SolidBorder(ColorConstants.GREEN, 20)); + table.addCell(cell); + } else { + table.addCell("Right cell " + i); + } + } + + doc.add(table); + + doc.close(); + Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder)); + } private Document createDocument() throws FileNotFoundException { outFileName = destinationFolder + fileName; diff --git a/layout/src/test/java/com/itextpdf/layout/TableTest.java b/layout/src/test/java/com/itextpdf/layout/TableTest.java index 602cd070e8..b94facd5a2 100644 --- a/layout/src/test/java/com/itextpdf/layout/TableTest.java +++ b/layout/src/test/java/com/itextpdf/layout/TableTest.java @@ -42,8 +42,8 @@ This file is part of the iText (R) project. */ package com.itextpdf.layout; -import com.itextpdf.io.logs.IoLogMessageConstant; import com.itextpdf.io.image.ImageDataFactory; +import com.itextpdf.io.logs.IoLogMessageConstant; import com.itextpdf.io.util.UrlUtil; import com.itextpdf.kernel.colors.ColorConstants; import com.itextpdf.kernel.geom.PageSize; @@ -67,6 +67,7 @@ This file is part of the iText (R) project. import com.itextpdf.layout.layout.LayoutArea; import com.itextpdf.layout.layout.LayoutContext; import com.itextpdf.layout.layout.LayoutResult; +import com.itextpdf.layout.logs.LayoutLogMessageConstant; import com.itextpdf.layout.minmaxwidth.MinMaxWidth; import com.itextpdf.layout.properties.BorderCollapsePropertyValue; import com.itextpdf.layout.properties.CaptionSide; @@ -80,14 +81,13 @@ This file is part of the iText (R) project. import com.itextpdf.test.annotations.LogMessages; import com.itextpdf.test.annotations.type.IntegrationTest; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.junit.experimental.categories.Category; -import java.io.ByteArrayOutputStream; -import java.io.IOException; - @Category(IntegrationTest.class) public class TableTest extends AbstractTableTest { public static final String sourceFolder = "./src/test/resources/com/itextpdf/layout/TableTest/"; @@ -539,9 +539,41 @@ public void simpleTableTest16() throws IOException, InterruptedException { Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, testName + "_diff")); } + @Test + public void wideFirstCellBorderDoesntAffectSecondCellTest() throws IOException, InterruptedException { + String testName = "wideFirstCellBorderDoesntAffectSecondCellTest.pdf"; + String outFileName = destinationFolder + testName; + String cmpFileName = sourceFolder + "cmp_" + testName; + + PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName)); + Document doc = new Document(pdfDoc); + + String longTextContent = "1. " + TEXT_CONTENT + "2. " + TEXT_CONTENT + "3. " + TEXT_CONTENT + "4. " + + TEXT_CONTENT + "5. " + TEXT_CONTENT + "6. " + TEXT_CONTENT + "7. " + TEXT_CONTENT + "8. " + + TEXT_CONTENT + "9. " + TEXT_CONTENT; + + Table table = new Table(new float[] {250, 250}) + .addCell(new Cell().add(new Paragraph("cell 1, 1"))) + .addCell(new Cell().add(new Paragraph("cell 1, 2")).setBorder(new SolidBorder(ColorConstants.RED, 100))) + .addCell(new Cell().add(new Paragraph("cell 2, 1\n" + longTextContent))) + .addCell(new Cell().add(new Paragraph("cell 2, 2\n" + longTextContent))) + .addCell(new Cell().add(new Paragraph("cell 2, 1\n" + longTextContent))) + .addCell(new Cell().add(new Paragraph("cell 2, 2\n" + longTextContent))) + .addCell(new Cell().add(new Paragraph("cell 2, 1\n" + longTextContent))) + .addCell(new Cell().add(new Paragraph("cell 2, 2\n" + longTextContent))) + .addCell(new Cell().add(new Paragraph("cell 2, 1\n" + longTextContent))) + .addCell(new Cell().add(new Paragraph("cell 2, 2\n" + longTextContent))) + .addCell(new Cell().add(new Paragraph("cell 2, 1\n" + longTextContent))) + .addCell(new Cell().add(new Paragraph("cell 2, 2\n" + longTextContent))); + doc.add(table); + doc.close(); + Assert.assertNull( + new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, testName + "_diff")); + } + @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1) }) public void simpleTableTest17() throws IOException, InterruptedException { String testName = "tableTest17.pdf"; @@ -571,7 +603,7 @@ public void simpleTableTest17() throws IOException, InterruptedException { @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1) }) public void simpleTableTest18() throws IOException, InterruptedException { String testName = "tableTest18.pdf"; @@ -603,7 +635,7 @@ public void simpleTableTest18() throws IOException, InterruptedException { @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1) }) public void simpleTableTest19() throws IOException, InterruptedException { String testName = "tableTest19.pdf"; @@ -634,7 +666,7 @@ public void simpleTableTest19() throws IOException, InterruptedException { @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1) }) public void simpleTableTest20() throws IOException, InterruptedException { String testName = "tableTest20.pdf"; @@ -661,7 +693,7 @@ public void simpleTableTest20() throws IOException, InterruptedException { @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1) }) public void simpleTableTest21() throws IOException, InterruptedException { String testName = "tableTest21.pdf"; @@ -1022,7 +1054,7 @@ public void extendLastRowTest01() throws IOException, InterruptedException { } @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1) }) @Test public void toLargeElementWithKeepTogetherPropertyInTableTest01() throws IOException, InterruptedException { @@ -1052,7 +1084,7 @@ public void toLargeElementWithKeepTogetherPropertyInTableTest01() throws IOExcep } @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1) }) @Test @@ -1182,7 +1214,7 @@ public void nestedTablesWithMarginsTest01() throws IOException, InterruptedExcep } @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1) }) @Test public void splitTableOnShortPage() throws IOException, InterruptedException { @@ -1609,7 +1641,7 @@ public void tableWithHeaderInTheBottomOfPageTest() throws IOException, Interrupt } @Test - @LogMessages(messages = {@LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)}) + @LogMessages(messages = {@LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)}) public void bigFooterTest01() throws IOException, InterruptedException { String testName = "bigFooterTest01.pdf"; String outFileName = destinationFolder + testName; @@ -1629,7 +1661,7 @@ public void bigFooterTest01() throws IOException, InterruptedException { } @Test - @LogMessages(messages = {@LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)}) + @LogMessages(messages = {@LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)}) public void bigFooterTest02() throws IOException, InterruptedException { String testName = "bigFooterTest02.pdf"; String outFileName = destinationFolder + testName; @@ -1987,7 +2019,7 @@ public void tableSplitTest04() throws IOException, InterruptedException { @Test @LogMessages(messages = { @LogMessage(messageTemplate = IoLogMessageConstant.LAST_ROW_IS_NOT_COMPLETE), - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void tableNothingResultTest() throws IOException, InterruptedException { String testName = "tableNothingResultTest.pdf"; @@ -2011,6 +2043,200 @@ public void tableNothingResultTest() throws IOException, InterruptedException { Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, testName + "_diff")); } + @Test + @LogMessages(messages = { + @LogMessage(messageTemplate = IoLogMessageConstant.LAST_ROW_IS_NOT_COMPLETE) + }) + public void tableWithEmptyLastRowTest() throws IOException, InterruptedException { + String testName = "tableWithEmptyLastRowTest.pdf"; + String outFileName = destinationFolder + testName; + String cmpFileName = sourceFolder + "cmp_" + testName; + + PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName)); + Document doc = new Document(pdfDoc); + + Table table = new Table(UnitValue.createPercentArray(new float[]{30, 30})); + table.addCell(new Cell().add(new Paragraph("Hello"))); + table.addCell(new Cell().add(new Paragraph("World"))); + startSeveralEmptyRows(table); + doc.add(table); + + doc.close(); + Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, testName + "_diff")); + } + + @Test + @LogMessages(messages = { + @LogMessage(messageTemplate = IoLogMessageConstant.UNEXPECTED_BEHAVIOUR_DURING_TABLE_ROW_COLLAPSING) + }) + public void tableWithEmptyRowsBetweenFullRowsTest() throws IOException, InterruptedException { + String testName = "tableWithEmptyRowsBetweenFullRowsTest.pdf"; + String outFileName = destinationFolder + testName; + String cmpFileName = sourceFolder + "cmp_" + testName; + + PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName)); + Document doc = new Document(pdfDoc); + + Table table = new Table(UnitValue.createPercentArray(new float[]{30, 30})); + table.addCell(new Cell().add(new Paragraph("Hello"))); + table.addCell(new Cell().add(new Paragraph("World"))); + startSeveralEmptyRows(table); + table.addCell(new Cell().add(new Paragraph("Hello"))); + table.addCell(new Cell().add(new Paragraph("World"))); + doc.add(table); + + doc.close(); + Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, testName + "_diff")); + } + + @Test + @LogMessages(messages = { + @LogMessage(messageTemplate = IoLogMessageConstant.UNEXPECTED_BEHAVIOUR_DURING_TABLE_ROW_COLLAPSING, count = 2), + @LogMessage(messageTemplate = IoLogMessageConstant.LAST_ROW_IS_NOT_COMPLETE) + }) + public void tableWithEmptyRowAfterJustOneCellTest() throws IOException, InterruptedException { + String testName = "tableWithEmptyRowAfterJustOneCellTest.pdf"; + String outFileName = destinationFolder + testName; + String cmpFileName = sourceFolder + "cmp_" + testName; + + PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName)); + Document doc = new Document(pdfDoc); + + Table table = new Table(3); + for (int i = 0; i < 3; i++) { + for (int j = 0; j <= i; j++) { + table.addCell(new Cell().add(new Paragraph("Hello"))); + } + startSeveralEmptyRows(table); + } + doc.add(table); + + doc.close(); + Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, testName + "_diff")); + } + + @Test + @LogMessages(messages = { + @LogMessage(messageTemplate = IoLogMessageConstant.UNEXPECTED_BEHAVIOUR_DURING_TABLE_ROW_COLLAPSING, count = 39), + @LogMessage(messageTemplate = IoLogMessageConstant.LAST_ROW_IS_NOT_COMPLETE) + }) + public void tableWithAlternatingRowsTest() throws IOException, InterruptedException { + String testName = "tableWithAlternatingRowsTest.pdf"; + String outFileName = destinationFolder + testName; + String cmpFileName = sourceFolder + "cmp_" + testName; + + PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName)); + Document doc = new Document(pdfDoc); + + Table table = new Table(UnitValue.createPercentArray(new float[]{30, 30})); + for (int i = 0; i < 40; i++) { + table.addCell(new Cell().add(new Paragraph("Hello"))); + table.addCell(new Cell().add(new Paragraph("World"))); + startSeveralEmptyRows(table); + } + doc.add(table); + + doc.close(); + Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, testName + "_diff")); + } + + @Test + public void coloredTableWithColoredCellsTest() throws IOException, InterruptedException { + String testName = "coloredTableWithColoredCellsTest.pdf"; + String outFileName = destinationFolder + testName; + String cmpFileName = sourceFolder + "cmp_" + testName; + + PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName)); + Document doc = new Document(pdfDoc); + + Table table = new Table(UnitValue.createPercentArray(new float[]{30, 30})); + table.setBackgroundColor(ColorConstants.RED); + for (int i = 0; i < 40; i++) { + table.addCell(new Cell().add(new Paragraph("Hello")).setBackgroundColor(ColorConstants.GREEN)); + table.startNewRow(); + } + table.addCell(new Cell().add(new Paragraph("Hello")).setBackgroundColor(ColorConstants.GREEN)); + table.addCell(new Cell().add(new Paragraph("World")).setBackgroundColor(ColorConstants.GREEN)); + doc.add(table); + + doc.close(); + Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, testName + "_diff")); + } + + @Test + @LogMessages(messages = { + @LogMessage(messageTemplate = IoLogMessageConstant.UNEXPECTED_BEHAVIOUR_DURING_TABLE_ROW_COLLAPSING, count = 2) + }) + public void tableWithEmptyRowsAndSeparatedBordersTest() throws IOException, InterruptedException { + String testName = "tableWithEmptyRowsAndSeparatedBordersTest.pdf"; + String outFileName = destinationFolder + testName; + String cmpFileName = sourceFolder + "cmp_" + testName; + + PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName)); + Document doc = new Document(pdfDoc); + + Table table = new Table(UnitValue.createPercentArray(new float[]{30, 30})); + table.setBorderCollapse(BorderCollapsePropertyValue.SEPARATE); + table.addCell(new Cell().add(new Paragraph("Hello"))); + table.addCell(new Cell().add(new Paragraph("World"))); + startSeveralEmptyRows(table); + table.addCell(new Cell().add(new Paragraph("Hello"))); + table.addCell(new Cell().add(new Paragraph("World"))); + doc.add(table); + + doc.close(); + Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, testName + "_diff")); + } + + @Test + // TODO DEVSIX-6020:Border-collapsing doesn't work in case startNewRow has been called + @LogMessages(messages = { + @LogMessage(messageTemplate = IoLogMessageConstant.UNEXPECTED_BEHAVIOUR_DURING_TABLE_ROW_COLLAPSING) + }) + public void tableWithCollapsedBordersTest() throws IOException, InterruptedException { + String testName = "tableWithCollapsedBordersTest.pdf"; + String outFileName = destinationFolder + testName; + String cmpFileName = sourceFolder + "cmp_" + testName; + + PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName)); + Document doc = new Document(pdfDoc); + + Table table = new Table(UnitValue.createPercentArray(new float[]{30, 30})); + table.addCell(new Cell().add(new Paragraph("Hello")).setBorderBottom(new SolidBorder(ColorConstants.BLUE, 10))); + table.addCell(new Cell().add(new Paragraph("World")).setBorderBottom(new SolidBorder(ColorConstants.BLUE, 10))); + startSeveralEmptyRows(table); + table.addCell(new Cell().add(new Paragraph("Hello")).setBorderTop(new SolidBorder(ColorConstants.RED, 20))); + table.addCell(new Cell().add(new Paragraph("World")).setBorderTop(new SolidBorder(ColorConstants.RED, 20))); + doc.add(table); + + doc.close(); + Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, testName + "_diff")); + } + + @Test + @LogMessages(messages = { + @LogMessage(messageTemplate = IoLogMessageConstant.LAST_ROW_IS_NOT_COMPLETE) + }) + public void tableWithCollapsedBordersAndFooterTest() throws IOException, InterruptedException { + String testName = "tableWithCollapsedBordersAndFooterTest.pdf"; + String outFileName = destinationFolder + testName; + String cmpFileName = sourceFolder + "cmp_" + testName; + + PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName)); + Document doc = new Document(pdfDoc); + + Table table = new Table(UnitValue.createPercentArray(new float[]{30, 30})); + table.addCell(new Cell().add(new Paragraph("Hello")).setBorderBottom(new SolidBorder(ColorConstants.BLUE, 10))); + table.addCell(new Cell().add(new Paragraph("World")).setBorderBottom(new SolidBorder(ColorConstants.BLUE, 10))); + startSeveralEmptyRows(table); + table.addFooterCell(new Cell().add(new Paragraph("Hello")).setBorderTop(new SolidBorder(ColorConstants.RED, 20))); + table.addFooterCell(new Cell().add(new Paragraph("World")).setBorderTop(new SolidBorder(ColorConstants.RED, 20))); + doc.add(table); + + doc.close(); + Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, testName + "_diff")); + } + @Test public void autoLayoutTest01() throws IOException, InterruptedException { String testName = "autoLayoutTest01.pdf"; @@ -2164,7 +2390,7 @@ public void fixedPositionTest01() throws IOException, InterruptedException { } @Test - @LogMessages(messages = {@LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)}) + @LogMessages(messages = {@LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)}) // When the test was created, only first line of text was displayed on the first page public void nestedTableLostContent() throws IOException, InterruptedException { String testName = "nestedTableLostContent.pdf"; @@ -2191,7 +2417,7 @@ public void nestedTableLostContent() throws IOException, InterruptedException { } @Test - @LogMessages(messages = {@LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)}) + @LogMessages(messages = {@LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)}) // When the test was created, an exception was thrown due to min-max width calculations for an inner table. // At some point isOriginalNonSplitRenderer was true for a parent renderer but false for the inner table renderer public void nestedTableMinMaxWidthException() throws IOException, InterruptedException { @@ -3054,7 +3280,7 @@ public void inheritHeaderPropsWhileMinMaxWidthCalculationsTest() throws IOExcept @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void infiniteLoopOnUnfitCellAndBigRowspanTest() throws IOException, InterruptedException { String testName = "infiniteLoopOnUnfitCellAndBigRowspanTest.pdf"; @@ -3088,7 +3314,7 @@ public void infiniteLoopOnUnfitCellAndBigRowspanTest() throws IOException, Inter @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA), + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA), @LogMessage(messageTemplate = IoLogMessageConstant.TABLE_WIDTH_IS_MORE_THAN_EXPECTED_DUE_TO_MIN_WIDTH) }) public void firstRowNotFitBigRowspanTest() throws IOException, InterruptedException { @@ -3193,7 +3419,7 @@ public void bigRowSpanTooFarPartialTest() throws IOException, InterruptedExcepti @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1) }) // TODO DEVSIX-5250 The first column should be fully red public void bigRowSpanTooFarNothingTest() throws IOException, InterruptedException { @@ -3231,6 +3457,71 @@ public void bigRowSpanTooFarNothingTest() throws IOException, InterruptedExcepti sourceFolder + "cmp_" + filename, destinationFolder)); } + @Test + // TODO DEVSIX-5916 The first cell's width is the same as the second one's, however, it's not respected + public void setWidthShouldBeRespectedTest() throws IOException, InterruptedException { + String fileName = "setWidthShouldBeRespectedTest.pdf"; + + PdfDocument pdfDocument = new PdfDocument(new PdfWriter(destinationFolder + fileName)); + Document doc = new Document(pdfDocument, new PageSize(842, 1400)); + + Table table = new Table(2); + table.setBorder(new SolidBorder(ColorConstants.GREEN, 90f)); + + Cell cell; + cell = new Cell().add(new Paragraph("100pt")); + cell.setBorder(new SolidBorder(ColorConstants.BLUE, 20f)); + cell.setWidth(100).setMargin(0).setPadding(0); + table.addCell(cell); + + cell = new Cell().add(new Paragraph("100pt")); + cell.setBorder(new SolidBorder(ColorConstants.RED, 120f)); + cell.setWidth(100).setMargin(0).setPadding(0); + table.addCell(cell); + + doc.add(table); + doc.close(); + + Assert.assertNull(new CompareTool().compareByContent(destinationFolder + fileName, + sourceFolder + "cmp_" + fileName, destinationFolder)); + } + + //creates 2 empty lines, where 2 is random number + private static void startSeveralEmptyRows(Table table) { + table.startNewRow(); + table.startNewRow(); + } + + @Test + public void tableRelayoutTest() { + try (PdfDocument pdfDoc = new PdfDocument(new PdfWriter(new ByteArrayOutputStream())); + Document doc = new Document(pdfDoc)) { + + float width = 142f; + + Table table = new Table(1); + table.setWidth(width); + table.setFixedLayout(); + Cell cell = new Cell(); + cell.setWidth(width); + cell.add(new Paragraph("Testing, FinancialProfessional Associate adasdasdasdasada.gmail.com")); + table.addCell(cell); + + LayoutResult result = table.createRendererSubTree().setParent(doc.getRenderer()) + .layout(new LayoutContext(new LayoutArea(1, + new Rectangle(0, 0, 10000, 10000.0F)))); + + Rectangle tableRect = result.getOccupiedArea().getBBox(); + + result = table.createRendererSubTree().setParent(doc.getRenderer()).layout(new LayoutContext( + new LayoutArea(1, new Rectangle(0, 0, 10000, 10000.0F)))); + + Rectangle tableRectRelayout = result.getOccupiedArea().getBBox(); + + Assert.assertTrue(tableRect.equalsWithEpsilon(tableRectRelayout)); + } + } + private static class RotatedDocumentRenderer extends DocumentRenderer { private final PdfDocument pdfDoc; diff --git a/layout/src/test/java/com/itextpdf/layout/element/FlexContainerTest.java b/layout/src/test/java/com/itextpdf/layout/element/FlexContainerTest.java index 629e65e7fe..26efc35e04 100644 --- a/layout/src/test/java/com/itextpdf/layout/element/FlexContainerTest.java +++ b/layout/src/test/java/com/itextpdf/layout/element/FlexContainerTest.java @@ -22,7 +22,6 @@ This file is part of the iText (R) project. */ package com.itextpdf.layout.element; -import com.itextpdf.io.logs.IoLogMessageConstant; import com.itextpdf.io.image.ImageDataFactory; import com.itextpdf.kernel.colors.ColorConstants; import com.itextpdf.kernel.pdf.PdfDocument; @@ -31,6 +30,7 @@ This file is part of the iText (R) project. import com.itextpdf.layout.Document; import com.itextpdf.layout.Style; import com.itextpdf.layout.borders.SolidBorder; +import com.itextpdf.layout.logs.LayoutLogMessageConstant; import com.itextpdf.layout.properties.AlignmentPropertyValue; import com.itextpdf.layout.properties.Background; import com.itextpdf.layout.properties.BoxSizingPropertyValue; @@ -212,7 +212,7 @@ public void flexContainerHeightClippedTest() throws IOException, InterruptedExce } @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA), ignore = true) + @LogMessages(messages = @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA), ignore = true) // TODO DEVSIX-5042 HEIGHT property is ignored when FORCED_PLACEMENT is true public void flexContainerDifferentChildrenDontFitHorizontallyTest() throws IOException, InterruptedException { String outFileName = destinationFolder + "flexContainerDifferentChildrenDontFitHorizontallyTest" + comparisonPdfId + ".pdf"; diff --git a/layout/src/test/java/com/itextpdf/layout/margincollapse/MarginsCollapseHandlerTest.java b/layout/src/test/java/com/itextpdf/layout/margincollapse/MarginsCollapseHandlerTest.java new file mode 100644 index 0000000000..513b8c185c --- /dev/null +++ b/layout/src/test/java/com/itextpdf/layout/margincollapse/MarginsCollapseHandlerTest.java @@ -0,0 +1,92 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2021 iText Group NV + Authors: Bruno Lowagie, Paulo Soares, et al. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License version 3 + as published by the Free Software Foundation with the addition of the + following permission added to Section 15 as permitted in Section 7(a): + FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY + ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT + OF THIRD PARTY RIGHTS + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Affero General Public License for more details. + You should have received a copy of the GNU Affero General Public License + along with this program; if not, see http://www.gnu.org/licenses or write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA, 02110-1301 USA, or download the license from the following URL: + http://itextpdf.com/terms-of-use/ + + The interactive user interfaces in modified source and object code versions + of this program must display Appropriate Legal Notices, as required under + Section 5 of the GNU Affero General Public License. + + In accordance with Section 7(b) of the GNU Affero General Public License, + a covered work must retain the producer line in every PDF that is created + or manipulated using iText. + + You can be released from the requirements of the license by purchasing + a commercial license. Buying such a license is mandatory as soon as you + develop commercial activities involving the iText software without + disclosing the source code of your own applications. + These activities include: offering paid services to customers as an ASP, + serving PDFs on the fly in a web application, shipping iText with a closed + source product. + + For more information, please contact iText Software Corp. at this + address: sales@itextpdf.com + */ +package com.itextpdf.layout.margincollapse; + +import com.itextpdf.io.logs.IoLogMessageConstant; +import com.itextpdf.kernel.geom.Rectangle; +import com.itextpdf.layout.element.Paragraph; +import com.itextpdf.layout.properties.Property; +import com.itextpdf.layout.properties.UnitValue; +import com.itextpdf.layout.renderer.ParagraphRenderer; +import com.itextpdf.test.AssertUtil; +import com.itextpdf.test.ExtendedITextTest; +import com.itextpdf.test.annotations.LogMessage; +import com.itextpdf.test.annotations.LogMessages; +import com.itextpdf.test.annotations.type.UnitTest; + +import org.junit.Test; +import org.junit.experimental.categories.Category; + +@Category(UnitTest.class) +public class MarginsCollapseHandlerTest extends ExtendedITextTest { + + @Test + @LogMessages(messages = { + @LogMessage(messageTemplate = IoLogMessageConstant.PROPERTY_IN_PERCENTS_NOT_SUPPORTED, count = 2) + }) + // This test's aim is to test message logging. + public void testDefiningMarginCollapse() { + ParagraphRenderer paragraphRenderer = new ParagraphRenderer(new Paragraph()); + Rectangle rectangle = new Rectangle(0f, 0f); + paragraphRenderer.getModelElement().setProperty(Property.MARGIN_TOP, UnitValue.createPercentValue(0f)); + paragraphRenderer.getModelElement().setProperty(Property.MARGIN_BOTTOM, UnitValue.createPercentValue(0f)); + + MarginsCollapseHandler marginsCollapseHandler = new MarginsCollapseHandler(paragraphRenderer, null); + AssertUtil.doesNotThrow(() -> marginsCollapseHandler.startMarginsCollapse(rectangle)); + } + + @Test + @LogMessages(messages = { + @LogMessage(messageTemplate = IoLogMessageConstant.PROPERTY_IN_PERCENTS_NOT_SUPPORTED, count = 2) + }) + // This test's aim is to test message logging. + public void testHasPadding() { + ParagraphRenderer paragraphRenderer = new ParagraphRenderer(new Paragraph()); + Rectangle rectangle = new Rectangle(0f, 0f); + paragraphRenderer.getModelElement().setProperty(Property.PADDING_TOP, UnitValue.createPercentValue(0f)); + paragraphRenderer.getModelElement().setProperty(Property.PADDING_BOTTOM, UnitValue.createPercentValue(0f)); + + MarginsCollapseHandler marginsCollapseHandler = new MarginsCollapseHandler(paragraphRenderer, null); + AssertUtil.doesNotThrow(() -> marginsCollapseHandler.startMarginsCollapse(rectangle)); + } +} \ No newline at end of file diff --git a/layout/src/test/java/com/itextpdf/layout/properties/BackgroundImageTest.java b/layout/src/test/java/com/itextpdf/layout/properties/BackgroundImageTest.java index ddb84361ca..7c056611e6 100644 --- a/layout/src/test/java/com/itextpdf/layout/properties/BackgroundImageTest.java +++ b/layout/src/test/java/com/itextpdf/layout/properties/BackgroundImageTest.java @@ -42,7 +42,6 @@ This file is part of the iText (R) project. */ package com.itextpdf.layout.properties; -import com.itextpdf.io.logs.IoLogMessageConstant; import com.itextpdf.io.image.ImageData; import com.itextpdf.io.image.ImageDataFactory; import com.itextpdf.kernel.colors.ColorConstants; @@ -63,6 +62,7 @@ This file is part of the iText (R) project. import com.itextpdf.layout.element.Div; import com.itextpdf.layout.element.Paragraph; import com.itextpdf.layout.element.Text; +import com.itextpdf.layout.logs.LayoutLogMessageConstant; import com.itextpdf.layout.properties.BackgroundRepeat.BackgroundRepeatValue; import com.itextpdf.test.ExtendedITextTest; import com.itextpdf.test.LogLevelConstants; @@ -195,7 +195,7 @@ public void backgroundImageWithLinearGradientAndPositionAndRepeatTest() throws I @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, logLevel = LogLevelConstants.WARN) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, logLevel = LogLevelConstants.WARN) }) public void backgroundImageWithLinearGradientAndTransformTest() throws IOException, InterruptedException { AbstractLinearGradientBuilder gradientBuilder = new StrategyBasedLinearGradientBuilder() diff --git a/layout/src/test/java/com/itextpdf/layout/renderer/MinWidthTest.java b/layout/src/test/java/com/itextpdf/layout/renderer/MinWidthTest.java index 33f8227640..3ffc308030 100644 --- a/layout/src/test/java/com/itextpdf/layout/renderer/MinWidthTest.java +++ b/layout/src/test/java/com/itextpdf/layout/renderer/MinWidthTest.java @@ -59,6 +59,7 @@ This file is part of the iText (R) project. import com.itextpdf.layout.element.Paragraph; import com.itextpdf.layout.element.Table; import com.itextpdf.layout.element.Text; +import com.itextpdf.layout.logs.LayoutLogMessageConstant; import com.itextpdf.layout.minmaxwidth.MinMaxWidth; import com.itextpdf.layout.minmaxwidth.MinMaxWidthUtils; import com.itextpdf.layout.properties.UnitValue; @@ -146,7 +147,7 @@ public void divWithSmallRotatedParagraph() throws IOException, InterruptedExcept @Test - @LogMessages(messages = @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) + @LogMessages(messages = @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)) public void divWithBigRotatedParagraph() throws IOException, InterruptedException { String outFileName = destinationFolder + "divBigRotatedParagraphTest01.pdf"; String cmpFileName = sourceFolder + "cmp_divBigRotatedParagraphTest01.pdf"; diff --git a/layout/src/test/java/com/itextpdf/layout/renderer/TextRendererIntegrationTest.java b/layout/src/test/java/com/itextpdf/layout/renderer/TextRendererIntegrationTest.java index cf89d340f9..77c0639037 100644 --- a/layout/src/test/java/com/itextpdf/layout/renderer/TextRendererIntegrationTest.java +++ b/layout/src/test/java/com/itextpdf/layout/renderer/TextRendererIntegrationTest.java @@ -44,6 +44,7 @@ This file is part of the iText (R) project. import com.itextpdf.layout.element.Paragraph; import com.itextpdf.layout.element.Table; import com.itextpdf.layout.element.Text; +import com.itextpdf.layout.logs.LayoutLogMessageConstant; import com.itextpdf.layout.properties.FloatPropertyValue; import com.itextpdf.layout.properties.OverflowPropertyValue; import com.itextpdf.layout.properties.OverflowWrapPropertyValue; @@ -796,7 +797,7 @@ public void nbspCannotBeFitAndIsTheOnlySymbolTest() throws IOException, Interrup @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void nbspCannotBeFitAndMakesTheFirstChunkTest() throws IOException, InterruptedException { String outFileName = destinationFolder + "nbspCannotBeFitAndMakesTheFirstChunkTest.pdf"; @@ -820,7 +821,7 @@ public void nbspCannotBeFitAndMakesTheFirstChunkTest() throws IOException, Inter @Test @LogMessages(messages = { - @LogMessage(messageTemplate = IoLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) + @LogMessage(messageTemplate = LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA) }) public void nbspCannotBeFitAndIsTheFirstSymbolOfChunkTest() throws IOException, InterruptedException { String outFileName = destinationFolder + "nbspCannotBeFitAndIsTheFirstSymbolOfChunkTest.pdf"; diff --git a/layout/src/test/resources/com/itextpdf/layout/EmptyNestedTableTest/cmp_emptyNestedTableTest.pdf b/layout/src/test/resources/com/itextpdf/layout/EmptyNestedTableTest/cmp_emptyNestedTableTest.pdf index 9d07aec78b..887435da5c 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/EmptyNestedTableTest/cmp_emptyNestedTableTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/EmptyNestedTableTest/cmp_emptyNestedTableTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyForcedPlacementTest1.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyForcedPlacementTest1.pdf index 6433e4b0db..042252d7e3 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyForcedPlacementTest1.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyForcedPlacementTest1.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyForcedPlacementTest2.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyForcedPlacementTest2.pdf index de7b2be2f9..0bc363bb72 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyForcedPlacementTest2.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyForcedPlacementTest2.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyForcedPlacementTest3.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyForcedPlacementTest3.pdf index 34af172817..01d22302de 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyForcedPlacementTest3.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyForcedPlacementTest3.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyForcedPlacementTest4.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyForcedPlacementTest4.pdf index ed87943b7b..2ef59978de 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyForcedPlacementTest4.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyForcedPlacementTest4.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyTest1.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyTest1.pdf index 442f93aa95..de4f81ee06 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyTest1.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyTest1.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyTest2.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyTest2.pdf index 92cd0227ea..2af7ceda58 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyTest2.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyTest2.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyTest3.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyTest3.pdf index c39b787d29..e643274301 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyTest3.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyTest3.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyTest4.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyTest4.pdf index 30f613f4e4..0dd04c4780 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyTest4.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitHorizontallyTest4.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitVerticallyTest1.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitVerticallyTest1.pdf index 71b7f3801c..d59a071d41 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitVerticallyTest1.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitVerticallyTest1.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitVerticallyTest2.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitVerticallyTest2.pdf index 29247c254b..3803bba00d 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitVerticallyTest2.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitVerticallyTest2.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitVerticallyTest3.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitVerticallyTest3.pdf index 054876c91b..15314eb081 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitVerticallyTest3.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitVerticallyTest3.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitVerticallyTest4.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitVerticallyTest4.pdf index e1d47f1d66..8dc598a4b5 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitVerticallyTest4.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenDontFitVerticallyTest4.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenFitContainerDoesNotFitVerticallyTest1.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenFitContainerDoesNotFitVerticallyTest1.pdf index aa9731177c..2cad3513da 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenFitContainerDoesNotFitVerticallyTest1.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenFitContainerDoesNotFitVerticallyTest1.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenFitContainerDoesNotFitVerticallyTest2.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenFitContainerDoesNotFitVerticallyTest2.pdf index c3895484b0..3bde7daba6 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenFitContainerDoesNotFitVerticallyTest2.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenFitContainerDoesNotFitVerticallyTest2.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenFitContainerDoesNotFitVerticallyTest3.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenFitContainerDoesNotFitVerticallyTest3.pdf index f5f7dd41bf..1971dea622 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenFitContainerDoesNotFitVerticallyTest3.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenFitContainerDoesNotFitVerticallyTest3.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenFitContainerDoesNotFitVerticallyTest4.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenFitContainerDoesNotFitVerticallyTest4.pdf index adcad83c4a..726c025927 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenFitContainerDoesNotFitVerticallyTest4.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenFitContainerDoesNotFitVerticallyTest4.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenTest1.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenTest1.pdf index 9246d4d542..f1f464b4f5 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenTest1.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenTest1.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenTest2.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenTest2.pdf index fa02204b6d..e33d3bc257 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenTest2.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenTest2.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenTest3.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenTest3.pdf index ab5d595127..859a251f75 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenTest3.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenTest3.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenTest4.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenTest4.pdf index 4e990260e5..65d47183ec 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenTest4.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenTest4.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexBasisTest1.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexBasisTest1.pdf index cdab23c984..81ce514d92 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexBasisTest1.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexBasisTest1.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexBasisTest2.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexBasisTest2.pdf index 769ccfaddf..443cc92800 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexBasisTest2.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexBasisTest2.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexBasisTest3.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexBasisTest3.pdf index 8da940fb87..f82e89bd3a 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexBasisTest3.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexBasisTest3.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexBasisTest4.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexBasisTest4.pdf index 2bc993a7f4..e277612cb7 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexBasisTest4.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexBasisTest4.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexShrinkTest1.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexShrinkTest1.pdf index 465e26726b..f3bae2ecab 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexShrinkTest1.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexShrinkTest1.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexShrinkTest2.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexShrinkTest2.pdf index 71319b2856..faf6e00d91 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexShrinkTest2.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexShrinkTest2.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexShrinkTest3.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexShrinkTest3.pdf index 1bd11f9750..fcb70c18f4 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexShrinkTest3.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexShrinkTest3.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexShrinkTest4.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexShrinkTest4.pdf index 9ed462637f..965c8e4e1e 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexShrinkTest4.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithFlexShrinkTest4.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithGrowTest1.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithGrowTest1.pdf index bbad35002d..4af31b7ea5 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithGrowTest1.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithGrowTest1.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithGrowTest2.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithGrowTest2.pdf index 8b605caef8..881c0578a8 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithGrowTest2.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithGrowTest2.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithGrowTest3.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithGrowTest3.pdf index c1acf33f57..d1a9f11bb5 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithGrowTest3.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithGrowTest3.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithGrowTest4.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithGrowTest4.pdf index 924e6dbd8d..a99f61dfe2 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithGrowTest4.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerDifferentChildrenWithGrowTest4.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerFillAvailableAreaTest1.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerFillAvailableAreaTest1.pdf index 91d15efd48..63db174c7b 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerFillAvailableAreaTest1.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerFillAvailableAreaTest1.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerFillAvailableAreaTest2.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerFillAvailableAreaTest2.pdf index c795158290..c43cde8298 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerFillAvailableAreaTest2.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerFillAvailableAreaTest2.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerFillAvailableAreaTest3.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerFillAvailableAreaTest3.pdf index cf476b2cbb..b1eef8d472 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerFillAvailableAreaTest3.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerFillAvailableAreaTest3.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerFillAvailableAreaTest4.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerFillAvailableAreaTest4.pdf index a17093196c..eeecc79b5d 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerFillAvailableAreaTest4.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerFillAvailableAreaTest4.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerHeightClippedTest1.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerHeightClippedTest1.pdf index aed7d967f2..ccf82a1e8d 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerHeightClippedTest1.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerHeightClippedTest1.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerHeightClippedTest2.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerHeightClippedTest2.pdf index 2358c5dd1b..ac105033fd 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerHeightClippedTest2.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerHeightClippedTest2.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerHeightClippedTest3.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerHeightClippedTest3.pdf index ae07dea7d0..df5ed37120 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerHeightClippedTest3.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerHeightClippedTest3.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerHeightClippedTest4.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerHeightClippedTest4.pdf index 84cd397ff0..af8b0977aa 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerHeightClippedTest4.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerHeightClippedTest4.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerRotationAngleTest1.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerRotationAngleTest1.pdf index d3c39d840e..74d39bdb8d 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerRotationAngleTest1.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerRotationAngleTest1.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerRotationAngleTest2.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerRotationAngleTest2.pdf index 7ab236ba29..500ea6f151 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerRotationAngleTest2.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerRotationAngleTest2.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerRotationAngleTest3.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerRotationAngleTest3.pdf index f2d4c5a8fc..54cf9e91ba 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerRotationAngleTest3.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerRotationAngleTest3.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerRotationAngleTest4.pdf b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerRotationAngleTest4.pdf index f206ec8d9b..4b9f67d3e0 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerRotationAngleTest4.pdf and b/layout/src/test/resources/com/itextpdf/layout/FlexContainerTest/cmp_flexContainerRotationAngleTest4.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_inlineBlocksAndFloatsWithTextAlignmentTest04.pdf b/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_inlineBlocksAndFloatsWithTextAlignmentTest04.pdf index ef03c98eec..c503d33aa6 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_inlineBlocksAndFloatsWithTextAlignmentTest04.pdf and b/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_inlineBlocksAndFloatsWithTextAlignmentTest04.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_tableWithAlignmentBetweenFloats.pdf b/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_tableWithAlignmentBetweenFloats.pdf index 4390e17e46..bc5b89d6fd 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_tableWithAlignmentBetweenFloats.pdf and b/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_tableWithAlignmentBetweenFloats.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_tableWithAlignmentNextToLeftFloat.pdf b/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_tableWithAlignmentNextToLeftFloat.pdf index c17eb72fbd..b1bb9adf20 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_tableWithAlignmentNextToLeftFloat.pdf and b/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_tableWithAlignmentNextToLeftFloat.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_tableWithAlignmentNextToRightFloat.pdf b/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_tableWithAlignmentNextToRightFloat.pdf index 9e4e873fe5..fb0a1a9b32 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_tableWithAlignmentNextToRightFloat.pdf and b/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_tableWithAlignmentNextToRightFloat.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_tableWithBigLeftMarginAfterFloat.pdf b/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_tableWithBigLeftMarginAfterFloat.pdf index 604947dd89..b2f027fb77 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_tableWithBigLeftMarginAfterFloat.pdf and b/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_tableWithBigLeftMarginAfterFloat.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_tableWithBigRightMarginAfterFloat.pdf b/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_tableWithBigRightMarginAfterFloat.pdf index e986019a55..4c078379d9 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_tableWithBigRightMarginAfterFloat.pdf and b/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_tableWithBigRightMarginAfterFloat.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_tableWithSideMarginsBetweenFloat.pdf b/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_tableWithSideMarginsBetweenFloat.pdf index 49789d9390..1019787424 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_tableWithSideMarginsBetweenFloat.pdf and b/layout/src/test/resources/com/itextpdf/layout/FloatAndAlignmentTest/cmp_tableWithSideMarginsBetweenFloat.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FloatTest/cmp_floatFixedHeightContentNotFit.pdf b/layout/src/test/resources/com/itextpdf/layout/FloatTest/cmp_floatFixedHeightContentNotFit.pdf index c72a5ed103..e903e99410 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FloatTest/cmp_floatFixedHeightContentNotFit.pdf and b/layout/src/test/resources/com/itextpdf/layout/FloatTest/cmp_floatFixedHeightContentNotFit.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FloatTest/cmp_floatTableTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/FloatTest/cmp_floatTableTest01.pdf index ff35776968..454ce67558 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FloatTest/cmp_floatTableTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/FloatTest/cmp_floatTableTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/FloatTest/cmp_floatingImageInCell.pdf b/layout/src/test/resources/com/itextpdf/layout/FloatTest/cmp_floatingImageInCell.pdf index 8ecbf81b69..7fc8b693e9 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/FloatTest/cmp_floatingImageInCell.pdf and b/layout/src/test/resources/com/itextpdf/layout/FloatTest/cmp_floatingImageInCell.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/ImageTest/cmp_flushOnDrawCheckCircularReferencesTest.pdf b/layout/src/test/resources/com/itextpdf/layout/ImageTest/cmp_flushOnDrawCheckCircularReferencesTest.pdf index 2ccdd38889..6deaba1ad0 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/ImageTest/cmp_flushOnDrawCheckCircularReferencesTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/ImageTest/cmp_flushOnDrawCheckCircularReferencesTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/ImageTest/cmp_flushOnDrawTest.pdf b/layout/src/test/resources/com/itextpdf/layout/ImageTest/cmp_flushOnDrawTest.pdf index 13c1e048ae..08a17d3017 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/ImageTest/cmp_flushOnDrawTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/ImageTest/cmp_flushOnDrawTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/ImageTest/cmp_imageInTableTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/ImageTest/cmp_imageInTableTest01.pdf index 28b9709ea1..9c58588792 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/ImageTest/cmp_imageInTableTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/ImageTest/cmp_imageInTableTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/ImageTest/cmp_imageInTableTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/ImageTest/cmp_imageInTableTest02.pdf index d36bf1ad7e..fedfc42cef 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/ImageTest/cmp_imageInTableTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/ImageTest/cmp_imageInTableTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/ImageTest/cmp_imageTest21.pdf b/layout/src/test/resources/com/itextpdf/layout/ImageTest/cmp_imageTest21.pdf index 4809b7ac89..810d14ca21 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/ImageTest/cmp_imageTest21.pdf and b/layout/src/test/resources/com/itextpdf/layout/ImageTest/cmp_imageTest21.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/ImageTest/cmp_precisionTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/ImageTest/cmp_precisionTest01.pdf index d9e5b3e3fa..07a7f602f0 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/ImageTest/cmp_precisionTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/ImageTest/cmp_precisionTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/InlineBlockTest/cmp_inlineTableTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/InlineBlockTest/cmp_inlineTableTest01.pdf index fab95755d6..1125e6db17 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/InlineBlockTest/cmp_inlineTableTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/InlineBlockTest/cmp_inlineTableTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/KeepTogetherTest/cmp_narrowPageTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/KeepTogetherTest/cmp_narrowPageTest01.pdf index 94ee750ad3..c24199459d 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/KeepTogetherTest/cmp_narrowPageTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/KeepTogetherTest/cmp_narrowPageTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/KeepTogetherTest/cmp_smallFloatInsideKeptTogetherTableTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/KeepTogetherTest/cmp_smallFloatInsideKeptTogetherTableTest01.pdf index 49c8081158..275b6188a3 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/KeepTogetherTest/cmp_smallFloatInsideKeptTogetherTableTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/KeepTogetherTest/cmp_smallFloatInsideKeptTogetherTableTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/KeepTogetherTest/cmp_smallFloatInsideKeptTogetherTableTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/KeepTogetherTest/cmp_smallFloatInsideKeptTogetherTableTest02.pdf index 84307ad03b..b945523c08 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/KeepTogetherTest/cmp_smallFloatInsideKeptTogetherTableTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/KeepTogetherTest/cmp_smallFloatInsideKeptTogetherTableTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/KeepWithNextTest/cmp_keepWithNextTest11.pdf b/layout/src/test/resources/com/itextpdf/layout/KeepWithNextTest/cmp_keepWithNextTest11.pdf index 5c0e984234..c3cf81b207 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/KeepWithNextTest/cmp_keepWithNextTest11.pdf and b/layout/src/test/resources/com/itextpdf/layout/KeepWithNextTest/cmp_keepWithNextTest11.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_flushingLargeTableAfterStartingNewRowTest.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_flushingLargeTableAfterStartingNewRowTest.pdf new file mode 100644 index 0000000000..c2cea4ae49 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_flushingLargeTableAfterStartingNewRowTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeEmptyTableTest.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeEmptyTableTest.pdf index cd65a24ecb..a24283ad79 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeEmptyTableTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeEmptyTableTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeEmptyTableTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeEmptyTableTest02.pdf index 80d1a50969..b7b8640a99 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeEmptyTableTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeEmptyTableTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeEmptyTableTest02Separated.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeEmptyTableTest02Separated.pdf index c9a7092416..304fc4d695 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeEmptyTableTest02Separated.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeEmptyTableTest02Separated.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableCollapsingSplitTest.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableCollapsingSplitTest.pdf index 6a1cfca592..1a9a39802b 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableCollapsingSplitTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableCollapsingSplitTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableFooterNotFitTest.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableFooterNotFitTest.pdf index 34dac054c4..6b660567d3 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableFooterNotFitTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableFooterNotFitTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableOnDifferentPages01.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableOnDifferentPages01.pdf index 7913a47f06..a35d201b47 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableOnDifferentPages01.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableOnDifferentPages01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableOnDifferentPages01A.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableOnDifferentPages01A.pdf index f128a19fd0..20494ef2d1 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableOnDifferentPages01A.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableOnDifferentPages01A.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableSplitFooter2ATest.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableSplitFooter2ATest.pdf new file mode 100644 index 0000000000..ea4a778da8 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableSplitFooter2ATest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableSplitFooter2BTest.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableSplitFooter2BTest.pdf new file mode 100644 index 0000000000..be5f2a316d Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableSplitFooter2BTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableSplitFooter2Test.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableSplitFooter2Test.pdf index 259e3a5ae9..660d254bbd 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableSplitFooter2Test.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableSplitFooter2Test.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableSplitFooterTest.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableSplitFooterTest.pdf index f85279c846..b4823afc13 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableSplitFooterTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableSplitFooterTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableSplitTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableSplitTest01.pdf index fa9917b892..5e8113aefa 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableSplitTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableSplitTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableTest01.pdf index 585a559afc..02efb799ca 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableTest02.pdf index abd9f17558..9af5d225e0 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithCellBordersSplitTest.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithCellBordersSplitTest.pdf index 4290bf3c9f..35ecd6768b 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithCellBordersSplitTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithCellBordersSplitTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithCellBordersSplitTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithCellBordersSplitTest02.pdf new file mode 100644 index 0000000000..a0742f3f31 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithCellBordersSplitTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithCellBordersSplitTest1.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithCellBordersSplitTest1.pdf new file mode 100644 index 0000000000..2399d9ea5b Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithCellBordersSplitTest1.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithCollapsedFooterTest.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithCollapsedFooterTest.pdf new file mode 100644 index 0000000000..d8804a9046 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithCollapsedFooterTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithEmptyLastRowTest.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithEmptyLastRowTest.pdf new file mode 100644 index 0000000000..339d0bd198 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithEmptyLastRowTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01A.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01A.pdf index b7a32aacca..9c8a621a59 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01A.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01A.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01ASeparated.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01ASeparated.pdf index 9d510e01ed..326cd0ea5d 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01ASeparated.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01ASeparated.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01B.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01B.pdf index c3fdb571b4..57caee1a10 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01B.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01B.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01C.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01C.pdf index 80085e23b1..982fd5f2e7 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01C.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01C.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01D.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01D.pdf index b777ce41b4..d85180613a 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01D.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01D.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01DSeparated.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01DSeparated.pdf index 1638cf44dc..f1d5979b22 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01DSeparated.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01DSeparated.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01E.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01E.pdf index 6eab781e1f..04a4e4ca0c 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01E.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01E.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01ESeparated.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01ESeparated.pdf index f2a4d31dfc..50b3080899 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01ESeparated.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest01ESeparated.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest02.pdf index 0e8db507d2..aa2a4d1b27 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest03.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest03.pdf index 7dd5153154..5ba2e95b17 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest03.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest03.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest04.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest04.pdf index ee1287e533..480933d74e 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest04.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithHeaderFooterTest04.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithLayoutResultNothingTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithLayoutResultNothingTest01.pdf index 9cd3107234..75215ff776 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithLayoutResultNothingTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithLayoutResultNothingTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithLayoutResultNothingTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithLayoutResultNothingTest02.pdf index 5f9aec1730..5dccc4ab79 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithLayoutResultNothingTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithLayoutResultNothingTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithLayoutResultNothingTest03.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithLayoutResultNothingTest03.pdf index 0388ec3ca5..3fabf3f00c 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithLayoutResultNothingTest03.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithLayoutResultNothingTest03.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithTableBorderSplitTest.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithTableBorderSplitTest.pdf index 9c05d8c82f..812295deb5 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithTableBorderSplitTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithTableBorderSplitTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithTableBorderSplitTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithTableBorderSplitTest02.pdf new file mode 100644 index 0000000000..12611a48d4 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_largeTableWithTableBorderSplitTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_reuseLargeTableTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_reuseLargeTableTest01.pdf index 12898244c5..eb82afc9c2 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_reuseLargeTableTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_reuseLargeTableTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_simpleLargeTableDifferentCellBottomBorderTest.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_simpleLargeTableDifferentCellBottomBorderTest.pdf new file mode 100644 index 0000000000..2b420fd191 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_simpleLargeTableDifferentCellBottomBorderTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_tableOnDifferentPages01.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_tableOnDifferentPages01.pdf index 7d9052b780..fc0c48dea7 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_tableOnDifferentPages01.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_tableOnDifferentPages01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_tableOnDifferentPages02.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_tableOnDifferentPages02.pdf index a8b9f60e52..841187888c 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_tableOnDifferentPages02.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_tableOnDifferentPages02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_tableWithLayoutResultNothingTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_tableWithLayoutResultNothingTest01.pdf index 098ac419c3..26b112f507 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_tableWithLayoutResultNothingTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/LargeElementTest/cmp_tableWithLayoutResultNothingTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingPdf2Test/cmp_docWithSectInPdf2.pdf b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingPdf2Test/cmp_docWithSectInPdf2.pdf new file mode 100644 index 0000000000..5502c694d3 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingPdf2Test/cmp_docWithSectInPdf2.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingPdf2Test/cmp_simpleDocDefault.pdf b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingPdf2Test/cmp_simpleDocDefault.pdf index e5650f75f2..effd74c361 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingPdf2Test/cmp_simpleDocDefault.pdf and b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingPdf2Test/cmp_simpleDocDefault.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingPdf2Test/cmp_simpleDocExplicitlyOldStdNs.pdf b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingPdf2Test/cmp_simpleDocExplicitlyOldStdNs.pdf index 50abc8aed4..a75a3037be 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingPdf2Test/cmp_simpleDocExplicitlyOldStdNs.pdf and b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingPdf2Test/cmp_simpleDocExplicitlyOldStdNs.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingPdf2Test/cmp_simpleDocNullNsByDefault.pdf b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingPdf2Test/cmp_simpleDocNullNsByDefault.pdf index a6e9beca86..f905bf5693 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingPdf2Test/cmp_simpleDocNullNsByDefault.pdf and b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingPdf2Test/cmp_simpleDocNullNsByDefault.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_artifactTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_artifactTest02.pdf index b403b291e6..ffb7350b59 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_artifactTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_artifactTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_createTaggedVersionOneDotFourTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_createTaggedVersionOneDotFourTest01.pdf index 5ae8f6cbc9..5ac32dd02f 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_createTaggedVersionOneDotFourTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_createTaggedVersionOneDotFourTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_flushingTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_flushingTest02.pdf index 2368064739..0ecadd1a0c 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_flushingTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_flushingTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_flushingTest03.pdf b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_flushingTest03.pdf index 1694164860..3e8de7e0c6 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_flushingTest03.pdf and b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_flushingTest03.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_linkInsideTable.pdf b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_linkInsideTable.pdf index ce0fefd60b..1cd5820c05 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_linkInsideTable.pdf and b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_linkInsideTable.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest01.pdf index 2f614039e8..ddf68a71fe 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest02.pdf index aaf0509f21..47ff205823 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest03.pdf b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest03.pdf index 35e2064986..0383faf185 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest03.pdf and b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest03.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest04.pdf b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest04.pdf index 22f94682ce..3efed496b3 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest04.pdf and b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest04.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest05.pdf b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest05.pdf index c14399d8fa..29fb46813f 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest05.pdf and b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest05.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest06.pdf b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest06.pdf index fd3011b89e..18a0842a8a 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest06.pdf and b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest06.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest07.pdf b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest07.pdf index 38a8849903..26ea200b9a 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest07.pdf and b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest07.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest08.pdf b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest08.pdf index 03c1f7091f..6e93a829a3 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest08.pdf and b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableTest08.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableWithCaption01.pdf b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableWithCaption01.pdf index 768b3a512e..0fbe4eb2e4 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableWithCaption01.pdf and b/layout/src/test/resources/com/itextpdf/layout/LayoutTaggingTest/cmp_tableWithCaption01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LinkTest/cmp_linkInRotatedCell.pdf b/layout/src/test/resources/com/itextpdf/layout/LinkTest/cmp_linkInRotatedCell.pdf index 10129256dd..fe39315cf9 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LinkTest/cmp_linkInRotatedCell.pdf and b/layout/src/test/resources/com/itextpdf/layout/LinkTest/cmp_linkInRotatedCell.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/LinkTest/cmp_tableHeaderLinkTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/LinkTest/cmp_tableHeaderLinkTest01.pdf index 9da53636fa..00c0c2603b 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/LinkTest/cmp_tableHeaderLinkTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/LinkTest/cmp_tableHeaderLinkTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest0.pdf b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest0.pdf new file mode 100644 index 0000000000..43d37ee7c9 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest0.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest1.pdf b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest1.pdf new file mode 100644 index 0000000000..5e7c593c98 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest1.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest10.pdf b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest10.pdf new file mode 100644 index 0000000000..54cf96785d Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest10.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest11.pdf b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest11.pdf new file mode 100644 index 0000000000..b4b8be5e1f Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest11.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest12.pdf b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest12.pdf new file mode 100644 index 0000000000..0ec94f3423 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest12.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest13.pdf b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest13.pdf new file mode 100644 index 0000000000..0f0c91909c Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest13.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest14.pdf b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest14.pdf new file mode 100644 index 0000000000..3e889cb789 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest14.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest15.pdf b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest15.pdf new file mode 100644 index 0000000000..aaf47c6991 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest15.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest2.pdf b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest2.pdf new file mode 100644 index 0000000000..2246ef7a32 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest2.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest3.pdf b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest3.pdf new file mode 100644 index 0000000000..9c28f7e5ef Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest3.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest4.pdf b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest4.pdf new file mode 100644 index 0000000000..511c0134ab Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest4.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest5.pdf b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest5.pdf new file mode 100644 index 0000000000..2221abe1ba Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest5.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest6.pdf b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest6.pdf new file mode 100644 index 0000000000..6705e6137b Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest6.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest7.pdf b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest7.pdf new file mode 100644 index 0000000000..71eeb8da77 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest7.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest8.pdf b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest8.pdf new file mode 100644 index 0000000000..0887988aae Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest8.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest9.pdf b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest9.pdf new file mode 100644 index 0000000000..9c3d074f5c Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/ListItemPositionAlignmentTest/cmp_defaultListItemTest9.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/ListTest/cmp_listNestedInTableTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/ListTest/cmp_listNestedInTableTest01.pdf index 73b058bbaf..ea65a81ec1 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/ListTest/cmp_listNestedInTableTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/ListTest/cmp_listNestedInTableTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/MinWidthTest/cmp_colspanRowspanTableTest.pdf b/layout/src/test/resources/com/itextpdf/layout/MinWidthTest/cmp_colspanRowspanTableTest.pdf index 9fd82d7b10..23691194fc 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/MinWidthTest/cmp_colspanRowspanTableTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/MinWidthTest/cmp_colspanRowspanTableTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/MinWidthTest/cmp_colspanTableTest.pdf b/layout/src/test/resources/com/itextpdf/layout/MinWidthTest/cmp_colspanTableTest.pdf index 575210ed28..8780e15a1d 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/MinWidthTest/cmp_colspanTableTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/MinWidthTest/cmp_colspanTableTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/MinWidthTest/cmp_headerFooterTableTest.pdf b/layout/src/test/resources/com/itextpdf/layout/MinWidthTest/cmp_headerFooterTableTest.pdf index a89fd3d295..93ef085b1f 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/MinWidthTest/cmp_headerFooterTableTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/MinWidthTest/cmp_headerFooterTableTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/MinWidthTest/cmp_simpleTableTest.pdf b/layout/src/test/resources/com/itextpdf/layout/MinWidthTest/cmp_simpleTableTest.pdf index 67cef6597b..d52568eb48 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/MinWidthTest/cmp_simpleTableTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/MinWidthTest/cmp_simpleTableTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_cellElementOpacity01.pdf b/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_cellElementOpacity01.pdf index e075075d23..dae01a9f15 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_cellElementOpacity01.pdf and b/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_cellElementOpacity01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_divElementOpacity01.pdf b/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_divElementOpacity01.pdf index a79ff33c83..e6eb77bb43 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_divElementOpacity01.pdf and b/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_divElementOpacity01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_imageElementOpacity01.pdf b/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_imageElementOpacity01.pdf index d7bfb8c0de..7c662a07d3 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_imageElementOpacity01.pdf and b/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_imageElementOpacity01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_listElementOpacity01.pdf b/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_listElementOpacity01.pdf index 06665bcaaf..f5f552cc4d 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_listElementOpacity01.pdf and b/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_listElementOpacity01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_listItemElementOpacity01.pdf b/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_listItemElementOpacity01.pdf index 4306cb62a6..1895164e32 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_listItemElementOpacity01.pdf and b/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_listItemElementOpacity01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_paraElementOpacity01.pdf b/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_paraElementOpacity01.pdf index 2db405201b..c5c22bf709 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_paraElementOpacity01.pdf and b/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_paraElementOpacity01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_tableElementOpacity01.pdf b/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_tableElementOpacity01.pdf index 2098f3fad3..e358135517 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_tableElementOpacity01.pdf and b/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_tableElementOpacity01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_textElementOpacity01.pdf b/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_textElementOpacity01.pdf index 2a7f91392a..4acd249a73 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_textElementOpacity01.pdf and b/layout/src/test/resources/com/itextpdf/layout/OpacityTest/cmp_textElementOpacity01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/PositioningTest/cmp_relativePositioningTable01Test.pdf b/layout/src/test/resources/com/itextpdf/layout/PositioningTest/cmp_relativePositioningTable01Test.pdf index 4011ce2c2d..3cec641d72 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/PositioningTest/cmp_relativePositioningTable01Test.pdf and b/layout/src/test/resources/com/itextpdf/layout/PositioningTest/cmp_relativePositioningTable01Test.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_cellRotationDependsOnNeighbourCell.pdf b/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_cellRotationDependsOnNeighbourCell.pdf index 4146cf9fd9..9a3f7aa2a4 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_cellRotationDependsOnNeighbourCell.pdf and b/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_cellRotationDependsOnNeighbourCell.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_cellRotationParagraphIsGone.pdf b/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_cellRotationParagraphIsGone.pdf index b4ac465ef0..e7d11457ae 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_cellRotationParagraphIsGone.pdf and b/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_cellRotationParagraphIsGone.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_cellRotationTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_cellRotationTest01.pdf index 55dde5f50b..40545d37c6 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_cellRotationTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_cellRotationTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_cellRotationTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_cellRotationTest02.pdf index 07da12eed9..64dabf8fcf 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_cellRotationTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_cellRotationTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_cellRotationTest03.pdf b/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_cellRotationTest03.pdf index 924749a3c4..c1bb793f7a 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_cellRotationTest03.pdf and b/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_cellRotationTest03.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_rotatedWithAlignmentCellInTable.pdf b/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_rotatedWithAlignmentCellInTable.pdf index 2a38a72838..4b3568f4ca 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_rotatedWithAlignmentCellInTable.pdf and b/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_rotatedWithAlignmentCellInTable.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_tableRotationTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_tableRotationTest02.pdf index 74a9324bb8..2729107b82 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_tableRotationTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_tableRotationTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_tableRotationTest03.pdf b/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_tableRotationTest03.pdf index f69cff1d0a..a52a8ad844 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_tableRotationTest03.pdf and b/layout/src/test/resources/com/itextpdf/layout/RotationTest/cmp_tableRotationTest03.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_borderCollapseTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_borderCollapseTest01.pdf index 5caf271263..6b19bbb4d1 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_borderCollapseTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_borderCollapseTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_borderCollapseTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_borderCollapseTest02.pdf index e9799da592..9e478a8043 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_borderCollapseTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_borderCollapseTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_borderCollapseTest02A.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_borderCollapseTest02A.pdf new file mode 100644 index 0000000000..d955e203ba Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_borderCollapseTest02A.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_borderCollapseTest03.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_borderCollapseTest03.pdf index d645afbeed..3bd09a5dc5 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_borderCollapseTest03.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_borderCollapseTest03.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_bordersWithSpansTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_bordersWithSpansTest01.pdf index 9db374448c..c66d20d23a 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_bordersWithSpansTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_bordersWithSpansTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_bordersWithSpansTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_bordersWithSpansTest02.pdf index 7be605cb1c..9b77b24d49 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_bordersWithSpansTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_bordersWithSpansTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_bordersWithSpansTest02A.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_bordersWithSpansTest02A.pdf new file mode 100644 index 0000000000..c8630e7eb4 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_bordersWithSpansTest02A.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_bordersWithSpansTest03.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_bordersWithSpansTest03.pdf index cdbc577a45..e9fe005863 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_bordersWithSpansTest03.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_bordersWithSpansTest03.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_cellBorderPriorityTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_cellBorderPriorityTest.pdf new file mode 100644 index 0000000000..ac7d3ed4e5 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_cellBorderPriorityTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_cellBorderPriorityTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_cellBorderPriorityTest02.pdf new file mode 100644 index 0000000000..87aca2b34f Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_cellBorderPriorityTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_cellsBorderPriorityTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_cellsBorderPriorityTest.pdf new file mode 100644 index 0000000000..275bbad566 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_cellsBorderPriorityTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_equalBordersSameInstancesTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_equalBordersSameInstancesTest.pdf new file mode 100644 index 0000000000..1789c1c011 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_equalBordersSameInstancesTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_forcedPlacementTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_forcedPlacementTest01.pdf index f7cf0a80a4..a295255268 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_forcedPlacementTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_forcedPlacementTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_headerTopBorderTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_headerTopBorderTest01.pdf index 8a8a10eddc..a2769d521b 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_headerTopBorderTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_headerTopBorderTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_incompleteTableTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_incompleteTableTest01.pdf index 4ac164be55..901de6c325 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_incompleteTableTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_incompleteTableTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_incompleteTableTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_incompleteTableTest02.pdf index 4eeb1b1044..0d73d8c6ab 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_incompleteTableTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_incompleteTableTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_incompleteTableTest03.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_incompleteTableTest03.pdf index 0538f4f365..fd94ffd8bb 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_incompleteTableTest03.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_incompleteTableTest03.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_incompleteTableTest04.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_incompleteTableTest04.pdf index e46a36599c..e9bd3f73b0 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_incompleteTableTest04.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_incompleteTableTest04.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_infiniteLoopTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_infiniteLoopTest01.pdf index 26fc3bac7b..c5b779587f 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_infiniteLoopTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_infiniteLoopTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_simpleBorderTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_simpleBorderTest02.pdf index f76076ee1d..f7aa86c1e1 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_simpleBorderTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_simpleBorderTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_simpleBorderTest03.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_simpleBorderTest03.pdf index 94c4e1250a..e706c4a971 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_simpleBorderTest03.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_simpleBorderTest03.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_simpleBorderTest04.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_simpleBorderTest04.pdf index 164d578133..b6a537ca1b 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_simpleBorderTest04.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_simpleBorderTest04.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest01.pdf index 662d51b366..16418bc046 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest02.pdf index e1ff75867a..b9bb2bbf0b 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest03.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest03.pdf index 4d262c85cc..11d8b19188 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest03.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest03.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest04.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest04.pdf index e7e06f42e6..2c859c743f 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest04.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest04.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest05.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest05.pdf index ce7bf3fa0c..85be981042 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest05.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest05.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest06.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest06.pdf index e4cb3a4ff3..7d4ddd5d5e 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest06.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest06.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest07.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest07.pdf index 71f6b0d337..3ad43ef528 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest07.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest07.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest08.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest08.pdf index 631aff13f1..f8479de66f 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest08.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest08.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest09.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest09.pdf index 9ea78eb553..92d2f6cd05 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest09.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest09.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest10.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest10.pdf index b6d9907e8d..f32c3ae9f4 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest10.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest10.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest10A.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest10A.pdf index 70a6a9d811..d2e59c210e 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest10A.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest10A.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest10C.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest10C.pdf index e0551b05d5..a42908b139 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest10C.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitCellsTest10C.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitRowspanKeepTogetherTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitRowspanKeepTogetherTest.pdf index 9ec8f48c11..3119f20d7a 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitRowspanKeepTogetherTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_splitRowspanKeepTogetherTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableAndCellBordersCollapseTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableAndCellBordersCollapseTest01.pdf new file mode 100644 index 0000000000..6f66ced325 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableAndCellBordersCollapseTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableBorderPriorityTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableBorderPriorityTest.pdf new file mode 100644 index 0000000000..96e899f581 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableBorderPriorityTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest01.pdf index 0615601144..de9c93accf 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest02.pdf index 0a2c0a2c55..a92c4db9a5 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest02A.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest02A.pdf new file mode 100644 index 0000000000..15a035509a Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest02A.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest03.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest03.pdf index 6c53d9d0f3..5485abcb6d 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest03.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest03.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest04.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest04.pdf index 5b7aabfca6..c09c783862 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest04.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest04.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest05.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest05.pdf index ddbe1dcbfd..53030025c1 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest05.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest05.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest06.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest06.pdf index 7b8ffc2457..b768ddc952 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest06.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest06.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest06A.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest06A.pdf index 12da86bc54..eabf896210 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest06A.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest06A.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest06B.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest06B.pdf index 7d3f43a83b..73c5633afb 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest06B.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest06B.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest07.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest07.pdf index 7b0162a70e..93c59cc6e6 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest07.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest07.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest08.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest08.pdf index 9437959c7d..93ebeca0d3 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest08.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest08.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest09.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest09.pdf index e9f4e58d1f..cbc4968eda 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest09.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest09.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest10.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest10.pdf index f213cb0dd6..eb294a6c6c 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest10.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest10.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest11.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest11.pdf index 168ccd323c..5da71dc8e8 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest11.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest11.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest11A.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest11A.pdf index 340c7da33a..805c3de7cb 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest11A.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest11A.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest12.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest12.pdf index a143646635..719e556b23 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest12.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest12.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest14.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest14.pdf index 49e937f42f..dd7a532721 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest14.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest14.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest15.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest15.pdf index c1f10f3bed..c579d8259a 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest15.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest15.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest16.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest16.pdf index 5a43a2acaa..f9338e6d88 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest16.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest16.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest17.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest17.pdf index 82beb8dba9..fca2132860 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest17.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest17.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest18.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest18.pdf index ddbf2c3dfc..3396582df5 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest18.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest18.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest19.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest19.pdf index 1380c253f4..6b6deaa755 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest19.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest19.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest20.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest20.pdf index 73bbaa7796..f023631abf 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest20.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_tableWithHeaderFooterTest20.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_verticalBordersInfluenceHorizontalTopAndbottomBordersTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_verticalBordersInfluenceHorizontalTopAndbottomBordersTest.pdf new file mode 100644 index 0000000000..d9a02ea36c Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_verticalBordersInfluenceHorizontalTopAndbottomBordersTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_verticalMiddleBorderTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_verticalMiddleBorderTest.pdf new file mode 100644 index 0000000000..68984b1c16 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_verticalMiddleBorderTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_wideBorderTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_wideBorderTest01.pdf index d793c9c9ca..68fd1f888f 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_wideBorderTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_wideBorderTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_wideBorderTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_wideBorderTest02.pdf index e633b32565..d91111d3d9 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_wideBorderTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_wideBorderTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_wideBorderTest03.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_wideBorderTest03.pdf index 6323e96265..c191423cea 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_wideBorderTest03.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_wideBorderTest03.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_wideBorderTest04.pdf b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_wideBorderTest04.pdf index 0a2167aa34..987773b28f 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_wideBorderTest04.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableBorderTest/cmp_wideBorderTest04.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_autoLayoutTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_autoLayoutTest01.pdf index 40c147aca3..b8ae76e83e 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_autoLayoutTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_autoLayoutTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_autoLayoutTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_autoLayoutTest02.pdf index 3efa92dd44..e908f6dfad 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_autoLayoutTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_autoLayoutTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_autoLayoutTest03.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_autoLayoutTest03.pdf index cf868ebbe9..a6b37a2afe 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_autoLayoutTest03.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_autoLayoutTest03.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigFooterTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigFooterTest01.pdf index fb3978a4f4..85d63e45d6 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigFooterTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigFooterTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigFooterTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigFooterTest02.pdf index 608c60af50..2c41d1cf94 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigFooterTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigFooterTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowSpanTooFarFullTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowSpanTooFarFullTest.pdf index f54e8ecce5..1f0b30bb6f 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowSpanTooFarFullTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowSpanTooFarFullTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowSpanTooFarNothingTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowSpanTooFarNothingTest.pdf index 36ad213afa..f21c0bcf7b 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowSpanTooFarNothingTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowSpanTooFarNothingTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowSpanTooFarPartialTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowSpanTooFarPartialTest.pdf index f3f689b39b..c306fae7ec 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowSpanTooFarPartialTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowSpanTooFarPartialTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest01.pdf index 0654067734..1c10578708 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest02.pdf index 29bb30537e..5e74318603 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest03.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest03.pdf index 88bfa68d83..2ed7732853 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest03.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest03.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest04.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest04.pdf index 64203543e0..4b9893e4b8 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest04.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest04.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest05.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest05.pdf index d8eee88973..cb159566d3 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest05.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest05.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest06.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest06.pdf index 16437629fc..71b20a448a 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest06.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest06.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest07.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest07.pdf index c3ad60a6af..d752c39689 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest07.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_bigRowspanTest07.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_captionedTableOfOnePageWithCollapsedBordersTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_captionedTableOfOnePageWithCollapsedBordersTest01.pdf index 14d7c15801..cdc36602cb 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_captionedTableOfOnePageWithCollapsedBordersTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_captionedTableOfOnePageWithCollapsedBordersTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_captionedTableOfOnePageWithSeparatedBordersTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_captionedTableOfOnePageWithSeparatedBordersTest01.pdf index 05a3bca932..2d6370c8c7 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_captionedTableOfOnePageWithSeparatedBordersTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_captionedTableOfOnePageWithSeparatedBordersTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_cellAlignmentAndKeepTogetherTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_cellAlignmentAndKeepTogetherTest01.pdf index a8ff1d9971..12427ffde5 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_cellAlignmentAndKeepTogetherTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_cellAlignmentAndKeepTogetherTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_cellAlignmentAndSplittingTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_cellAlignmentAndSplittingTest01.pdf index 9511649a89..c847b1f86c 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_cellAlignmentAndSplittingTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_cellAlignmentAndSplittingTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_cellWithBigRowspanCompletedRowNotTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_cellWithBigRowspanCompletedRowNotTest.pdf index 89d7d6263b..b1c0a3f4c5 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_cellWithBigRowspanCompletedRowNotTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_cellWithBigRowspanCompletedRowNotTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_cellWithBigRowspanCompletedRowTooTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_cellWithBigRowspanCompletedRowTooTest.pdf index 2ca82492c3..26aea7bb3a 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_cellWithBigRowspanCompletedRowTooTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_cellWithBigRowspanCompletedRowTooTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_cellsWithEdgeCaseLeadingTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_cellsWithEdgeCaseLeadingTest01.pdf index 3901a6207f..d02d9bc7df 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_cellsWithEdgeCaseLeadingTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_cellsWithEdgeCaseLeadingTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_collapseWithNextRowWiderThanWithTableBorderTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_collapseWithNextRowWiderThanWithTableBorderTest.pdf index 13a2c34a25..27151619e7 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_collapseWithNextRowWiderThanWithTableBorderTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_collapseWithNextRowWiderThanWithTableBorderTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_coloredTableWithColoredCellsTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_coloredTableWithColoredCellsTest.pdf new file mode 100644 index 0000000000..3b870fc270 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_coloredTableWithColoredCellsTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_differentPageOrientationTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_differentPageOrientationTest01.pdf index c525d1193d..a02dd95030 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_differentPageOrientationTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_differentPageOrientationTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_emptyTableTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_emptyTableTest01.pdf index e3a8c91f0b..34d5865bb7 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_emptyTableTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_emptyTableTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_emptyTableTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_emptyTableTest02.pdf index 9c1ed91cc3..1ea9be3c34 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_emptyTableTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_emptyTableTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_extendLastRowTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_extendLastRowTest01.pdf index d5397be97c..323a438f92 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_extendLastRowTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_extendLastRowTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_firstRowNotFitBigRowspanTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_firstRowNotFitBigRowspanTest.pdf index 7ce5df406b..21995ba7ec 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_firstRowNotFitBigRowspanTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_firstRowNotFitBigRowspanTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_firstRowPartiallyFitWideBottomBorderTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_firstRowPartiallyFitWideBottomBorderTest.pdf index f94e628cef..cd26c3e5c9 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_firstRowPartiallyFitWideBottomBorderTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_firstRowPartiallyFitWideBottomBorderTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_fixedLayoutTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_fixedLayoutTest01.pdf index 34a255bde7..0117876c6a 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_fixedLayoutTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_fixedLayoutTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_fixedLayoutTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_fixedLayoutTest02.pdf index b7f9496aaa..65b3c9224c 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_fixedLayoutTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_fixedLayoutTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_fixedPositionTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_fixedPositionTest01.pdf index 8284b8114c..4665940a3b 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_fixedPositionTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_fixedPositionTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_imageInTableTest_HA.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_imageInTableTest_HA.pdf index 79a9d6a198..fbb36e5830 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_imageInTableTest_HA.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_imageInTableTest_HA.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_infiniteLoopOnUnfitCellAndBigRowspanTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_infiniteLoopOnUnfitCellAndBigRowspanTest.pdf index a34dd89fb8..af120842b8 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_infiniteLoopOnUnfitCellAndBigRowspanTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_infiniteLoopOnUnfitCellAndBigRowspanTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_inheritHeaderPropsWhileMinMaxWidthCalculations.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_inheritHeaderPropsWhileMinMaxWidthCalculations.pdf index d44ed36c41..1aed552417 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_inheritHeaderPropsWhileMinMaxWidthCalculations.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_inheritHeaderPropsWhileMinMaxWidthCalculations.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_marginPaddingTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_marginPaddingTest01.pdf index e485f90002..0d172817a0 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_marginPaddingTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_marginPaddingTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_nestedTableLostContent.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_nestedTableLostContent.pdf index ad119e769f..6eab98a380 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_nestedTableLostContent.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_nestedTableLostContent.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_nestedTableMinMaxWidthException.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_nestedTableMinMaxWidthException.pdf index 7f7a9b0c92..391aec0e32 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_nestedTableMinMaxWidthException.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_nestedTableMinMaxWidthException.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_nestedTableSkipHeaderFooter.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_nestedTableSkipHeaderFooter.pdf index 268b21db17..b661443aa7 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_nestedTableSkipHeaderFooter.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_nestedTableSkipHeaderFooter.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_nestedTablesCollapseTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_nestedTablesCollapseTest01.pdf index f4069aba4e..e96d2f3858 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_nestedTablesCollapseTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_nestedTablesCollapseTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_nestedTablesWithMarginsTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_nestedTablesWithMarginsTest01.pdf index 45e26857e9..f3828c850f 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_nestedTablesWithMarginsTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_nestedTablesWithMarginsTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_setWidthShouldBeRespectedTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_setWidthShouldBeRespectedTest.pdf new file mode 100644 index 0000000000..490026cbb5 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_setWidthShouldBeRespectedTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_skipFooterTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_skipFooterTest01.pdf index e2b053ae5a..8a465d9628 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_skipFooterTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_skipFooterTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_skipHeaderTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_skipHeaderTest01.pdf index 08ab7df7e9..6b8861793b 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_skipHeaderTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_skipHeaderTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_skipLastFooterAndProcessBigRowspanTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_skipLastFooterAndProcessBigRowspanTest01.pdf index 7ae8e78cee..6d2ab155b2 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_skipLastFooterAndProcessBigRowspanTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_skipLastFooterAndProcessBigRowspanTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_skipLastFooterAndProcessBigRowspanTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_skipLastFooterAndProcessBigRowspanTest02.pdf index 51347bac1d..13ea728832 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_skipLastFooterAndProcessBigRowspanTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_skipLastFooterAndProcessBigRowspanTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_skipLastFooterOnShortPageTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_skipLastFooterOnShortPageTest01.pdf index 35ae9154c3..f7c61811e6 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_skipLastFooterOnShortPageTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_skipLastFooterOnShortPageTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_skipLastRowTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_skipLastRowTest.pdf index 100523db2f..a1840a6c75 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_skipLastRowTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_skipLastRowTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_spacingTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_spacingTest01.pdf index 6ab3f344e2..c2c682f680 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_spacingTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_spacingTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_splitCellWithStyles.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_splitCellWithStyles.pdf index cfd0f23737..6dae2123e5 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_splitCellWithStyles.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_splitCellWithStyles.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_splitTableOnShortPage.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_splitTableOnShortPage.pdf index 7655aef806..583d5f7147 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_splitTableOnShortPage.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_splitTableOnShortPage.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_splitTableWithCaptionTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_splitTableWithCaptionTest01.pdf index 7ad8f3443c..b3dc961516 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_splitTableWithCaptionTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_splitTableWithCaptionTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableBottomBorderWideTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableBottomBorderWideTest.pdf index b1ac609551..09ae116b60 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableBottomBorderWideTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableBottomBorderWideTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableMinMaxWidthTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableMinMaxWidthTest01.pdf index bc384c75a4..c27da2157d 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableMinMaxWidthTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableMinMaxWidthTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableMinMaxWidthTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableMinMaxWidthTest02.pdf index c077ff11cb..56107d72e9 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableMinMaxWidthTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableMinMaxWidthTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableMinMaxWidthTest03.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableMinMaxWidthTest03.pdf index f15cae9d5c..f585b51c02 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableMinMaxWidthTest03.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableMinMaxWidthTest03.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableMinMaxWidthTest04.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableMinMaxWidthTest04.pdf index 244d3cc175..3e88b12147 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableMinMaxWidthTest04.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableMinMaxWidthTest04.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableMinMaxWidthTest05.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableMinMaxWidthTest05.pdf index ae00ee482f..1d45fff0f7 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableMinMaxWidthTest05.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableMinMaxWidthTest05.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableNothingResultTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableNothingResultTest.pdf index 2529cad84c..f97946dd48 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableNothingResultTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableNothingResultTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableSplitTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableSplitTest01.pdf index 9ae7ba69d4..e099f503ac 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableSplitTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableSplitTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableSplitTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableSplitTest02.pdf index eec04f33ba..90208eb2b3 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableSplitTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableSplitTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableSplitTest03.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableSplitTest03.pdf index 52f31faf7b..3d7945f1cd 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableSplitTest03.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableSplitTest03.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableSplitTest04.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableSplitTest04.pdf index fa732ebb69..bf89bbc3a1 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableSplitTest04.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableSplitTest04.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest01.pdf index d7a80231cf..8295b681b5 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest02.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest02.pdf index cd72bf60ae..f886de0508 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest02.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest03.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest03.pdf index fa1f3c5a99..c352b196e1 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest03.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest03.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest04.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest04.pdf index d3d7df6e3c..b0f159abd0 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest04.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest04.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest05.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest05.pdf index 852057af5c..7c0b0e44fd 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest05.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest05.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest06.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest06.pdf index a5546a5bc4..85f9709238 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest06.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest06.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest07.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest07.pdf index adcd426a10..99fb21c294 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest07.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest07.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest08.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest08.pdf index fbd2780b0b..1b61346ff3 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest08.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest08.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest09.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest09.pdf index 7a3c9ed860..8abdc66f81 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest09.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest09.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest10.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest10.pdf index b905e7a9e0..2d9abfd16e 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest10.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest10.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest11.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest11.pdf index 76821998db..ed0576b605 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest11.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest11.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest12.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest12.pdf index 3aa99aad0c..20eaa09121 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest12.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest12.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest13.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest13.pdf index 506aa9275a..91b9416817 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest13.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest13.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest14.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest14.pdf index 35450dddcf..207c621b28 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest14.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest14.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest15.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest15.pdf index 52624b1c85..46fab4663a 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest15.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest15.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest16.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest16.pdf index 2498df4e2b..19e442520b 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest16.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest16.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest17.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest17.pdf index 02a8702a0d..6c0a69a826 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest17.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest17.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest18.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest18.pdf index 20301f0472..2fa3db33fa 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest18.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest18.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest19.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest19.pdf index 2fbbc6b8df..6aec78ba92 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest19.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest19.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest20.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest20.pdf index a02eab6ae2..469017cc96 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest20.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest20.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest21.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest21.pdf index 845c0091a4..5a60b83fb1 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest21.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest21.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest22.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest22.pdf index 6194807f83..32bc02e3a4 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest22.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest22.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest23.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest23.pdf index 8dc560fdcd..d819bc9b75 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest23.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableTest23.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithAlternatingRowsTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithAlternatingRowsTest.pdf new file mode 100644 index 0000000000..452bb1c533 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithAlternatingRowsTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithCollapsedBordersAndFooterTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithCollapsedBordersAndFooterTest.pdf new file mode 100644 index 0000000000..f99ba31691 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithCollapsedBordersAndFooterTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithCollapsedBordersTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithCollapsedBordersTest.pdf new file mode 100644 index 0000000000..4c4e684a0a Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithCollapsedBordersTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithCustomRendererTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithCustomRendererTest01.pdf index 2611f28100..9295955ca5 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithCustomRendererTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithCustomRendererTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithDifferentStylesOfCollapsedBordersTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithDifferentStylesOfCollapsedBordersTest.pdf index e628a4f139..21b551f27f 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithDifferentStylesOfCollapsedBordersTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithDifferentStylesOfCollapsedBordersTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithDocumentRelayoutTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithDocumentRelayoutTest.pdf index b61bc6b4e5..7410b22cae 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithDocumentRelayoutTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithDocumentRelayoutTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithEmptyLastRowTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithEmptyLastRowTest.pdf new file mode 100644 index 0000000000..d817354f96 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithEmptyLastRowTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithEmptyRowAfterJustOneCellTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithEmptyRowAfterJustOneCellTest.pdf new file mode 100644 index 0000000000..602d5bf1db Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithEmptyRowAfterJustOneCellTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithEmptyRowsAndSeparatedBordersTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithEmptyRowsAndSeparatedBordersTest.pdf new file mode 100644 index 0000000000..a0fca5197c Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithEmptyRowsAndSeparatedBordersTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithEmptyRowsBetweenFullRowsTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithEmptyRowsBetweenFullRowsTest.pdf new file mode 100644 index 0000000000..d17b88bf62 Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithEmptyRowsBetweenFullRowsTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithHeaderInTheBottomOfPageTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithHeaderInTheBottomOfPageTest.pdf index 4e394cbf83..da75f242c1 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithHeaderInTheBottomOfPageTest.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithHeaderInTheBottomOfPageTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithIncompleteFooter.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithIncompleteFooter.pdf index 16e0b2fd61..21ef4fc822 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithIncompleteFooter.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithIncompleteFooter.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithKeepTogetherOnCells.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithKeepTogetherOnCells.pdf index 9a8cff18b2..f3a7da0de4 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithKeepTogetherOnCells.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithKeepTogetherOnCells.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithSetHeightProperties01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithSetHeightProperties01.pdf index 2bfa5d6274..929845275c 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithSetHeightProperties01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithSetHeightProperties01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithSetHeightProperties02.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithSetHeightProperties02.pdf index ab4ed7fa52..7c2fcf575d 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithSetHeightProperties02.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithSetHeightProperties02.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithSetHeightProperties03.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithSetHeightProperties03.pdf index 9069fe3ec2..7d55d22646 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithSetHeightProperties03.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_tableWithSetHeightProperties03.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_toLargeElementInTableTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_toLargeElementInTableTest01.pdf index 04d421e28e..9fb44e3d94 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_toLargeElementInTableTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_toLargeElementInTableTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_toLargeElementWithKeepTogetherPropertyInTableTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_toLargeElementWithKeepTogetherPropertyInTableTest01.pdf index 60a02c1e6a..fd1a9b7c85 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_toLargeElementWithKeepTogetherPropertyInTableTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_toLargeElementWithKeepTogetherPropertyInTableTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_wideCaptionTest01.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_wideCaptionTest01.pdf index 85f9a39497..4a86990d9b 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_wideCaptionTest01.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_wideCaptionTest01.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_wideFirstCellBorderDoesntAffectSecondCellTest.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_wideFirstCellBorderDoesntAffectSecondCellTest.pdf new file mode 100644 index 0000000000..3ad581366b Binary files /dev/null and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_wideFirstCellBorderDoesntAffectSecondCellTest.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_widthInPercentShouldBeResetAfterOverflow.pdf b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_widthInPercentShouldBeResetAfterOverflow.pdf index 2bbb171f90..493735b4c2 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_widthInPercentShouldBeResetAfterOverflow.pdf and b/layout/src/test/resources/com/itextpdf/layout/TableTest/cmp_widthInPercentShouldBeResetAfterOverflow.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TabsTest/cmp_tablesAndTabInsideOfParagraph.pdf b/layout/src/test/resources/com/itextpdf/layout/TabsTest/cmp_tablesAndTabInsideOfParagraph.pdf index 45ccc50dc0..a4fdb39fa8 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TabsTest/cmp_tablesAndTabInsideOfParagraph.pdf and b/layout/src/test/resources/com/itextpdf/layout/TabsTest/cmp_tablesAndTabInsideOfParagraph.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TextRendererIntegrationTest/cmp_minMaxWidthWordSplitAcrossMultipleTextRenderers.pdf b/layout/src/test/resources/com/itextpdf/layout/TextRendererIntegrationTest/cmp_minMaxWidthWordSplitAcrossMultipleTextRenderers.pdf index 767b3d0898..8a1afa8f6d 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TextRendererIntegrationTest/cmp_minMaxWidthWordSplitAcrossMultipleTextRenderers.pdf and b/layout/src/test/resources/com/itextpdf/layout/TextRendererIntegrationTest/cmp_minMaxWidthWordSplitAcrossMultipleTextRenderers.pdf differ diff --git a/layout/src/test/resources/com/itextpdf/layout/TextRendererIntegrationTest/cmp_minWidthForSpanningWordFollowedByFloat.pdf b/layout/src/test/resources/com/itextpdf/layout/TextRendererIntegrationTest/cmp_minWidthForSpanningWordFollowedByFloat.pdf index e0d5796650..8348c5f0e7 100644 Binary files a/layout/src/test/resources/com/itextpdf/layout/TextRendererIntegrationTest/cmp_minWidthForSpanningWordFollowedByFloat.pdf and b/layout/src/test/resources/com/itextpdf/layout/TextRendererIntegrationTest/cmp_minWidthForSpanningWordFollowedByFloat.pdf differ diff --git a/pdfa/pom.xml b/pdfa/pom.xml index a3ce1078bf..0da2bbc6d1 100644 --- a/pdfa/pom.xml +++ b/pdfa/pom.xml @@ -4,7 +4,7 @@ com.itextpdf root - 7.2.0 + 7.2.1 pdfa iText 7 - pdfa diff --git a/pdfa/src/main/java/com/itextpdf/pdfa/checker/PdfA2Checker.java b/pdfa/src/main/java/com/itextpdf/pdfa/checker/PdfA2Checker.java index cd880d04ab..7b2e44dd74 100644 --- a/pdfa/src/main/java/com/itextpdf/pdfa/checker/PdfA2Checker.java +++ b/pdfa/src/main/java/com/itextpdf/pdfa/checker/PdfA2Checker.java @@ -55,6 +55,7 @@ This file is part of the iText (R) project. import com.itextpdf.kernel.font.PdfType3Font; import com.itextpdf.kernel.font.Type3Glyph; import com.itextpdf.kernel.geom.Rectangle; +import com.itextpdf.kernel.pdf.PdfAConformanceLevel; import com.itextpdf.kernel.pdf.PdfArray; import com.itextpdf.kernel.pdf.PdfBoolean; import com.itextpdf.kernel.pdf.PdfDictionary; @@ -73,7 +74,6 @@ This file is part of the iText (R) project. import com.itextpdf.kernel.pdf.extgstate.PdfExtGState; import com.itextpdf.pdfa.exceptions.PdfAConformanceException; import com.itextpdf.pdfa.logs.PdfAConformanceLogMessageConstant; -import com.itextpdf.kernel.pdf.PdfAConformanceLevel; import java.util.Collections; import org.slf4j.Logger; @@ -188,11 +188,7 @@ public void checkColor(Color color, PdfDictionary currentColorSpaces, Boolean fi PdfObject colorSpace = shadingDictionary.get(PdfName.ColorSpace); checkColorSpace(PdfColorSpace.makeColorSpace(colorSpace), currentColorSpaces, true, true); final PdfDictionary extGStateDict = ((PdfDictionary) pattern.getPdfObject()).getAsDictionary(PdfName.ExtGState); - CanvasGraphicsState gState = new CanvasGraphicsState() { - { - updateFromExtGState(new PdfExtGState(extGStateDict)); - } - }; + CanvasGraphicsState gState = new UpdateCanvasGraphicsState(extGStateDict); checkExtGState(gState, contentStream); } else if (pattern instanceof PdfPattern.Tiling) { checkContentStream((PdfStream) pattern.getPdfObject()); @@ -1084,4 +1080,10 @@ private void checkType3FontGlyphs(PdfType3Font font, PdfStream contentStream) { } } } + + private static final class UpdateCanvasGraphicsState extends CanvasGraphicsState { + public UpdateCanvasGraphicsState(PdfDictionary extGStateDict) { + updateFromExtGState(new PdfExtGState(extGStateDict)); + } + } } diff --git a/pdfa/src/test/java/com/itextpdf/pdfa/PdfATransparencyCheckTest.java b/pdfa/src/test/java/com/itextpdf/pdfa/PdfATransparencyCheckTest.java index 8f73d0d910..ae35164a20 100644 --- a/pdfa/src/test/java/com/itextpdf/pdfa/PdfATransparencyCheckTest.java +++ b/pdfa/src/test/java/com/itextpdf/pdfa/PdfATransparencyCheckTest.java @@ -204,14 +204,14 @@ public void nestedXObjectWithTransparencyTest() { PdfCanvas canvas = new PdfCanvas(form, pdfDocument); canvas.rectangle(10, 10, 30, 30); canvas.stroke(); - canvas.addXObject(form1, 0, 0); + canvas.addXObjectAt(form1, 0, 0); canvas.release(); form.flush(); //Create page1 and add forms to the page. PdfPage page1 = pdfDocument.addNewPage(); canvas = new PdfCanvas(page1); - canvas.addXObject(form, 0, 0); + canvas.addXObjectAt(form, 0, 0); canvas.release(); Exception e = Assert.assertThrows(PdfAConformanceException.class, () -> pdfDocument.close()); diff --git a/pdfa/src/test/java/com/itextpdf/pdfa/checker/PdfA2CheckerTest.java b/pdfa/src/test/java/com/itextpdf/pdfa/checker/PdfA2CheckerTest.java index 6cd873ca17..cd414f07c7 100644 --- a/pdfa/src/test/java/com/itextpdf/pdfa/checker/PdfA2CheckerTest.java +++ b/pdfa/src/test/java/com/itextpdf/pdfa/checker/PdfA2CheckerTest.java @@ -42,14 +42,18 @@ This file is part of the iText (R) project. */ package com.itextpdf.pdfa.checker; +import com.itextpdf.kernel.colors.Color; +import com.itextpdf.kernel.colors.PatternColor; import com.itextpdf.kernel.pdf.PdfAConformanceLevel; import com.itextpdf.kernel.pdf.PdfArray; import com.itextpdf.kernel.pdf.PdfDictionary; import com.itextpdf.kernel.pdf.PdfName; import com.itextpdf.kernel.pdf.PdfString; import com.itextpdf.kernel.pdf.colorspace.PdfDeviceCs; +import com.itextpdf.kernel.pdf.colorspace.PdfPattern; import com.itextpdf.kernel.pdf.colorspace.PdfSpecialCs; import com.itextpdf.pdfa.exceptions.PdfAConformanceException; +import com.itextpdf.test.AssertUtil; import com.itextpdf.test.ExtendedITextTest; import com.itextpdf.test.annotations.type.UnitTest; @@ -362,4 +366,21 @@ public void deviceNColorspaceNoAttributesDictionary() { currentColorSpaces, true, false) ); } + + @Test + public void checkColorShadingTest() { + PdfDictionary patternDict = new PdfDictionary(); + patternDict.put(PdfName.ExtGState, new PdfDictionary()); + PdfPattern.Shading pattern = new PdfPattern.Shading(patternDict); + + PdfDictionary dictionary = new PdfDictionary(); + dictionary.put(PdfName.ColorSpace, PdfName.DeviceCMYK); + pattern.setShading(dictionary); + + Color color = new PatternColor(pattern); + + AssertUtil.doesNotThrow(() -> { + pdfA2Checker.checkColor(color, new PdfDictionary(), true, null); + }); + } } diff --git a/pdftest/pom.xml b/pdftest/pom.xml index 960c978f69..37affe90d1 100644 --- a/pdftest/pom.xml +++ b/pdftest/pom.xml @@ -4,7 +4,7 @@ com.itextpdf root - 7.2.0 + 7.2.1 pdftest iText 7 - pdftest diff --git a/pom.xml b/pom.xml index 190d5b47ea..dee9a87dfc 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.itextpdf root - 7.2.0 + 7.2.1 pom iText 7 A Free Java-PDF library @@ -72,7 +72,7 @@ -Xmx1024m - 1.68 + 1.69 6.0.3 3.0.0-M3 com.itextpdf.test.annotations.type.IntegrationTest @@ -83,7 +83,7 @@ 3.0.1 4.13.2 1.0.4 - 1.2.3 + 1.2.4 1.8 1.8 3.1.0 @@ -93,7 +93,7 @@ UTF-8 com.itextpdf.test.annotations.type.SampleTest true - 1.7.30 + 1.7.31 com.itextpdf.test.annotations.type.SlowTest target/dependency-check-report.html target/dependency-check-report.xml diff --git a/sign/pom.xml b/sign/pom.xml index 6db9360473..a0e0d843a6 100644 --- a/sign/pom.xml +++ b/sign/pom.xml @@ -4,7 +4,7 @@ com.itextpdf root - 7.2.0 + 7.2.1 sign iText 7 - sign diff --git a/sign/src/main/java/com/itextpdf/signatures/BouncyCastleDigest.java b/sign/src/main/java/com/itextpdf/signatures/BouncyCastleDigest.java index 80d1012af4..19a5d9dc0d 100644 --- a/sign/src/main/java/com/itextpdf/signatures/BouncyCastleDigest.java +++ b/sign/src/main/java/com/itextpdf/signatures/BouncyCastleDigest.java @@ -67,9 +67,11 @@ public class BouncyCastleDigest implements IExternalDigest { @Override public MessageDigest getMessageDigest(String hashAlgorithm) throws GeneralSecurityException { - // TODO DEVSIX-5800 throw an correct exception if there is no digest for an algorithm String oid = DigestAlgorithms.getAllowedDigest(hashAlgorithm); + if (oid == null) { + throw new NoSuchAlgorithmException(hashAlgorithm); + } switch (oid) { case "1.2.840.113549.2.2": //MD2 return new MD2.Digest(); diff --git a/sign/src/main/java/com/itextpdf/signatures/CertificateVerification.java b/sign/src/main/java/com/itextpdf/signatures/CertificateVerification.java index 111454629e..5ff38485bd 100644 --- a/sign/src/main/java/com/itextpdf/signatures/CertificateVerification.java +++ b/sign/src/main/java/com/itextpdf/signatures/CertificateVerification.java @@ -44,6 +44,7 @@ This file is part of the iText (R) project. package com.itextpdf.signatures; import com.itextpdf.commons.utils.DateTimeUtil; +import com.itextpdf.signatures.logs.SignLogMessageConstant; import org.bouncycastle.cert.ocsp.BasicOCSPResp; import org.bouncycastle.tsp.TimeStampToken; import org.slf4j.Logger; @@ -64,11 +65,10 @@ This file is part of the iText (R) project. */ public class CertificateVerification { - /** * The Logger instance. */ - private static final Logger LOGGER = LoggerFactory.getLogger(CrlClientOnline.class); + private static final Logger LOGGER = LoggerFactory.getLogger(CertificateVerification.class); /** * Verifies a single certificate for the current date. @@ -217,7 +217,9 @@ public static boolean verifyOcspCertificates(BasicOCSPResp ocsp, KeyStore keysto try { for (X509Certificate certStoreX509 : SignUtils.getCertificates(keystore)) { try { - return SignUtils.isSignatureValid(ocsp, certStoreX509, provider); + if (SignUtils.isSignatureValid(ocsp, certStoreX509, provider)) { + return true; + } } catch (Exception ex) { exceptionsThrown.add(ex); } @@ -225,9 +227,8 @@ public static boolean verifyOcspCertificates(BasicOCSPResp ocsp, KeyStore keysto } catch (Exception e) { exceptionsThrown.add(e); } - for (Exception ex : exceptionsThrown) { - LOGGER.error(ex.getMessage(), ex); - } + + logExceptionMessages(exceptionsThrown); return false; } @@ -244,22 +245,25 @@ public static boolean verifyTimestampCertificates(TimeStampToken ts, KeyStore ke try { for (X509Certificate certStoreX509 : SignUtils.getCertificates(keystore)) { try { - SignUtils.isSignatureValid(ts, certStoreX509, provider); return true; } catch (Exception ex) { exceptionsThrown.add(ex); - } } } catch (Exception e) { exceptionsThrown.add(e); } + logExceptionMessages(exceptionsThrown); + return false; + } + + private static void logExceptionMessages(List exceptionsThrown) { for (Exception ex : exceptionsThrown) { - LOGGER.error(ex.getMessage(), ex); + LOGGER.error(ex.getMessage() == null ? + SignLogMessageConstant.EXCEPTION_WITHOUT_MESSAGE : ex.getMessage(), ex); } - return false; } } diff --git a/sign/src/main/java/com/itextpdf/signatures/DigestAlgorithms.java b/sign/src/main/java/com/itextpdf/signatures/DigestAlgorithms.java index 9108749848..dba28e658e 100644 --- a/sign/src/main/java/com/itextpdf/signatures/DigestAlgorithms.java +++ b/sign/src/main/java/com/itextpdf/signatures/DigestAlgorithms.java @@ -43,6 +43,8 @@ */ package com.itextpdf.signatures; +import com.itextpdf.signatures.exceptions.SignExceptionMessageConstant; + import java.io.IOException; import java.io.InputStream; import java.security.GeneralSecurityException; @@ -255,6 +257,9 @@ public static String normalizeDigestName(String algo) { * @return An oid. */ public static String getAllowedDigest(String name) { + if (name == null) { + throw new IllegalArgumentException(SignExceptionMessageConstant.THE_NAME_OF_THE_DIGEST_ALGORITHM_IS_NULL); + } return allowedDigests.get(name.toUpperCase()); } } diff --git a/sign/src/main/java/com/itextpdf/signatures/PdfPKCS7.java b/sign/src/main/java/com/itextpdf/signatures/PdfPKCS7.java index c04975dca5..a01d2c63e6 100644 --- a/sign/src/main/java/com/itextpdf/signatures/PdfPKCS7.java +++ b/sign/src/main/java/com/itextpdf/signatures/PdfPKCS7.java @@ -770,7 +770,7 @@ public byte[] getEncodedPKCS1() { digest = sig.sign(); ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - ASN1OutputStream dout = new ASN1OutputStream(bOut); + ASN1OutputStream dout = ASN1OutputStream.create(bOut); dout.writeObject(new DEROctetString(digest)); dout.close(); @@ -926,7 +926,7 @@ public byte[] getEncodedPKCS7(byte[] secondDigest, PdfSigner.CryptoStandard sigt ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - ASN1OutputStream dout = new ASN1OutputStream(bOut); + ASN1OutputStream dout = ASN1OutputStream.create(bOut); dout.writeObject(new DERSequence(whole)); dout.close(); @@ -1195,7 +1195,7 @@ private boolean verifySigAttributes(byte[] attr) throws GeneralSecurityException * @throws GeneralSecurityException on error */ public boolean verifyTimestampImprint() throws GeneralSecurityException { - // TODO ensure this method works correctly + // TODO DEVSIX-6011 ensure this method works correctly if (timeStampToken == null) return false; TimeStampTokenInfo info = timeStampToken.getTimeStampInfo(); diff --git a/sign/src/main/java/com/itextpdf/signatures/PdfSignatureAppearance.java b/sign/src/main/java/com/itextpdf/signatures/PdfSignatureAppearance.java index b24d28c460..2b7bf5f699 100644 --- a/sign/src/main/java/com/itextpdf/signatures/PdfSignatureAppearance.java +++ b/sign/src/main/java/com/itextpdf/signatures/PdfSignatureAppearance.java @@ -873,7 +873,9 @@ protected PdfFormXObject getAppearance() throws IOException { napp.getResources().addForm(topLayer, new PdfName("FRM")); canvas = new PdfCanvas(napp, document); - canvas.addXObject(topLayer, 0, 0); + canvas.addXObjectAt(topLayer, + topLayer.getBBox().getAsNumber(0).floatValue(), + topLayer.getBBox().getAsNumber(1).floatValue()); return napp; } diff --git a/sign/src/main/java/com/itextpdf/signatures/PdfSigner.java b/sign/src/main/java/com/itextpdf/signatures/PdfSigner.java index 8e5330ad26..f9ce01350d 100644 --- a/sign/src/main/java/com/itextpdf/signatures/PdfSigner.java +++ b/sign/src/main/java/com/itextpdf/signatures/PdfSigner.java @@ -176,7 +176,6 @@ public enum CryptoStandard { * The crypto dictionary. */ protected PdfSignature cryptoDictionary; - private PdfName digestMethod; /** * Holds value of property signatureEvent. @@ -454,6 +453,9 @@ public PdfDocument getDocument() { * @param document The PdfDocument */ protected void setDocument(PdfDocument document) { + if (null == document.getReader()) { + throw new IllegalArgumentException(SignExceptionMessageConstant.DOCUMENT_MUST_HAVE_READER); + } this.document = document; } @@ -592,7 +594,6 @@ public void signDetached(IExternalDigest externalDigest, IExternalSignature exte dic.setContact(appearance.getContact()); dic.setDate(new PdfDate(getSignDate())); // time-stamp will over-rule this cryptoDictionary = dic; - digestMethod = getHashAlgorithmNameInCompatibleForPdfForm(hashAlgorithm); Map exc = new HashMap<>(); exc.put(PdfName.Contents, estimatedSize * 2 + 2); @@ -666,8 +667,9 @@ public void signExternalContainer(IExternalSignatureContainer externalSignatureC InputStream data = getRangeStream(); byte[] encodedSig = externalSignatureContainer.sign(data); - if (estimatedSize < encodedSig.length) - throw new IOException("Not enough space"); + if (estimatedSize < encodedSig.length) { + throw new IOException(SignExceptionMessageConstant.NOT_ENOUGH_SPACE); + } byte[] paddedSig = new byte[estimatedSize]; System.arraycopy(encodedSig, 0, paddedSig, 0, encodedSig.length); @@ -1089,7 +1091,7 @@ protected void close(PdfDictionary update) throws IOException { bous.reset(); os.write(obj); if (bous.size() > lit.getBytesCount()) - throw new IllegalArgumentException("The key is too big"); + throw new IllegalArgumentException(SignExceptionMessageConstant.TOO_BIG_KEY); if (tempFile == null) { System.arraycopy(bous.toByteArray(), 0, bout, (int) lit.getPosition(), (int) bous.size()); } else { @@ -1159,7 +1161,6 @@ protected void addDocMDP(PdfSignature crypto) { reference.put(PdfName.TransformMethod, PdfName.DocMDP); reference.put(PdfName.Type, PdfName.SigRef); reference.put(PdfName.TransformParams, transformParams); - setDigestParamToSigRefIfNeeded(reference); reference.put(PdfName.Data, document.getTrailer().get(PdfName.Root)); PdfArray types = new PdfArray(); types.add(reference); @@ -1182,7 +1183,6 @@ protected void addFieldMDP(PdfSignature crypto, PdfSigFieldLock fieldLock) { reference.put(PdfName.TransformMethod, PdfName.FieldMDP); reference.put(PdfName.Type, PdfName.SigRef); reference.put(PdfName.TransformParams, transformParams); - setDigestParamToSigRefIfNeeded(reference); reference.put(PdfName.Data, document.getTrailer().get(PdfName.Root)); PdfArray types = crypto.getPdfObject().getAsArray(PdfName.Reference); if (types == null) { @@ -1260,52 +1260,10 @@ protected int getWidgetPageNumber(PdfWidgetAnnotation widget) { return pageNumber; } - private void setDigestParamToSigRefIfNeeded(PdfDictionary reference) { - if (document.getPdfVersion().compareTo(PdfVersion.PDF_1_6) < 0) { - // Don't really know what to say about this if-clause code. - // Let's leave it, assuming that it is reasoned in some very specific way, until opposite is not proven. - - reference.put(PdfName.DigestValue, new PdfString("aa")); - PdfArray loc = new PdfArray(); - loc.add(new PdfNumber(0)); - loc.add(new PdfNumber(0)); - reference.put(PdfName.DigestLocation, loc); - reference.put(PdfName.DigestMethod, PdfName.MD5); - - } else if (isDocumentPdf2()) { - if (digestMethod != null) { - reference.put(PdfName.DigestMethod, digestMethod); - } else { - Logger logger = LoggerFactory.getLogger(PdfSigner.class); - logger.error(IoLogMessageConstant.UNKNOWN_DIGEST_METHOD); - } - } - } - - private PdfName getHashAlgorithmNameInCompatibleForPdfForm(String hashAlgorithm) { - PdfName pdfCompatibleName = null; - String hashAlgOid = DigestAlgorithms.getAllowedDigest(hashAlgorithm); - if (hashAlgOid != null) { - String hashAlgorithmNameInCompatibleForPdfForm = DigestAlgorithms.getDigest(hashAlgOid); - if (hashAlgorithmNameInCompatibleForPdfForm != null) { - pdfCompatibleName = new PdfName(hashAlgorithmNameInCompatibleForPdfForm); - } - } - return pdfCompatibleName; - } - private boolean isDocumentPdf2() { return document.getPdfVersion().compareTo(PdfVersion.PDF_2_0) >= 0; } - private static StampingProperties initStampingProperties(boolean append) { - StampingProperties properties = new StampingProperties(); - if (append) { - properties.useAppendMode(); - } - return properties; - } - /** * An interface to retrieve the signature dictionary for modification. */ diff --git a/sign/src/main/java/com/itextpdf/signatures/exceptions/SignExceptionMessageConstant.java b/sign/src/main/java/com/itextpdf/signatures/exceptions/SignExceptionMessageConstant.java index 736cc6e61f..41ec2c2ced 100644 --- a/sign/src/main/java/com/itextpdf/signatures/exceptions/SignExceptionMessageConstant.java +++ b/sign/src/main/java/com/itextpdf/signatures/exceptions/SignExceptionMessageConstant.java @@ -39,6 +39,7 @@ public final class SignExceptionMessageConstant { public static final String DICTIONARY_THIS_KEY_IS_NOT_A_NAME = "Dictionary key {0} is not a name."; public static final String DOCUMENT_ALREADY_PRE_CLOSED = "Document has been already pre closed."; public static final String DOCUMENT_MUST_BE_PRE_CLOSED = "Document must be preClosed."; + public static final String DOCUMENT_MUST_HAVE_READER = "Document must have reader."; public static final String FAILED_TO_GET_TSA_RESPONSE = "Failed to get TSA response from {0}."; public static final String FIELD_ALREADY_SIGNED = "Field has been already signed."; public static final String FIELD_NAMES_CANNOT_CONTAIN_A_DOT = "Field names cannot contain a dot."; @@ -49,8 +50,10 @@ public final class SignExceptionMessageConstant { public static final String NOT_A_VALID_PKCS7_OBJECT_NOT_A_SEQUENCE = "Not a valid PKCS#7 object - not a sequence"; public static final String NOT_A_VALID_PKCS7_OBJECT_NOT_SIGNED_DATA = "Not a valid PKCS#7 object - not signed " + "data."; + public static final String NOT_ENOUGH_SPACE = "Not enough space."; public static final String SIGNATURE_WITH_THIS_NAME_IS_NOT_THE_LAST_IT_DOES_NOT_COVER_WHOLE_DOCUMENT = "Signature " + "with name {0} is not the last. It doesn't cover the whole document."; + public static final String THE_NAME_OF_THE_DIGEST_ALGORITHM_IS_NULL = "The name of the digest algorithm is null."; public static final String THERE_IS_NO_FIELD_IN_THE_DOCUMENT_WITH_SUCH_NAME = "There is no field in the document " + "with such name: {0}."; public static final String THIS_PKCS7_OBJECT_HAS_MULTIPLE_SIGNERINFOS_ONLY_ONE_IS_SUPPORTED_AT_THIS_TIME = "This " @@ -59,6 +62,7 @@ public final class SignExceptionMessageConstant { + "already closed."; public static final String THIS_TSA_FAILED_TO_RETURN_TIME_STAMP_TOKEN = "TSA {0} failed to return time stamp " + "token: {1}."; + public static final String TOO_BIG_KEY = "The key is too big."; public static final String UNEXPECTED_CLOSE_BRACKET = "Unexpected close bracket."; public static final String UNEXPECTED_GT_GT = "unexpected >>."; public static final String UNKNOWN_HASH_ALGORITHM = "Unknown hash algorithm: {0}."; diff --git a/sign/src/main/java/com/itextpdf/signatures/logs/SignLogMessageConstant.java b/sign/src/main/java/com/itextpdf/signatures/logs/SignLogMessageConstant.java new file mode 100644 index 0000000000..ab3d321b17 --- /dev/null +++ b/sign/src/main/java/com/itextpdf/signatures/logs/SignLogMessageConstant.java @@ -0,0 +1,36 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2021 iText Group NV + Authors: iText Software. + + This program is offered under a commercial and under the AGPL license. + For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + + AGPL licensing: + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +package com.itextpdf.signatures.logs; + +/** + * Class which contains constants to be used in logging inside sign module. + */ +public final class SignLogMessageConstant { + + public static final String EXCEPTION_WITHOUT_MESSAGE = + "Unexpected exception without message was thrown during keystore processing"; + + private SignLogMessageConstant() { + // Private constructor will prevent the instantiation of this class directly + } +} diff --git a/sign/src/test/java/com/itextpdf/signatures/BouncyCastleDigestUnitTest.java b/sign/src/test/java/com/itextpdf/signatures/BouncyCastleDigestUnitTest.java index b9708afe50..e26a610f88 100644 --- a/sign/src/test/java/com/itextpdf/signatures/BouncyCastleDigestUnitTest.java +++ b/sign/src/test/java/com/itextpdf/signatures/BouncyCastleDigestUnitTest.java @@ -27,6 +27,8 @@ This file is part of the iText (R) project. import java.security.GeneralSecurityException; import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + import org.junit.Assert; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -90,17 +92,15 @@ public void getMessageDigestGOST3411Test() throws GeneralSecurityException { } @Test - // TODO DEVSIX-5800 throw an correct exception if there is no digest for an algorithm public void getMessageDigestNullTest() { IExternalDigest digest = new BouncyCastleDigest(); - Assert.assertThrows(NullPointerException.class, () -> digest.getMessageDigest(null)); + Assert.assertThrows(IllegalArgumentException.class, () -> digest.getMessageDigest(null)); } @Test - // TODO DEVSIX-5800 throw an correct exception if there is no digest for an algorithm public void getMessageDigestUnknownTest() { IExternalDigest digest = new BouncyCastleDigest(); - Assert.assertThrows(NullPointerException.class, () -> digest.getMessageDigest("unknown")); + Assert.assertThrows(NoSuchAlgorithmException.class, () -> digest.getMessageDigest("unknown")); } private static void getMessageDigestTest(String hashAlgorithm, String expectedDigestAlgorithm) diff --git a/sign/src/test/java/com/itextpdf/signatures/DigestAlgorithmsTest.java b/sign/src/test/java/com/itextpdf/signatures/DigestAlgorithmsTest.java index 3f86bbddd6..eb3fe65c66 100644 --- a/sign/src/test/java/com/itextpdf/signatures/DigestAlgorithmsTest.java +++ b/sign/src/test/java/com/itextpdf/signatures/DigestAlgorithmsTest.java @@ -75,6 +75,6 @@ public void nonExistingNameGetAllowedDigestTest() { @Test public void nullNameGetAllowedDigestTest() { - Assert.assertThrows(NullPointerException.class, () -> DigestAlgorithms.getAllowedDigest(null)); + Assert.assertThrows(IllegalArgumentException.class, () -> DigestAlgorithms.getAllowedDigest(null)); } } \ No newline at end of file diff --git a/sign/src/test/java/com/itextpdf/signatures/LtvVerifierUnitTest.java b/sign/src/test/java/com/itextpdf/signatures/LtvVerifierUnitTest.java new file mode 100644 index 0000000000..e5dde5f9b2 --- /dev/null +++ b/sign/src/test/java/com/itextpdf/signatures/LtvVerifierUnitTest.java @@ -0,0 +1,87 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2021 iText Group NV + Authors: iText Software. + + This program is offered under a commercial and under the AGPL license. + For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + + AGPL licensing: + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +package com.itextpdf.signatures; + +import com.itextpdf.kernel.pdf.PdfDictionary; +import com.itextpdf.kernel.pdf.PdfDocument; +import com.itextpdf.kernel.pdf.PdfReader; +import com.itextpdf.test.ExtendedITextTest; +import com.itextpdf.test.annotations.type.UnitTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.io.FileInputStream; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@Category(UnitTest.class) +public class LtvVerifierUnitTest extends ExtendedITextTest { + + private static final String SOURCE_FOLDER = "./src/test/resources/com/itextpdf/signatures/LtvVerifierUnitTest/"; + + @Test + public void setVerifierTest() throws GeneralSecurityException, IOException { + LtvVerifier verifier1 = new LtvVerifier(new PdfDocument(new PdfReader(new FileInputStream(SOURCE_FOLDER + "ltvDoc.pdf")))); + LtvVerifier verifier2 = new LtvVerifier(new PdfDocument(new PdfReader(new FileInputStream(SOURCE_FOLDER + "ltvDoc.pdf")))); + + verifier1.setVerifier(verifier2); + Assert.assertSame(verifier2, verifier1.verifier); + } + + @Test + public void setVerifyRootCertificateTest() throws GeneralSecurityException, IOException { + LtvVerifier verifier = new LtvVerifier(new PdfDocument(new PdfReader(new FileInputStream(SOURCE_FOLDER + "ltvDoc.pdf")))); + + verifier.setVerifyRootCertificate(true); + Assert.assertTrue(verifier.verifyRootCertificate); + } + + @Test + public void verifyNotNullTest() throws GeneralSecurityException, IOException { + LtvVerifier verifier = new LtvVerifier(new PdfDocument(new PdfReader(new FileInputStream(SOURCE_FOLDER + "ltvDoc.pdf")))); + verifier.pkcs7 = null; + + List list = Collections.emptyList(); + Assert.assertSame(list, verifier.verify(list)); + } + + @Test + public void getCRLsFromDSSCRLsNullTest() throws GeneralSecurityException, IOException { + LtvVerifier verifier = new LtvVerifier(new PdfDocument(new PdfReader(new FileInputStream(SOURCE_FOLDER + "ltvDoc.pdf")))); + + verifier.dss = new PdfDictionary(); + Assert.assertEquals(new ArrayList<>(), verifier.getCRLsFromDSS()); + } + + @Test + public void getOCSPResponsesFromDSSOCSPsNullTest() throws GeneralSecurityException, IOException { + LtvVerifier verifier = new LtvVerifier(new PdfDocument(new PdfReader(new FileInputStream(SOURCE_FOLDER + "ltvDoc.pdf")))); + + verifier.dss = new PdfDictionary(); + Assert.assertEquals(new ArrayList<>(), verifier.getOCSPResponsesFromDSS()); + } +} diff --git a/sign/src/test/java/com/itextpdf/signatures/PdfPKCS7Test.java b/sign/src/test/java/com/itextpdf/signatures/PdfPKCS7Test.java index d76edfa1ae..b64a8779d4 100644 --- a/sign/src/test/java/com/itextpdf/signatures/PdfPKCS7Test.java +++ b/sign/src/test/java/com/itextpdf/signatures/PdfPKCS7Test.java @@ -27,13 +27,19 @@ This file is part of the iText (R) project. import com.itextpdf.kernel.exceptions.PdfException; import com.itextpdf.kernel.pdf.PdfDocument; import com.itextpdf.kernel.pdf.PdfReader; +import com.itextpdf.kernel.pdf.StampingProperties; import com.itextpdf.signatures.exceptions.SignExceptionMessageConstant; +import com.itextpdf.signatures.sign.PadesSigTest; +import com.itextpdf.signatures.testutils.SignaturesCompareTool; import com.itextpdf.signatures.testutils.TimeTestUtil; +import com.itextpdf.signatures.testutils.client.TestTsaClient; import com.itextpdf.test.ExtendedITextTest; import com.itextpdf.test.annotations.type.UnitTest; import com.itextpdf.test.signutils.Pkcs12FileHelper; +import java.io.FileOutputStream; import java.io.IOException; +import java.security.GeneralSecurityException; import java.security.InvalidKeyException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; @@ -43,6 +49,7 @@ This file is part of the iText (R) project. import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.CertificateException; +import java.util.Arrays; import java.util.Calendar; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.tsp.TimeStampToken; @@ -188,6 +195,38 @@ public void ocspGetTest() throws IOException { EPS); } + @Test + public void verifyTimestampImprintSimpleSignatureTest() throws IOException, GeneralSecurityException { + PdfDocument outDocument = new PdfDocument( + new PdfReader(SOURCE_FOLDER + "simpleSignature.pdf")); + PdfPKCS7 pkcs7 = new SignatureUtil(outDocument).readSignatureData("Signature1"); + Assert.assertFalse(pkcs7.verifyTimestampImprint()); + } + + @Test + public void verifyTimestampImprintTimeStampSignatureTest() throws IOException, GeneralSecurityException { + PdfDocument outDocument = new PdfDocument( + new PdfReader(SOURCE_FOLDER + "timeStampSignature.pdf")); + PdfPKCS7 pkcs7 = new SignatureUtil(outDocument).readSignatureData("timestampSig1"); + Assert.assertFalse(pkcs7.verifyTimestampImprint()); + } + + @Test + public void verifyTimestampImprintEmbeddedTimeStampSignatureTest() throws IOException, GeneralSecurityException { + PdfDocument outDocument = new PdfDocument( + new PdfReader(SOURCE_FOLDER + "embeddedTimeStampSignature.pdf")); + PdfPKCS7 pkcs7 = new SignatureUtil(outDocument).readSignatureData("Signature1"); + Assert.assertTrue(pkcs7.verifyTimestampImprint()); + } + + @Test + public void verifyTimestampImprintCorruptedTimeStampSignatureTest() throws IOException, GeneralSecurityException { + PdfDocument outDocument = new PdfDocument( + new PdfReader(SOURCE_FOLDER + "embeddedTimeStampCorruptedSignature.pdf")); + PdfPKCS7 pkcs7 = new SignatureUtil(outDocument).readSignatureData("Signature1"); + Assert.assertTrue(pkcs7.verifyTimestampImprint()); + } + // PdfPKCS7 is created here the same way it's done in PdfSigner#signDetached private static PdfPKCS7 createSimplePdfPKCS7() throws NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException { diff --git a/sign/src/test/java/com/itextpdf/signatures/PdfSignerUnitTest.java b/sign/src/test/java/com/itextpdf/signatures/PdfSignerUnitTest.java index db0e63e256..af64cc7643 100644 --- a/sign/src/test/java/com/itextpdf/signatures/PdfSignerUnitTest.java +++ b/sign/src/test/java/com/itextpdf/signatures/PdfSignerUnitTest.java @@ -22,39 +22,89 @@ This file is part of the iText (R) project. */ package com.itextpdf.signatures; +import com.itextpdf.commons.utils.DateTimeUtil; import com.itextpdf.forms.PdfAcroForm; import com.itextpdf.forms.PdfSigFieldLock; import com.itextpdf.forms.fields.PdfFormField; import com.itextpdf.forms.fields.PdfSignatureFormField; import com.itextpdf.io.source.ByteArrayOutputStream; +import com.itextpdf.kernel.exceptions.PdfException; import com.itextpdf.kernel.geom.Rectangle; import com.itextpdf.kernel.pdf.EncryptionConstants; +import com.itextpdf.kernel.pdf.PdfAConformanceLevel; import com.itextpdf.kernel.pdf.PdfDictionary; import com.itextpdf.kernel.pdf.PdfDocument; import com.itextpdf.kernel.pdf.PdfName; +import com.itextpdf.kernel.pdf.PdfOutputIntent; import com.itextpdf.kernel.pdf.PdfReader; +import com.itextpdf.kernel.pdf.PdfString; +import com.itextpdf.kernel.pdf.PdfVersion; import com.itextpdf.kernel.pdf.PdfWriter; import com.itextpdf.kernel.pdf.ReaderProperties; import com.itextpdf.kernel.pdf.StampingProperties; import com.itextpdf.kernel.pdf.WriterProperties; import com.itextpdf.kernel.pdf.annot.PdfWidgetAnnotation; +import com.itextpdf.pdfa.PdfADocument; +import com.itextpdf.signatures.PdfSigner.ISignatureEvent; +import com.itextpdf.signatures.exceptions.SignExceptionMessageConstant; import com.itextpdf.test.ExtendedITextTest; import com.itextpdf.test.annotations.type.UnitTest; -import org.junit.Assert; -import org.junit.Test; -import org.junit.experimental.categories.Category; +import com.itextpdf.test.signutils.Pkcs12FileHelper; import java.io.ByteArrayInputStream; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; +import java.security.GeneralSecurityException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Security; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.util.Calendar; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; @Category(UnitTest.class) public class PdfSignerUnitTest extends ExtendedITextTest { + private static final byte[] OWNER = "owner".getBytes(); + private static final byte[] USER = "user".getBytes(); + + private static final String PDFA_RESOURCES = "./src/test/resources/com/itextpdf/signatures/pdfa/"; + private static final String DESTINATION_FOLDER = "./target/test/com/itextpdf/signatures/PdfSignerUnitTest/"; + private static final String CERTS_SRC = "./src/test/resources/com/itextpdf/signatures/certs/"; + + private static final char[] PASSWORD = "testpass".toCharArray(); + + private Certificate[] chain; + private PrivateKey pk; + + + @BeforeClass + public static void before() { + Security.addProvider(new BouncyCastleProvider()); + createOrClearDestinationFolder(DESTINATION_FOLDER); + } + + @Before + public void init() throws KeyStoreException, IOException, CertificateException, + NoSuchAlgorithmException, UnrecoverableKeyException { + pk = Pkcs12FileHelper.readFirstKey(CERTS_SRC + "signCertRsa01.p12", PASSWORD, PASSWORD); + chain = Pkcs12FileHelper.readFirstChain(CERTS_SRC + "signCertRsa01.p12", PASSWORD); + } + @Test public void createNewSignatureFormFieldInvisibleAnnotationTest() throws IOException { - PdfSigner signer = new PdfSigner( - new PdfReader(new ByteArrayInputStream(createDocumentWithoutWidgetAnnotation()), - new ReaderProperties().setPassword("owner".getBytes())), new ByteArrayOutputStream(), new StampingProperties()); + PdfSigner signer = new PdfSigner(new PdfReader( + new ByteArrayInputStream(createEncryptedDocumentWithoutWidgetAnnotation()), + new ReaderProperties().setPassword(OWNER)), new ByteArrayOutputStream(), new StampingProperties()); signer.cryptoDictionary = new PdfSignature(); signer.appearance.setPageRect(new Rectangle(100, 100, 0, 0)); @@ -70,8 +120,8 @@ public void createNewSignatureFormFieldInvisibleAnnotationTest() throws IOExcept @Test public void createNewSignatureFormFieldNotInvisibleAnnotationTest() throws IOException { PdfSigner signer = new PdfSigner( - new PdfReader(new ByteArrayInputStream(createDocumentWithoutWidgetAnnotation()), - new ReaderProperties().setPassword("owner".getBytes())), new ByteArrayOutputStream(), new StampingProperties()); + new PdfReader(new ByteArrayInputStream(createEncryptedDocumentWithoutWidgetAnnotation()), + new ReaderProperties().setPassword(OWNER)), new ByteArrayOutputStream(), new StampingProperties()); signer.cryptoDictionary = new PdfSignature(); signer.appearance.setPageRect(new Rectangle(100, 100, 10, 10)); PdfSigFieldLock fieldLock = new PdfSigFieldLock(); @@ -86,17 +136,65 @@ public void createNewSignatureFormFieldNotInvisibleAnnotationTest() throws IOExc Assert.assertTrue(formFieldDictionary.containsKey(PdfName.AP)); } + @Test + public void signWithFieldLockNotNullTest() throws IOException, GeneralSecurityException { + PdfSigner signer = new PdfSigner(new PdfReader( + new ByteArrayInputStream(createSimpleDocument(PdfVersion.PDF_2_0))), + new ByteArrayOutputStream(), + new StampingProperties()); + signer.cryptoDictionary = new PdfSignature(); + signer.appearance.setPageRect(new Rectangle(100, 100, 10, 10)); + PdfSigFieldLock fieldLock = new PdfSigFieldLock(); + signer.fieldLock = fieldLock; + + IExternalSignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, + BouncyCastleProvider.PROVIDER_NAME); + signer.signDetached(new BouncyCastleDigest(), pks, chain, null, null, null, 0, PdfSigner.CryptoStandard.CADES); + Assert.assertTrue(signer.closed); + } + + @Test + public void signDetachedWhenAlreadySignedIsNotPossibleTest() throws IOException, GeneralSecurityException { + PdfSigner signer = new PdfSigner(new PdfReader( + new ByteArrayInputStream(createSimpleDocument())), + new ByteArrayOutputStream(), + new StampingProperties()); + IExternalSignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, + BouncyCastleProvider.PROVIDER_NAME); + signer.signDetached(new BouncyCastleDigest(), pks, chain, null, null, null, 0, PdfSigner.CryptoStandard.CADES); + + Exception e = Assert.assertThrows(PdfException.class, () -> + signer.signDetached(new BouncyCastleDigest(), pks, chain, null, null, null, 0, + PdfSigner.CryptoStandard.CADES)); + Assert.assertEquals(SignExceptionMessageConstant.THIS_INSTANCE_OF_PDF_SIGNER_ALREADY_CLOSED, e.getMessage()); + } + + @Test + public void signExternalWhenAlreadySignedIsNotPossibleTest() throws IOException, GeneralSecurityException { + PdfSigner signer = new PdfSigner(new PdfReader( + new ByteArrayInputStream(createSimpleDocument())), + new ByteArrayOutputStream(), + new StampingProperties()); + IExternalSignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, + BouncyCastleProvider.PROVIDER_NAME); + signer.signDetached(new BouncyCastleDigest(), pks, chain, null, null, null, 0, PdfSigner.CryptoStandard.CADES); + + Exception e = Assert.assertThrows(PdfException.class, () -> + signer.signExternalContainer(new ExternalBlankSignatureContainer(new PdfDictionary()), 0)); + Assert.assertEquals(SignExceptionMessageConstant.THIS_INSTANCE_OF_PDF_SIGNER_ALREADY_CLOSED, e.getMessage()); + } + @Test public void populateExistingSignatureFormFieldInvisibleAnnotationTest() throws IOException { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); PdfDocument document = new PdfDocument(new PdfWriter(outputStream, - new WriterProperties().setStandardEncryption("user".getBytes(), "owner".getBytes(), 0, EncryptionConstants.STANDARD_ENCRYPTION_128))); + new WriterProperties().setStandardEncryption(USER, OWNER, 0, EncryptionConstants.STANDARD_ENCRYPTION_128))); document.addNewPage(); PdfWidgetAnnotation widgetAnnotation = new PdfWidgetAnnotation(new Rectangle(100, 100, 0, 0)); document.getPage(1).addAnnotation(widgetAnnotation); document.close(); PdfSigner signer = new PdfSigner( - new PdfReader(new ByteArrayInputStream(outputStream.toByteArray()), new ReaderProperties().setPassword("owner".getBytes())), + new PdfReader(new ByteArrayInputStream(outputStream.toByteArray()), new ReaderProperties().setPassword(OWNER)), new ByteArrayOutputStream(), new StampingProperties()); signer.cryptoDictionary = new PdfSignature(); signer.appearance.setPageRect(new Rectangle(100, 100, 0, 0)); @@ -118,13 +216,13 @@ public void populateExistingSignatureFormFieldInvisibleAnnotationTest() throws I public void populateExistingSignatureFormFieldNotInvisibleAnnotationTest() throws IOException { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); PdfDocument document = new PdfDocument(new PdfWriter(outputStream, - new WriterProperties().setStandardEncryption("user".getBytes(), "owner".getBytes(), 0, EncryptionConstants.STANDARD_ENCRYPTION_128))); + new WriterProperties().setStandardEncryption(USER, OWNER, 0, EncryptionConstants.STANDARD_ENCRYPTION_128))); document.addNewPage(); PdfWidgetAnnotation widgetAnnotation = new PdfWidgetAnnotation(new Rectangle(100, 100, 0, 0)); document.getPage(1).addAnnotation(widgetAnnotation); document.close(); PdfSigner signer = new PdfSigner( - new PdfReader(new ByteArrayInputStream(outputStream.toByteArray()), new ReaderProperties().setPassword("owner".getBytes())), + new PdfReader(new ByteArrayInputStream(outputStream.toByteArray()), new ReaderProperties().setPassword(OWNER)), new ByteArrayOutputStream(), new StampingProperties()); signer.cryptoDictionary = new PdfSignature(); PdfSigFieldLock fieldLock = new PdfSigFieldLock(); @@ -144,18 +242,282 @@ public void populateExistingSignatureFormFieldNotInvisibleAnnotationTest() throw Assert.assertTrue(formFieldDictionary.containsKey(PdfName.AP)); } - private static byte[] createDocumentWithoutWidgetAnnotation() { + @Test + public void tempFileProvidedTest() throws IOException { + String tempFileName = "tempFile"; + PdfSigner signer = new PdfSigner( + new PdfReader(new ByteArrayInputStream(createSimpleDocument())), + new ByteArrayOutputStream(), DESTINATION_FOLDER + tempFileName, new StampingProperties()); + Assert.assertNotNull(signer.tempFile); + Assert.assertEquals(tempFileName, signer.tempFile.getName()); + Assert.assertNull(signer.temporaryOS); + } + + @Test + // TODO DEVSIX-5910 The wrapped document should be recognized as Pdf/A + public void initPdfaDocumentTest() throws IOException { + PdfSigner signer = new PdfSigner( + new PdfReader(new ByteArrayInputStream(createSimplePdfaDocument())), + new ByteArrayOutputStream(), new StampingProperties()); + Assert.assertFalse(signer.getDocument() instanceof PdfADocument); + } + + @Test + public void signingDateSetGetTest() throws IOException { + PdfSigner signer = new PdfSigner( + new PdfReader(new ByteArrayInputStream(createSimplePdfaDocument())), + new ByteArrayOutputStream(), new StampingProperties()); + Calendar testDate = DateTimeUtil.getCurrentTimeCalendar(); + signer.setSignDate(testDate); + + Assert.assertEquals(testDate, signer.getSignDate()); + } + + @Test + public void certificationLevelSetGetTest() throws IOException { + PdfSigner signer = new PdfSigner( + new PdfReader(new ByteArrayInputStream(createSimplePdfaDocument())), + new ByteArrayOutputStream(), new StampingProperties()); + Assert.assertEquals(PdfSigner.NOT_CERTIFIED, signer.getCertificationLevel()); + + int testLevel = PdfSigner.CERTIFIED_NO_CHANGES_ALLOWED; + signer.setCertificationLevel(testLevel); + Assert.assertEquals(testLevel, signer.getCertificationLevel()); + } + + @Test + public void signatureDictionarySetGetTest() throws IOException { + PdfSigner signer = new PdfSigner( + new PdfReader(new ByteArrayInputStream(createSimplePdfaDocument())), + new ByteArrayOutputStream(), new StampingProperties()); + Assert.assertNull(signer.getSignatureDictionary()); + + PdfSignature testSignature = new PdfSignature(); + signer.cryptoDictionary = testSignature; + Assert.assertEquals(testSignature, signer.getSignatureDictionary()); + } + + @Test + public void signatureEventSetGetTest() throws IOException { + PdfSigner signer = new PdfSigner( + new PdfReader(new ByteArrayInputStream(createSimplePdfaDocument())), + new ByteArrayOutputStream(), new StampingProperties()); + Assert.assertNull(signer.getSignatureEvent()); + + ISignatureEvent testEvent = new DummySignatureEvent(); + signer.setSignatureEvent(testEvent); + Assert.assertEquals(testEvent, signer.getSignatureEvent()); + } + + @Test + public void signatureFieldNameMustNotContainDotTest() throws IOException { + PdfSigner signer = new PdfSigner( + new PdfReader(new ByteArrayInputStream(createSimplePdfaDocument())), + new ByteArrayOutputStream(), new StampingProperties()); + + Exception exception = + Assert.assertThrows(IllegalArgumentException.class, () -> signer.setFieldName("name.with.dots")); + Assert.assertEquals(SignExceptionMessageConstant.FIELD_NAMES_CANNOT_CONTAIN_A_DOT, exception.getMessage()); + } + + @Test + public void documentWithoutReaderCannotBeSetToSignerTest() throws IOException { + PdfReader reader = new PdfReader(new ByteArrayInputStream(createSimplePdfaDocument())); + PdfSigner signer = new PdfSigner(reader, new ByteArrayOutputStream(), new StampingProperties()); + + PdfDocument documentWithoutReader = new PdfDocument(new PdfWriter(new ByteArrayOutputStream())); + Exception e = + Assert.assertThrows(IllegalArgumentException.class, () -> signer.setDocument(documentWithoutReader)); + Assert.assertEquals(SignExceptionMessageConstant.DOCUMENT_MUST_HAVE_READER, e.getMessage()); + } + + @Test + public void documentSetGetTest() throws IOException { + PdfReader reader = new PdfReader(new ByteArrayInputStream(createSimplePdfaDocument())); + PdfSigner signer = new PdfSigner(reader, new ByteArrayOutputStream(), new StampingProperties()); + + PdfDocument document = signer.getDocument(); + Assert.assertEquals(reader, document.getReader()); + + PdfDocument documentWithoutReader = new PdfDocument( + new PdfReader(new ByteArrayInputStream(createSimpleDocument())), + new PdfWriter(new ByteArrayOutputStream())); + signer.setDocument(documentWithoutReader); + Assert.assertEquals(documentWithoutReader, signer.getDocument()); + } + + @Test + public void outputStreamSetGetTest() throws IOException { + PdfReader reader = new PdfReader(new ByteArrayInputStream(createSimplePdfaDocument())); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + PdfSigner signer = new PdfSigner(reader, outputStream, new StampingProperties()); + + Assert.assertEquals(outputStream, signer.originalOS); + + ByteArrayOutputStream anotherStream = new ByteArrayOutputStream(); + signer.setOriginalOutputStream(anotherStream); + Assert.assertEquals(anotherStream, signer.originalOS); + } + + @Test + public void fieldLockSetGetTest() throws IOException { + PdfReader reader = new PdfReader(new ByteArrayInputStream(createSimplePdfaDocument())); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + PdfSigner signer = new PdfSigner(reader, outputStream, new StampingProperties()); + + Assert.assertNull(signer.getFieldLockDict()); + + PdfSigFieldLock fieldLock = new PdfSigFieldLock(); + signer.setFieldLockDict(fieldLock); + Assert.assertEquals(fieldLock, signer.getFieldLockDict()); + } + + @Test + public void setFieldNameNullForDefaultSignerTest() throws IOException { + PdfReader reader = new PdfReader(new ByteArrayInputStream(createSimpleDocument())); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + PdfSigner signer = new PdfSigner(reader, outputStream, new StampingProperties()); + + signer.setFieldName(null); + Assert.assertEquals("Signature1", signer.getFieldName()); + } + + @Test + public void keepFieldNameAfterSetToNullTest() throws IOException { + PdfReader reader = new PdfReader(new ByteArrayInputStream(createSimpleDocument())); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + PdfSigner signer = new PdfSigner(reader, outputStream, new StampingProperties()); + + String testName = "test_name"; + signer.setFieldName(testName); + signer.setFieldName(null); + Assert.assertEquals(testName, signer.getFieldName()); + } + + @Test + public void setFieldNameToFieldWithSameNameAndNoSigTest() throws IOException { + PdfReader reader = new PdfReader(new ByteArrayInputStream(createDocumentWithEmptyField())); + PdfSigner signer = new PdfSigner(reader, new ByteArrayOutputStream(), new StampingProperties()); + + Exception e = Assert.assertThrows(IllegalArgumentException.class, () -> signer.setFieldName("test_field")); + Assert.assertEquals(SignExceptionMessageConstant.FIELD_TYPE_IS_NOT_A_SIGNATURE_FIELD_TYPE, e.getMessage()); + + reader.close(); + } + + @Test + public void setFieldNameToSigFieldWithValueTest() throws IOException { + String fieldName = "test_field"; + String fieldValue = "test_value"; + PdfReader reader = new PdfReader( + new ByteArrayInputStream(createDocumentWithSignatureWithTestValueField(fieldName, fieldValue))); + PdfSigner signer = new PdfSigner(reader, new ByteArrayOutputStream(), new StampingProperties()); + + Exception e = Assert.assertThrows(IllegalArgumentException.class, () -> signer.setFieldName(fieldName)); + Assert.assertEquals(SignExceptionMessageConstant.FIELD_ALREADY_SIGNED, e.getMessage()); + + reader.close(); + } + + @Test + public void setFieldNameToSigFieldWithoutWidgetsTest() throws IOException { + String fieldName = "test_field"; + PdfReader reader = new PdfReader(new ByteArrayInputStream(createDocumentWithSignatureField(fieldName))); + PdfSigner signer = new PdfSigner(reader, new ByteArrayOutputStream(), new StampingProperties()); + + signer.setFieldName(fieldName); + Assert.assertEquals(fieldName, signer.getFieldName()); + + reader.close(); + } + + private static byte[] createDocumentWithEmptyField() { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + PdfDocument pdfDocument = new PdfDocument(new PdfWriter(outputStream)); + PdfFormField formField = PdfFormField.createEmptyField(pdfDocument).setFieldName("test_field"); + PdfAcroForm acroForm = PdfAcroForm.getAcroForm(pdfDocument, true); + acroForm.addField(formField); + pdfDocument.close(); + return outputStream.toByteArray(); + } + + private static byte[] createDocumentWithSignatureWithTestValueField(String fieldName, String fieldValue) { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + PdfDocument pdfDocument = new PdfDocument(new PdfWriter(outputStream)); + PdfFormField formField = PdfFormField.createSignature(pdfDocument) + .setFieldName(fieldName) + .setValue(fieldValue); + PdfAcroForm acroForm = PdfAcroForm.getAcroForm(pdfDocument, true); + acroForm.addField(formField); + pdfDocument.close(); + return outputStream.toByteArray(); + } + + private static byte[] createDocumentWithSignatureField(String fieldName) { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + PdfDocument pdfDocument = new PdfDocument(new PdfWriter(outputStream)); + PdfFormField formField = PdfFormField.createSignature(pdfDocument) + .setFieldName(fieldName); + PdfAcroForm acroForm = PdfAcroForm.getAcroForm(pdfDocument, true); + acroForm.addField(formField); + pdfDocument.close(); + return outputStream.toByteArray(); + } + + private static byte[] createEncryptedDocumentWithoutWidgetAnnotation() { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); PdfDocument document = new PdfDocument(new PdfWriter(outputStream, - new WriterProperties().setStandardEncryption("user".getBytes(), "owner".getBytes(), 0, EncryptionConstants.STANDARD_ENCRYPTION_128))); + new WriterProperties() + .setStandardEncryption(USER, OWNER, 0, EncryptionConstants.STANDARD_ENCRYPTION_128))); + document.addNewPage(); + document.close(); + return outputStream.toByteArray(); + } + + private static byte[] createSimpleDocument() { + return createSimpleDocument(PdfVersion.PDF_1_7); + } + + private static byte[] createSimpleDocument(PdfVersion version) { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + WriterProperties writerProperties = new WriterProperties(); + if (null != version) { + writerProperties.setPdfVersion(version); + } + PdfDocument document = new PdfDocument(new PdfWriter(outputStream, writerProperties)); document.addNewPage(); document.close(); return outputStream.toByteArray(); } + private static byte[] createSimplePdfaDocument() throws IOException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + PdfWriter writer = new PdfWriter(outputStream); + InputStream is = new FileInputStream(PDFA_RESOURCES + "sRGB Color Space Profile.icm"); + PdfOutputIntent outputIntent = + new PdfOutputIntent("Custom", "", "http://www.color.org", "sRGB IEC61966-2.1", is); + PdfDocument document = new PdfADocument(writer, PdfAConformanceLevel.PDF_A_1A, outputIntent); + + document.setTagged(); + document.getCatalog().setLang(new PdfString("en-US")); + + document.addNewPage(); + document.close(); + + return outputStream.toByteArray(); + } + static class ExtendedPdfSignatureFormField extends PdfSignatureFormField { public ExtendedPdfSignatureFormField(PdfWidgetAnnotation widgetAnnotation, PdfDocument document) { super(widgetAnnotation, document); } } + + class DummySignatureEvent implements ISignatureEvent { + + @Override + public void getSignatureDictionary(PdfSignature sig) { + // Do nothing + } + } } diff --git a/sign/src/test/java/com/itextpdf/signatures/VerificationOKTest.java b/sign/src/test/java/com/itextpdf/signatures/VerificationOKTest.java index 3d0cb57dc1..6e7cced032 100644 --- a/sign/src/test/java/com/itextpdf/signatures/VerificationOKTest.java +++ b/sign/src/test/java/com/itextpdf/signatures/VerificationOKTest.java @@ -42,23 +42,10 @@ This file is part of the iText (R) project. */ package com.itextpdf.signatures; +import com.itextpdf.signatures.testutils.X509MockCertificate; import com.itextpdf.test.ExtendedITextTest; import com.itextpdf.test.annotations.type.UnitTest; -import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.Principal; -import java.security.PublicKey; -import java.security.SignatureException; -import java.security.cert.CertificateEncodingException; -import java.security.cert.CertificateException; -import java.security.cert.CertificateExpiredException; -import java.security.cert.CertificateNotYetValidException; -import java.security.cert.X509Certificate; -import java.util.Date; -import java.util.Set; import org.junit.Assert; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -67,8 +54,14 @@ This file is part of the iText (R) project. public class VerificationOKTest extends ExtendedITextTest { @Test public void toStringTest() { - VerificationOK verificationOK = new VerificationOK(null, CRLVerifier.class, "Mock verification"); Assert.assertEquals(CRLVerifier.class.getName() + ": Mock verification", verificationOK.toString()); } + + @Test + public void toStringWithCertificateNotNullTest() { + VerificationOK verificationOK = new VerificationOK(new X509MockCertificate(), CRLVerifier.class, "Mock verification"); + // NPE is thrown because getSubjectDN method returns null for X509MockCertificate class. + Assert.assertThrows(NullPointerException.class, () -> verificationOK.toString()); + } } diff --git a/sign/src/test/java/com/itextpdf/signatures/sign/LtvSigTest.java b/sign/src/test/java/com/itextpdf/signatures/sign/LtvSigTest.java index b17b47a809..5f62682bd8 100644 --- a/sign/src/test/java/com/itextpdf/signatures/sign/LtvSigTest.java +++ b/sign/src/test/java/com/itextpdf/signatures/sign/LtvSigTest.java @@ -54,6 +54,7 @@ This file is part of the iText (R) project. import com.itextpdf.signatures.LtvVerification; import com.itextpdf.signatures.PdfSigner; import com.itextpdf.signatures.PrivateKeySignature; +import com.itextpdf.signatures.testutils.SignaturesCompareTool; import com.itextpdf.signatures.testutils.client.TestCrlClient; import com.itextpdf.signatures.testutils.client.TestOcspClient; import com.itextpdf.signatures.testutils.client.TestTsaClient; @@ -117,6 +118,9 @@ public void ltvEnabledTest01() throws IOException, GeneralSecurityException { signer.timestamp(testTsa, "timestampSig1"); basicCheckLtvDoc("ltvEnabledTsTest01.pdf", "timestampSig1"); + + Assert.assertNull( + SignaturesCompareTool.compareSignatures(ltvTsFileName, sourceFolder + "cmp_ltvEnabledTsTest01.pdf")); } @Test @@ -179,6 +183,9 @@ public void secondLtvOriginalHasNoVri01() throws IOException, GeneralSecurityExc signer.timestamp(testTsa, "timestampSig2"); basicCheckLtvDoc("secondLtvOriginalHasNoVriTs01.pdf", "timestampSig2"); + + Assert.assertNull(SignaturesCompareTool.compareSignatures( + ltvTsFileName, sourceFolder + "cmp_secondLtvOriginalHasNoVriTs01.pdf")); } private void basicCheckLtvDoc(String outFileName, String tsSigName) throws IOException, GeneralSecurityException { diff --git a/sign/src/test/java/com/itextpdf/signatures/sign/PadesSignatureLevelTest.java b/sign/src/test/java/com/itextpdf/signatures/sign/PadesSignatureLevelTest.java index 935ea84c5f..c9a01314f8 100644 --- a/sign/src/test/java/com/itextpdf/signatures/sign/PadesSignatureLevelTest.java +++ b/sign/src/test/java/com/itextpdf/signatures/sign/PadesSignatureLevelTest.java @@ -56,6 +56,7 @@ This file is part of the iText (R) project. import com.itextpdf.signatures.LtvVerification; import com.itextpdf.signatures.PdfSigner; import com.itextpdf.signatures.PrivateKeySignature; +import com.itextpdf.signatures.testutils.SignaturesCompareTool; import com.itextpdf.signatures.testutils.client.TestCrlClient; import com.itextpdf.signatures.testutils.client.TestOcspClient; import com.itextpdf.signatures.testutils.client.TestTsaClient; @@ -119,6 +120,9 @@ public void padesSignatureLevelTTest01() throws GeneralSecurityException, IOExce signer.signDetached(new BouncyCastleDigest(), pks, signRsaChain, null, null, testTsa, 0, PdfSigner.CryptoStandard.CADES); PadesSigTest.basicCheckSignedDoc(destinationFolder + "padesSignatureLevelTTest01.pdf", "Signature1"); + + Assert.assertNull(SignaturesCompareTool.compareSignatures( + outFileName, sourceFolder + "cmp_padesSignatureLevelTTest01.pdf")); } @Test diff --git a/sign/src/test/java/com/itextpdf/signatures/sign/PdfASigningTest.java b/sign/src/test/java/com/itextpdf/signatures/sign/PdfASigningTest.java index f65890a7e9..e4a67b0b6e 100644 --- a/sign/src/test/java/com/itextpdf/signatures/sign/PdfASigningTest.java +++ b/sign/src/test/java/com/itextpdf/signatures/sign/PdfASigningTest.java @@ -42,6 +42,7 @@ This file is part of the iText (R) project. */ package com.itextpdf.signatures.sign; +import com.itextpdf.forms.PdfSigFieldLock; import com.itextpdf.kernel.font.PdfFont; import com.itextpdf.kernel.font.PdfFontFactory; import com.itextpdf.kernel.font.PdfFontFactory.EmbeddingStrategy; @@ -55,17 +56,13 @@ This file is part of the iText (R) project. import com.itextpdf.signatures.PdfSignatureAppearance; import com.itextpdf.signatures.PdfSigner; import com.itextpdf.signatures.PrivateKeySignature; -import com.itextpdf.test.signutils.Pkcs12FileHelper; +import com.itextpdf.signatures.testutils.SignaturesCompareTool; import com.itextpdf.test.ExtendedITextTest; import com.itextpdf.test.annotations.type.IntegrationTest; +import com.itextpdf.test.pdfa.VeraPdfValidator; +import com.itextpdf.test.signutils.Pkcs12FileHelper; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.junit.Assert; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.experimental.categories.Category; - +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.security.GeneralSecurityException; @@ -76,10 +73,16 @@ This file is part of the iText (R) project. import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.CertificateException; -import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; @Category(IntegrationTest.class) public class PdfASigningTest extends ExtendedITextTest { @@ -121,10 +124,28 @@ public void simpleSigningTest() throws GeneralSecurityException, IOException, In sign(src, fieldName, dest, chain, pk, DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CADES, "Test 1", "TestCity", rect, false, false, PdfSigner.NOT_CERTIFIED, 12f); + Assert.assertNull(new VeraPdfValidator().validate(dest)); + Assert.assertNull(SignaturesCompareTool.compareSignatures(dest, sourceFolder + "cmp_" + fileName)); Assert.assertNull(new CompareTool().compareVisually(dest, sourceFolder + "cmp_" + fileName, destinationFolder, "diff_", getTestMap(new Rectangle(67, 575, 155, 15)))); } + @Test + public void signingPdfA2DocumentTest() throws IOException, GeneralSecurityException { + String src = sourceFolder + "simplePdfA2Document.pdf"; + String out = destinationFolder + "signedPdfA2Document.pdf"; + + PdfReader reader = new PdfReader(new FileInputStream(src)); + PdfSigner signer = new PdfSigner(reader, new FileOutputStream(out), new StampingProperties()); + signer.setFieldLockDict(new PdfSigFieldLock()); + signer.setCertificationLevel(PdfSigner.CERTIFIED_NO_CHANGES_ALLOWED); + + IExternalSignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, BouncyCastleProvider.PROVIDER_NAME); + signer.signDetached(new BouncyCastleDigest(), pks, chain, null, null, null, 0, PdfSigner.CryptoStandard.CADES); + + Assert.assertNull(new VeraPdfValidator().validate(out)); + } + protected void sign(String src, String name, String dest, Certificate[] chain, PrivateKey pk, @@ -172,8 +193,7 @@ protected void sign(String src, String name, String dest, private static Map> getTestMap(Rectangle ignoredArea) { Map> result = new HashMap>(); - result.put(1, Arrays.asList(ignoredArea)); + result.put(1, Collections.singletonList(ignoredArea)); return result; } - } diff --git a/sign/src/test/java/com/itextpdf/signatures/sign/SequentialSignaturesTest.java b/sign/src/test/java/com/itextpdf/signatures/sign/SequentialSignaturesTest.java index 18d0681242..7985b75b47 100644 --- a/sign/src/test/java/com/itextpdf/signatures/sign/SequentialSignaturesTest.java +++ b/sign/src/test/java/com/itextpdf/signatures/sign/SequentialSignaturesTest.java @@ -55,6 +55,7 @@ This file is part of the iText (R) project. import com.itextpdf.signatures.PdfSigner; import com.itextpdf.signatures.PdfSigner.CryptoStandard; import com.itextpdf.signatures.PrivateKeySignature; +import com.itextpdf.signatures.testutils.SignaturesCompareTool; import com.itextpdf.test.signutils.Pkcs12FileHelper; import com.itextpdf.test.ExtendedITextTest; import com.itextpdf.test.annotations.type.IntegrationTest; @@ -90,6 +91,7 @@ public void sequentialSignOfFileWithAnnots() throws IOException, GeneralSecurity String signCertFileName = certsSrc + "signCertRsa01.p12"; String outFileName = destinationFolder + "sequentialSignOfFileWithAnnots.pdf"; String srcFileName = sourceFolder + "signedWithAnnots.pdf"; + String cmpFileName = sourceFolder + "cmp_sequentialSignOfFileWithAnnots.pdf"; Certificate[] signChain = Pkcs12FileHelper.readFirstChain(signCertFileName, password); PrivateKey signPrivateKey = Pkcs12FileHelper.readFirstKey(signCertFileName, password, password); @@ -107,6 +109,7 @@ public void sequentialSignOfFileWithAnnots() throws IOException, GeneralSecurity signer.signDetached(new BouncyCastleDigest(), pks, signChain, null, null, null, 0, PdfSigner.CryptoStandard.CADES); PadesSigTest.basicCheckSignedDoc(outFileName, signatureName); + Assert.assertNull(SignaturesCompareTool.compareSignatures(outFileName, cmpFileName)); } @Test @@ -114,6 +117,7 @@ public void secondSignOfTaggedDocTest() throws IOException, GeneralSecurityExcep String signCertFileName = certsSrc + "signCertRsa01.p12"; String outFileName = destinationFolder + "secondSignOfTagged.pdf"; String srcFileName = sourceFolder + "taggedAndSignedDoc.pdf"; + String cmpFileName = sourceFolder + "cmp_secondSignOfTagged.pdf"; Certificate[] signChain = Pkcs12FileHelper.readFirstChain(signCertFileName, password); @@ -159,5 +163,7 @@ public void secondSignOfTaggedDocTest() throws IOException, GeneralSecurityExcep // objects in StructTreeRoot to ensure that it won't be changed. Assert.assertNotEquals(resourceStrElemNumber, outStrElemNumber); } + + Assert.assertNull(SignaturesCompareTool.compareSignatures(outFileName, cmpFileName)); } } diff --git a/sign/src/test/java/com/itextpdf/signatures/sign/SignDeferredTest.java b/sign/src/test/java/com/itextpdf/signatures/sign/SignDeferredTest.java index 51852083e2..ef4be470e0 100644 --- a/sign/src/test/java/com/itextpdf/signatures/sign/SignDeferredTest.java +++ b/sign/src/test/java/com/itextpdf/signatures/sign/SignDeferredTest.java @@ -61,15 +61,12 @@ This file is part of the iText (R) project. import com.itextpdf.signatures.PdfSignatureAppearance; import com.itextpdf.signatures.PdfSigner; import com.itextpdf.signatures.PrivateKeySignature; +import com.itextpdf.signatures.exceptions.SignExceptionMessageConstant; import com.itextpdf.signatures.testutils.SignTestPortUtil; +import com.itextpdf.signatures.testutils.SignaturesCompareTool; import com.itextpdf.test.ExtendedITextTest; import com.itextpdf.test.annotations.type.IntegrationTest; import com.itextpdf.test.signutils.Pkcs12FileHelper; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.experimental.categories.Category; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -80,6 +77,11 @@ This file is part of the iText (R) project. import java.security.PrivateKey; import java.security.Security; import java.security.cert.Certificate; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; @Category(IntegrationTest.class) public class SignDeferredTest extends ExtendedITextTest { @@ -121,6 +123,57 @@ public void prepareDocForSignDeferredTest() throws IOException, GeneralSecurityE validateTemplateForSignedDeferredResult(output, sigFieldName, filter, subFilter, estimatedSize); } + @Test + public void prepareDocForSignDeferredNotEnoughSizeTest() throws IOException, GeneralSecurityException { + String input = sourceFolder + "helloWorldDoc.pdf"; + + String sigFieldName = "DeferredSignature1"; + PdfName filter = PdfName.Adobe_PPKLite; + PdfName subFilter = PdfName.Adbe_pkcs7_detached; + + PdfReader reader = new PdfReader(input); + PdfSigner signer = new PdfSigner(reader, new ByteArrayOutputStream(), new StampingProperties()); + PdfSignatureAppearance appearance = signer.getSignatureAppearance(); + appearance + .setLayer2Text("Signature field which signing is deferred.") + .setPageRect(new Rectangle(36, 600, 200, 100)) + .setPageNumber(1); + signer.setFieldName(sigFieldName); + IExternalSignatureContainer external = new ExternalBlankSignatureContainer(filter, subFilter); + + // This size is definitely not enough + int estimatedSize = -1; + Exception e = Assert.assertThrows(IOException.class, + () -> signer.signExternalContainer(external, estimatedSize)); + Assert.assertEquals(SignExceptionMessageConstant.NOT_ENOUGH_SPACE, e.getMessage()); + } + + @Test + public void prepareDocForSignDeferredLittleSpaceTest() throws IOException { + String input = sourceFolder + "helloWorldDoc.pdf"; + + String sigFieldName = "DeferredSignature1"; + PdfName filter = PdfName.Adobe_PPKLite; + PdfName subFilter = PdfName.Adbe_pkcs7_detached; + + PdfReader reader = new PdfReader(input); + PdfSigner signer = new PdfSigner(reader, new ByteArrayOutputStream(), new StampingProperties()); + PdfSignatureAppearance appearance = signer.getSignatureAppearance(); + appearance + .setLayer2Text("Signature field which signing is deferred.") + .setPageRect(new Rectangle(36, 600, 200, 100)) + .setPageNumber(1); + signer.setFieldName(sigFieldName); + IExternalSignatureContainer external = new ExternalBlankSignatureContainer(filter, subFilter); + + // This size is definitely not enough, however, the size check will pass. + // The test will fail lately on an invalid key + int estimatedSize = 0; + Exception e = Assert.assertThrows(IllegalArgumentException.class, + () -> signer.signExternalContainer(external, estimatedSize)); + Assert.assertEquals(SignExceptionMessageConstant.TOO_BIG_KEY, e.getMessage()); + } + @Test public void deferredHashCalcAndSignTest01() throws IOException, GeneralSecurityException, InterruptedException { String srcFileName = sourceFolder + "templateForSignCMSDeferred.pdf"; @@ -143,6 +196,7 @@ public void deferredHashCalcAndSignTest01() throws IOException, GeneralSecurityE // validate result PadesSigTest.basicCheckSignedDoc(outFileName, sigFieldName); Assert.assertNull(new CompareTool().compareVisually(outFileName, cmpFileName, destinationFolder, null)); + Assert.assertNull(SignaturesCompareTool.compareSignatures(outFileName, cmpFileName)); } @Test @@ -193,6 +247,7 @@ public void calcHashOnDocCreationThenDeferredSignTest01() throws IOException, Ge // validate result PadesSigTest.basicCheckSignedDoc(outFileName, sigFieldName); Assert.assertNull(new CompareTool().compareVisually(outFileName, cmpFileName, destinationFolder, null)); + Assert.assertNull(SignaturesCompareTool.compareSignatures(outFileName, cmpFileName)); } static void validateTemplateForSignedDeferredResult(String output, String sigFieldName, PdfName filter, PdfName subFilter, int estimatedSize) throws IOException { diff --git a/sign/src/test/java/com/itextpdf/signatures/sign/SimpleSigningTest.java b/sign/src/test/java/com/itextpdf/signatures/sign/SimpleSigningTest.java index 3a11347cf9..a737c08903 100644 --- a/sign/src/test/java/com/itextpdf/signatures/sign/SimpleSigningTest.java +++ b/sign/src/test/java/com/itextpdf/signatures/sign/SimpleSigningTest.java @@ -44,6 +44,7 @@ This file is part of the iText (R) project. import com.itextpdf.kernel.geom.Rectangle; import com.itextpdf.kernel.pdf.PdfReader; +import com.itextpdf.kernel.pdf.PdfWriter; import com.itextpdf.kernel.pdf.StampingProperties; import com.itextpdf.kernel.utils.CompareTool; import com.itextpdf.signatures.BouncyCastleDigest; @@ -121,6 +122,51 @@ public void pdfDocWithParagraphSigningTest() throws GeneralSecurityException, IO Assert.assertNull(SignaturesCompareTool.compareSignatures(outPdf, cmpPdf)); } + @Test + public void signWithoutPKeyTest() throws GeneralSecurityException, IOException, InterruptedException { + String srcFile = SOURCE_FOLDER + "emptySignatureWithoutPKey.pdf"; + String cmpPdf = SOURCE_FOLDER + "cmp_signedWithoutPKey.pdf"; + String outPdf = DESTINATION_FOLDER + "signedWithoutPKey.pdf"; + + Rectangle rect = new Rectangle(36, 648, 200, 100); + + String fieldName = "Signature1"; + sign(srcFile, fieldName, outPdf, chain, pk, DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CADES, "Test 1", + "TestCity", rect, false, false, PdfSigner.NOT_CERTIFIED, 12f); + + Assert.assertNull(new CompareTool().compareVisually(outPdf, cmpPdf, DESTINATION_FOLDER, "diff_", + getTestMap(rect))); + + Assert.assertNull(SignaturesCompareTool.compareSignatures(outPdf, cmpPdf)); + } + + @Test + public void signWithTempFileTest() throws GeneralSecurityException, IOException, InterruptedException { + String srcFile = SOURCE_FOLDER + "simpleDocument.pdf"; + String cmpPdf = SOURCE_FOLDER + "cmp_signedWithTempFile.pdf"; + String outPdf = DESTINATION_FOLDER + "signedWithTempFile.pdf"; + + String tempFileName = "tempFile"; + PdfSigner signer = new PdfSigner( + new PdfReader(srcFile), + new PdfWriter(outPdf), DESTINATION_FOLDER + tempFileName, new StampingProperties()); + Rectangle rect = new Rectangle(36, 648, 200, 100); + + signer.setCertificationLevel(PdfSigner.NOT_CERTIFIED); + signer.setFieldName("Signature1"); + + // Creating the appearance + createAppearance(signer, "Test 1", "TestCity", false, rect, 12f); + + // Creating the signature + IExternalSignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, BouncyCastleProvider.PROVIDER_NAME); + signer.signDetached(new BouncyCastleDigest(), pks, chain, null, null, null, 0, PdfSigner.CryptoStandard.CADES); + + Assert.assertNull(new CompareTool().compareVisually(outPdf, cmpPdf, DESTINATION_FOLDER, "diff_", + getTestMap(rect))); + Assert.assertNull(SignaturesCompareTool.compareSignatures(outPdf, cmpPdf)); + } + protected void sign(String src, String name, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm, PdfSigner.CryptoStandard subfilter, @@ -138,17 +184,7 @@ protected void sign(String src, String name, String dest, signer.setCertificationLevel(certificationLevel); // Creating the appearance - PdfSignatureAppearance appearance = signer.getSignatureAppearance() - .setReason(reason) - .setLocation(location) - .setReuseAppearance(setReuseAppearance); - - if (rectangleForNewField != null) { - appearance.setPageRect(rectangleForNewField); - } - if (fontSize != null) { - appearance.setLayer2FontSize((float) fontSize); - } + createAppearance(signer, reason, location, setReuseAppearance, rectangleForNewField, fontSize); signer.setFieldName(name); // Creating the signature @@ -161,4 +197,19 @@ private static Map> getTestMap(Rectangle ignoredArea) { result.put(1, Arrays.asList(ignoredArea)); return result; } + + private static void createAppearance(PdfSigner signer, String reason, String location, boolean setReuseAppearance, + Rectangle rectangleForNewField, Float fontSize) { + PdfSignatureAppearance appearance = signer.getSignatureAppearance() + .setReason(reason) + .setLocation(location) + .setReuseAppearance(setReuseAppearance); + + if (rectangleForNewField != null) { + appearance.setPageRect(rectangleForNewField); + } + if (fontSize != null) { + appearance.setLayer2FontSize((float) fontSize); + } + } } diff --git a/sign/src/test/java/com/itextpdf/signatures/sign/TimestampSigTest.java b/sign/src/test/java/com/itextpdf/signatures/sign/TimestampSigTest.java index 4f1f487ae8..3a4793521c 100644 --- a/sign/src/test/java/com/itextpdf/signatures/sign/TimestampSigTest.java +++ b/sign/src/test/java/com/itextpdf/signatures/sign/TimestampSigTest.java @@ -45,10 +45,12 @@ This file is part of the iText (R) project. import com.itextpdf.kernel.pdf.PdfReader; import com.itextpdf.kernel.pdf.StampingProperties; import com.itextpdf.signatures.PdfSigner; +import com.itextpdf.signatures.testutils.SignaturesCompareTool; import com.itextpdf.signatures.testutils.client.TestTsaClient; import com.itextpdf.test.ExtendedITextTest; import com.itextpdf.test.annotations.type.IntegrationTest; import com.itextpdf.test.signutils.Pkcs12FileHelper; +import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -92,6 +94,9 @@ public void timestampTest01() throws IOException, GeneralSecurityException { signer.timestamp(testTsa, "timestampSig1"); PadesSigTest.basicCheckSignedDoc(destinationFolder + "timestampTest01.pdf", "timestampSig1"); + + Assert.assertNull( + SignaturesCompareTool.compareSignatures(outFileName, sourceFolder + "cmp_timestampTest01.pdf")); } diff --git a/sign/src/test/java/com/itextpdf/signatures/testutils/SignaturesCompareTool.java b/sign/src/test/java/com/itextpdf/signatures/testutils/SignaturesCompareTool.java index a05b239cf6..36069fcf9c 100644 --- a/sign/src/test/java/com/itextpdf/signatures/testutils/SignaturesCompareTool.java +++ b/sign/src/test/java/com/itextpdf/signatures/testutils/SignaturesCompareTool.java @@ -53,7 +53,12 @@ This file is part of the iText (R) project. import java.io.ByteArrayInputStream; import java.io.FileWriter; import java.io.IOException; +import java.util.Arrays; import java.util.List; +import java.util.Objects; + +import com.itextpdf.test.ITextTest; +import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1OctetString; @@ -65,9 +70,20 @@ This file is part of the iText (R) project. public class SignaturesCompareTool { private static final String OID_MESSAGE_DIGEST = "1.2.840.113549.1.9.4"; + + // Timestamp related ids private static final String OID_SIGNED_DATA = "1.2.840.113549.1.7.2"; + private static final String OID_TST_INFO = "1.2.840.113549.1.9.16.1.4"; + private static final String OID_SIGNING_TIME = "1.2.840.113549.1.9.5"; + private static final String OID_SIGNATURE_TIMESTAMP_ATTRIBUTE = "1.2.840.113549.1.9.16.2.14"; + + public static String compareSignatures(String dest, String cmp) { + return compareSignatures(dest, cmp, new ReaderProperties(), new ReaderProperties()); + } public static String compareSignatures(String dest, String cmp, ReaderProperties destProperties, ReaderProperties cmpProperties) { + ITextTest.printOutCmpPdfNameAndDir(dest, cmp); + StringBuilder errorText = new StringBuilder(); try (PdfDocument outDocument = new PdfDocument(new PdfReader(dest, destProperties)); @@ -82,197 +98,242 @@ public static String compareSignatures(String dest, String cmp, ReaderProperties List signatures = cmpSigUtil.getSignatureNames(); for (String sig : signatures) { - boolean isFailed = false; ASN1Sequence outSignedData = (ASN1Sequence) getSignatureContent(sig, outSigUtil); ASN1Sequence cmpSignedData = (ASN1Sequence) getSignatureContent(sig, cmpSigUtil); - if (outSignedData.size() != cmpSignedData.size() || outSignedData.size() != 2) { - addError(errorText, "Signature top level elements count is incorrect (should be exactly 2):", - String.valueOf(outSignedData.size()), - String.valueOf(cmpSignedData.size())); - isFailed = true; - } - ASN1ObjectIdentifier outObjId = (ASN1ObjectIdentifier) outSignedData.getObjectAt(0); - ASN1ObjectIdentifier cmpObjId = (ASN1ObjectIdentifier) cmpSignedData.getObjectAt(0); - if (!outObjId.equals(cmpObjId) || !outObjId.getId().equals(OID_SIGNED_DATA)) { - addError(errorText, "Signatures object identifier is incorrect (should be " - + OID_SIGNED_DATA + ")", - String.valueOf(outObjId.getId()), - String.valueOf(cmpObjId.getId())); - isFailed = true; - } + boolean isEqual = compareSignatureObjects(outSignedData, cmpSignedData, errorText); - ASN1Sequence outContent = (ASN1Sequence) ((ASN1TaggedObject) outSignedData.getObjectAt(1)).getObject(); - ASN1Sequence cmpContent = (ASN1Sequence) ((ASN1TaggedObject) cmpSignedData.getObjectAt(1)).getObject(); - if (outContent.size() != cmpContent.size()) { - addError(errorText, "Signatures base elements counts are different", - String.valueOf(outContent.size()), - String.valueOf(cmpContent.size())); - isFailed = true; - } + if (!isEqual) { + String sigFileName = dest.substring(0, dest.lastIndexOf(".")); + String outSigFile = sigFileName + "_" + sig + "_out.txt"; + String cmpSigFile = sigFileName + "_" + sig + "_cmp.txt"; + writeToFile(outSigFile, sig + "\n" + ASN1Dump.dumpAsString(outSignedData, true) + "\n"); + writeToFile(cmpSigFile, sig + "\n" + ASN1Dump.dumpAsString(cmpSignedData, true) + "\n"); - int signerInfoIndex = getSignerInfoIndex(cmpContent); - if (outContent.getObjectAt(signerInfoIndex) instanceof ASN1TaggedObject) { - addError(errorText, "SignerInfo object indexes are different", null, null); - isFailed = true; + errorText.insert(0, "See signature output files: \nout: " + + UrlUtil.getNormalizedFileUriString(outSigFile) + "\ncmp: " + + UrlUtil.getNormalizedFileUriString(cmpSigFile) + "\n"); } + } + } catch (Exception e) { + errorText.append(e.getMessage()); + } - for (int i = 0; i < cmpContent.size(); i++) { + return errorText.toString().isEmpty() ? null : errorText.toString(); + } - // SignerInfo objects will be compared separately - if (i == signerInfoIndex) { - continue; - } + private static boolean compareSignatureObjects(ASN1Sequence outSignedData, ASN1Sequence cmpSignedData, StringBuilder errorText) { + if (outSignedData.size() != cmpSignedData.size() || outSignedData.size() != 2) { + addError(errorText, "Signature top level elements count is incorrect (should be exactly 2):", + String.valueOf(outSignedData.size()), + String.valueOf(cmpSignedData.size())); + return false; + } - if (!cmpContent.getObjectAt(i).equals(outContent.getObjectAt(i))) { - addError(errorText, "SignedData objects are different", null, null); - isFailed = true; - } - } + ASN1ObjectIdentifier outObjId = (ASN1ObjectIdentifier) outSignedData.getObjectAt(0); + ASN1ObjectIdentifier cmpObjId = (ASN1ObjectIdentifier) cmpSignedData.getObjectAt(0); + if (!outObjId.equals(cmpObjId) || !outObjId.getId().equals(OID_SIGNED_DATA)) { + addError(errorText, "Signatures object identifier is incorrect (should be " + + OID_SIGNED_DATA + ")", + String.valueOf(outObjId.getId()), + String.valueOf(cmpObjId.getId())); + return false; + } - ASN1Set cmpSignerInfos = (ASN1Set) cmpContent.getObjectAt(signerInfoIndex); - ASN1Set outSignerInfos = (ASN1Set) outContent.getObjectAt(signerInfoIndex); + ASN1Sequence outContent = (ASN1Sequence) ((ASN1TaggedObject) outSignedData.getObjectAt(1)).getObject(); + ASN1Sequence cmpContent = (ASN1Sequence) ((ASN1TaggedObject) cmpSignedData.getObjectAt(1)).getObject(); + if (outContent.size() != cmpContent.size()) { + addError(errorText, "Signatures base elements counts are different", + String.valueOf(outContent.size()), + String.valueOf(cmpContent.size())); + return false; + } - // Currently, iText signature validation mechanism do not support signatures, - // containing more than one SignerInfo entry. However, it is still valid signature. - if (cmpSignerInfos.size() != outSignerInfos.size() || cmpSignerInfos.size() != 1) { - addError(errorText, "Incorrect SignerInfos objects count", String.valueOf(outSignerInfos.size()), - String.valueOf(cmpSignerInfos.size())); - isFailed = true; - } + int signerInfoIndex = getSignerInfoIndex(cmpContent); + if (!(outContent.getObjectAt(signerInfoIndex) instanceof ASN1Set)) { + addError(errorText, "SignerInfo object indexes are different", null, null); + return false; + } - ASN1Sequence outSignerInfo = (ASN1Sequence) cmpSignerInfos.getObjectAt(0); - ASN1Sequence cmpSignerInfo = (ASN1Sequence) outSignerInfos.getObjectAt(0); - if (cmpSignerInfo.size() != outSignerInfo.size()) { - addError(errorText, "Incorrect SignerInfo entries count", String.valueOf(outSignerInfo.size()), - String.valueOf(cmpSignerInfo.size())); - isFailed = true; - } + for (int i = 0; i < cmpContent.size(); i++) { - for (int i = 0; i < cmpSignerInfo.size(); i++) { - - // Skipping comparison of ASN1OctetString fields in SignerInfo. SignerInfo is expected to have - // a single field of ASN1OctetString which is SignatureValue, that is expected to be - // different in each signature instance. - if (outSignerInfo.getObjectAt(i) instanceof ASN1OctetString) { - if (cmpSignerInfo.getObjectAt(i) instanceof ASN1OctetString) { - continue; - } else { - addError(errorText, "Signature values indexes are different!", null, null); - isFailed = true; - } - } - - if (!isFailed) { - isFailed = compareAsn1Structures(outSignerInfo.getObjectAt(i).toASN1Primitive(), - cmpSignerInfo.getObjectAt(i).toASN1Primitive(), errorText); - } - } + // SignerInfo objects will be compared separately + if (i == signerInfoIndex) { + continue; + } - if (isFailed) { - String sigFileName = dest.substring(0, dest.lastIndexOf(".")); - String outSigFile = sigFileName + "_out.txt"; - String cmpSigFile = sigFileName + "_cmp.txt"; - writeToFile(outSigFile, sig + "\n" + ASN1Dump.dumpAsString(outSignedData, true)+ "\n"); - writeToFile(cmpSigFile, sig + "\n" + ASN1Dump.dumpAsString(cmpSignedData, true)+ "\n"); + // Sequences and sets related to timestamp token info should be ignored. + if (OID_TST_INFO.equals(getASN1ObjectId(cmpContent.getObjectAt(i).toASN1Primitive())) && + OID_TST_INFO.equals(getASN1ObjectId(outContent.getObjectAt(i).toASN1Primitive()))) { + continue; + } - errorText.insert(0, "See signature output files: \nout: " - + UrlUtil.getNormalizedFileUriString(outSigFile) + "\ncmp: " - + UrlUtil.getNormalizedFileUriString(cmpSigFile) + "\n"); - } + if (!cmpContent.getObjectAt(i).equals(outContent.getObjectAt(i))) { + addError(errorText, "SignedData objects are different", null, null); + return false; } - } catch (Exception e) { - errorText.append(e.getMessage()); } - if (!errorText.toString().isEmpty()) { - return errorText.toString(); - } else { - return null; - } - } + ASN1Set cmpSignerInfos = (ASN1Set) cmpContent.getObjectAt(signerInfoIndex); + ASN1Set outSignerInfos = (ASN1Set) outContent.getObjectAt(signerInfoIndex); - public static String compareSignatures(String dest, String cmp) { - return compareSignatures(dest, cmp, new ReaderProperties(), new ReaderProperties()); - } + // Currently, iText signature validation mechanism do not support signatures, + // containing more than one SignerInfo entry. However, it is still valid signature. + if (cmpSignerInfos.size() != outSignerInfos.size() || cmpSignerInfos.size() != 1) { + addError(errorText, "Incorrect SignerInfos objects count", String.valueOf(outSignerInfos.size()), + String.valueOf(cmpSignerInfos.size())); + return false; + } - private static void writeToFile(String path, String content) throws IOException { - try (FileWriter writer = new FileWriter(path, true)) { - writer.write(content); + ASN1Sequence outSignerInfo = (ASN1Sequence) cmpSignerInfos.getObjectAt(0); + ASN1Sequence cmpSignerInfo = (ASN1Sequence) outSignerInfos.getObjectAt(0); + if (cmpSignerInfo.size() != outSignerInfo.size()) { + addError(errorText, "Incorrect SignerInfo entries count", String.valueOf(outSignerInfo.size()), + String.valueOf(cmpSignerInfo.size())); + return false; } - } - private static int getSignerInfoIndex(ASN1Sequence baseElement) { - for (int i = 3; i < baseElement.size(); i++) { - if (!(baseElement.getObjectAt(i) instanceof ASN1TaggedObject)) { - return i; + for (int i = 0; i < cmpSignerInfo.size(); i++) { + + // Skipping comparison of ASN1OctetString fields in SignerInfo. SignerInfo is expected to have + // a single field of ASN1OctetString which is SignatureValue, that is expected to be + // different in each signature instance. + if (outSignerInfo.getObjectAt(i) instanceof ASN1OctetString) { + if (cmpSignerInfo.getObjectAt(i) instanceof ASN1OctetString) { + continue; + } else { + addError(errorText, "Signature values indexes are different!", null, null); + return false; + } + } + + if (!compareAsn1Structures( + outSignerInfo.getObjectAt(i).toASN1Primitive(), + cmpSignerInfo.getObjectAt(i).toASN1Primitive(), errorText)) { + return false; } } - throw new IllegalStateException("SignerInfo entry has not been found."); + return true; } private static boolean compareAsn1Structures(ASN1Primitive out, ASN1Primitive cmp, StringBuilder errorText) { - boolean isFailed = false; if (!out.getClass().equals(cmp.getClass())) { addError(errorText, "ASN1 objects types are different", out.getClass().getName(), cmp.getClass().getName()); - isFailed = true; + return false; } - if (cmp instanceof ASN1TaggedObject || cmp instanceof ASN1Sequence) { - ASN1Sequence cmpObject; - ASN1Sequence outObject; - if (cmp instanceof ASN1TaggedObject) { - ASN1TaggedObject cmpTag = (ASN1TaggedObject) cmp; - ASN1TaggedObject outTag = (ASN1TaggedObject) out; - if (!(cmpTag.getObject() instanceof ASN1Sequence)) { - if (!cmpTag.getObject().equals(outTag.getObject())) { - addError(errorText, "ASN1 objects are different", ASN1Dump.dumpAsString(outTag, true), - ASN1Dump.dumpAsString(cmpTag, true)); - isFailed = true; - } - - return isFailed; - } - - cmpObject = (ASN1Sequence) (cmpTag).getObject(); - outObject = (ASN1Sequence) (outTag).getObject(); - } else { - cmpObject = (ASN1Sequence) cmp; - outObject = (ASN1Sequence) out; + if (cmp instanceof ASN1TaggedObject) { + return compareAsn1Structures( + ((ASN1TaggedObject) cmp).getObject(), ((ASN1TaggedObject) out).getObject(), errorText); + } else if (cmp instanceof ASN1Sequence) { + if (!compareContainers(((ASN1Sequence) out).toArray(), ((ASN1Sequence) cmp).toArray(), errorText)) { + addError(errorText, "ASN1Sequence objects are different", null, null); + return false; } + } else if (cmp instanceof ASN1Set) { + if (!compareContainers(((ASN1Set) out).toArray(), ((ASN1Set) cmp).toArray(), errorText)) { + addError(errorText, "ASN1Set objects are different", null, null); + return false; + } + } else { + if (!cmp.equals(out)) { + addError(errorText, "ASN1 objects are different", + ASN1Dump.dumpAsString(out, true), ASN1Dump.dumpAsString(cmp, true)); + return false; + } + } + return true; + } - if (cmpObject.getObjectAt(0) instanceof ASN1ObjectIdentifier) { - ASN1ObjectIdentifier objectIdentifier = (ASN1ObjectIdentifier) (cmpObject.getObjectAt(0)); + private static boolean compareContainers(ASN1Encodable[] outArray, + ASN1Encodable[] cmpArray, StringBuilder errorText) { + if (cmpArray.length != outArray.length) { + addError(errorText, "Container lengths are different", + Integer.toString(outArray.length), Integer.toString(cmpArray.length)); + return false; + } - // Message digest should be ignored during comparing - if (objectIdentifier.getId().equals(OID_MESSAGE_DIGEST)) { - return isFailed; - } + String cmpASN1ObjectId = getASN1ObjectId(cmpArray); + String outASN1ObjectId = getASN1ObjectId(outArray); + if (!Objects.equals(cmpASN1ObjectId, outASN1ObjectId)) { + addError(errorText, "Containers ids are different", outASN1ObjectId, cmpASN1ObjectId); + return false; + } + + // Message digest, timestamp token info and signing time should be ignored during comparing. + if (OID_MESSAGE_DIGEST.equals(cmpASN1ObjectId) || + OID_TST_INFO.equals(cmpASN1ObjectId) || OID_SIGNING_TIME.equals(cmpASN1ObjectId)) { + return true; + } + // Signature timestamp attribute (nested timestamp signature) should be processed as separated signature. + if (OID_SIGNATURE_TIMESTAMP_ATTRIBUTE.equals(cmpASN1ObjectId)) { + return compareTimestampAttributes(outArray, cmpArray, errorText); + } + for (int i = 0; i < cmpArray.length; i++) { + if (!compareAsn1Structures(outArray[i].toASN1Primitive(), cmpArray[i].toASN1Primitive(), errorText)) { + return false; } - for (int i = 0; i < cmpObject.size(); i++) { - if (!isFailed) { - isFailed = compareAsn1Structures(outObject.getObjectAt(i).toASN1Primitive(), - cmpObject.getObjectAt(i).toASN1Primitive(), errorText); + } + return true; + } + + private static boolean compareTimestampAttributes(ASN1Encodable[] out, ASN1Encodable[] cmp, StringBuilder errorText) { + if (cmp.length == 2) { + if (cmp[1] instanceof ASN1Set && out[1] instanceof ASN1Set) { + ASN1Primitive outSequence = ((ASN1Set) out[1]).getObjectAt(0).toASN1Primitive(); + ASN1Primitive cmpSequence = ((ASN1Set) cmp[1]).getObjectAt(0).toASN1Primitive(); + + if (outSequence instanceof ASN1Sequence && cmpSequence instanceof ASN1Sequence) { + return compareSignatureObjects((ASN1Sequence) outSequence, (ASN1Sequence) cmpSequence, errorText); } } - } else if (cmp instanceof ASN1Set) { - ASN1Set cmpSet = (ASN1Set) cmp; - ASN1Set outSet = (ASN1Set) out; - if (!isFailed) { - isFailed = compareAsn1Structures(cmpSet.getObjectAt(0).toASN1Primitive(), - outSet.getObjectAt(0).toASN1Primitive(), errorText); - } - } else { - if (!cmp.equals(out)) { - addError(errorText, "ASN1 objects are different", ASN1Dump.dumpAsString(out, true), - ASN1Dump.dumpAsString(cmp, true)); - isFailed = true; + } + + addError(errorText, + "Signature timestamp attribute structure is invalid", Arrays.toString(out), Arrays.toString(cmp)); + return false; + } + + private static int getSignerInfoIndex(ASN1Sequence baseElement) { + for (int i = 3; i < baseElement.size(); i++) { + if (baseElement.getObjectAt(i) instanceof ASN1Set) { + return i; } } - return isFailed; + throw new IllegalStateException("SignerInfo entry has not been found."); + } + + private static String getASN1ObjectId(ASN1Primitive primitive) { + if (primitive instanceof ASN1Sequence) { + return getASN1ObjectId(((ASN1Sequence) primitive).toArray()); + } + if (primitive instanceof ASN1Set) { + return getASN1ObjectId(((ASN1Set) primitive).toArray()); + } + return null; + } + + private static String getASN1ObjectId(ASN1Encodable[] primitives) { + if (primitives.length != 0 && primitives[0] instanceof ASN1ObjectIdentifier) { + return ((ASN1ObjectIdentifier) primitives[0]).getId(); + } + return null; + } + + private static ASN1Primitive getSignatureContent(String signatureName, SignatureUtil util) throws IOException { + PdfSignature signature = util.getSignature(signatureName); + byte[] contents = signature.getContents().getValueBytes(); + ASN1InputStream inputStream = new ASN1InputStream(new ByteArrayInputStream(contents)); + return inputStream.readObject(); + } + + private static void writeToFile(String path, String content) throws IOException { + try (FileWriter writer = new FileWriter(path, true)) { + writer.write(content); + } } private static void addError(StringBuilder errorBuilder, String errorText, String out, String cmp) { @@ -287,11 +348,4 @@ private static void addError(StringBuilder errorBuilder, String errorText, Strin errorBuilder.append("\n\n"); } - - private static ASN1Primitive getSignatureContent(String signatureName, SignatureUtil util) throws IOException { - PdfSignature signature = util.getSignature(signatureName); - byte[] contents = signature.getContents().getValueBytes(); - ASN1InputStream inputStream = new ASN1InputStream(new ByteArrayInputStream(contents)); - return inputStream.readObject(); - } } diff --git a/sign/src/test/java/com/itextpdf/signatures/verify/CertificateVerificationClassTest.java b/sign/src/test/java/com/itextpdf/signatures/verify/CertificateVerificationClassTest.java index 06addb37d4..bd5ddcbb11 100644 --- a/sign/src/test/java/com/itextpdf/signatures/verify/CertificateVerificationClassTest.java +++ b/sign/src/test/java/com/itextpdf/signatures/verify/CertificateVerificationClassTest.java @@ -44,6 +44,9 @@ This file is part of the iText (R) project. import com.itextpdf.signatures.CertificateVerification; import com.itextpdf.signatures.VerificationException; +import com.itextpdf.signatures.testutils.client.TestTsaClient; +import com.itextpdf.test.annotations.LogMessage; +import com.itextpdf.test.annotations.LogMessages; import com.itextpdf.test.signutils.Pkcs12FileHelper; import com.itextpdf.test.ExtendedITextTest; import com.itextpdf.test.ITextTest; @@ -53,12 +56,17 @@ This file is part of the iText (R) project. import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; +import java.security.PrivateKey; import java.security.Security; -import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.CertificateException; +import java.util.Arrays; import java.util.List; + +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.cms.ContentInfo; import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.tsp.TimeStampToken; import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; @@ -67,6 +75,10 @@ This file is part of the iText (R) project. @Category(UnitTest.class) public class CertificateVerificationClassTest extends ExtendedITextTest { + + // Such messageTemplate is equal to any log message. This is required for porting reasons. + private static final String ANY_LOG_MESSAGE = "{0}"; + private static final String certsSrc = "./src/test/resources/com/itextpdf/signatures/certs/"; private static final char[] password = "testpass".toCharArray(); @@ -92,4 +104,45 @@ public void validCertificateChain01() throws CertificateException, NoSuchAlgorit Assert.assertTrue(verificationExceptions.isEmpty()); } + + @Test + public void timestampCertificateAndKeyStoreCorrespondTest() throws Exception { + String tsaCertFileName = certsSrc + "tsCertRsa.p12"; + + KeyStore caKeyStore = Pkcs12FileHelper.initStore(tsaCertFileName, password); + + Assert.assertTrue(verifyTimestampCertificates(tsaCertFileName, caKeyStore)); + } + + @Test + @LogMessages(messages = @LogMessage(messageTemplate = "certificate hash does not match certID hash.")) + public void timestampCertificateAndKeyStoreDoNotCorrespondTest() throws Exception { + String tsaCertFileName = certsSrc + "tsCertRsa.p12"; + String notTsaCertFileName = certsSrc + "rootRsa.p12"; + + KeyStore caKeyStore = Pkcs12FileHelper.initStore(notTsaCertFileName, password); + + Assert.assertFalse(verifyTimestampCertificates(tsaCertFileName, caKeyStore)); + } + + @Test + @LogMessages(messages = @LogMessage(messageTemplate = ANY_LOG_MESSAGE)) + public void keyStoreWithoutCertificatesTest() throws Exception { + String tsaCertFileName = certsSrc + "tsCertRsa.p12"; + + Assert.assertFalse(verifyTimestampCertificates(tsaCertFileName, null)); + } + + private static boolean verifyTimestampCertificates(String tsaClientCertificate, KeyStore caKeyStore) throws Exception { + Certificate[] tsaChain = Pkcs12FileHelper.readFirstChain(tsaClientCertificate, password); + PrivateKey tsaPrivateKey = Pkcs12FileHelper.readFirstKey(tsaClientCertificate, password, password); + + TestTsaClient testTsaClient = new TestTsaClient(Arrays.asList(tsaChain), tsaPrivateKey); + + byte[] tsaCertificateBytes = testTsaClient.getTimeStampToken(testTsaClient.getMessageDigest().digest()); + TimeStampToken timeStampToken = new TimeStampToken( + ContentInfo.getInstance(ASN1Sequence.getInstance(tsaCertificateBytes))); + + return CertificateVerification.verifyTimestampCertificates(timeStampToken, caKeyStore, null); + } } diff --git a/sign/src/test/java/com/itextpdf/signatures/verify/OcspCertificateVerificationTest.java b/sign/src/test/java/com/itextpdf/signatures/verify/OcspCertificateVerificationTest.java new file mode 100644 index 0000000000..c7ba7e19e1 --- /dev/null +++ b/sign/src/test/java/com/itextpdf/signatures/verify/OcspCertificateVerificationTest.java @@ -0,0 +1,109 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2021 iText Group NV + Authors: iText Software. + + This program is offered under a commercial and under the AGPL license. + For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + + AGPL licensing: + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +package com.itextpdf.signatures.verify; + +import com.itextpdf.signatures.CertificateVerification; +import com.itextpdf.signatures.testutils.client.TestOcspClient; +import com.itextpdf.test.ExtendedITextTest; +import com.itextpdf.test.annotations.LogMessage; +import com.itextpdf.test.annotations.LogMessages; +import com.itextpdf.test.annotations.type.UnitTest; +import com.itextpdf.test.signutils.Pkcs12FileHelper; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ocsp.BasicOCSPResponse; +import org.bouncycastle.cert.ocsp.BasicOCSPResp; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.security.PrivateKey; +import java.security.Security; +import java.security.cert.X509Certificate; + +@Category(UnitTest.class) +public class OcspCertificateVerificationTest extends ExtendedITextTest { + + // Such messageTemplate is equal to any log message. This is required for porting reasons. + private static final String ANY_LOG_MESSAGE = "{0}"; + + private static final String ocspCertsSrc = "./src/test/resources/com/itextpdf/signatures/verify/OcspCertificateVerificationTest/"; + + private static final String rootOcspCert = ocspCertsSrc + "ocspRootRsa.p12"; + private static final String signOcspCert = ocspCertsSrc + "ocspSignRsa.p12"; + private static final String notOcspAndOcspCert = ocspCertsSrc + "notOcspAndOcspCertificates.p12"; + + private static final char[] password = "testpass".toCharArray(); + private static final String ocspServiceUrl = "http://localhost:9000/demo/ocsp/ocsp-service"; + + private static X509Certificate checkCert; + private static X509Certificate rootCert; + + @BeforeClass + public static void before() throws Exception { + Security.addProvider(new BouncyCastleProvider()); + checkCert = (X509Certificate) Pkcs12FileHelper.readFirstChain(signOcspCert, password)[0]; + rootCert = (X509Certificate) Pkcs12FileHelper.readFirstChain(rootOcspCert, password)[0]; + } + + @Test + public void keyStoreWithRootOcspCertificateTest() throws Exception { + BasicOCSPResp response = getOcspResponse(); + + Assert.assertTrue(CertificateVerification.verifyOcspCertificates( + response, Pkcs12FileHelper.initStore(rootOcspCert, password), null)); + } + + @Test + public void keyStoreWithSignOcspCertificateTest() throws Exception { + BasicOCSPResp response = getOcspResponse(); + + Assert.assertFalse(CertificateVerification.verifyOcspCertificates( + response, Pkcs12FileHelper.initStore(signOcspCert, password), null)); + } + + @Test + public void keyStoreWithNotOcspAndOcspCertificatesTest() throws Exception { + BasicOCSPResp response = getOcspResponse(); + + Assert.assertTrue(CertificateVerification.verifyOcspCertificates( + response, Pkcs12FileHelper.initStore(notOcspAndOcspCert, password), null)); + } + + @Test + @LogMessages(messages = @LogMessage(messageTemplate = ANY_LOG_MESSAGE)) + public void keyStoreWithNotOcspCertificateTest() throws Exception { + Assert.assertFalse(CertificateVerification.verifyOcspCertificates( + null, Pkcs12FileHelper.initStore(signOcspCert, password), null)); + } + + private static BasicOCSPResp getOcspResponse() throws Exception { + TestOcspClient testClient = new TestOcspClient(); + PrivateKey key = Pkcs12FileHelper.readFirstKey(rootOcspCert, password, password); + testClient.addBuilderForCertIssuer(rootCert, key); + byte[] ocspResponseBytes = testClient.getEncoded(checkCert, rootCert, ocspServiceUrl); + ASN1Primitive var2 = ASN1Primitive.fromByteArray(ocspResponseBytes); + return new BasicOCSPResp(BasicOCSPResponse.getInstance(var2)); + } +} diff --git a/sign/src/test/resources/com/itextpdf/signatures/LtvVerifierUnitTest/ltvDoc.pdf b/sign/src/test/resources/com/itextpdf/signatures/LtvVerifierUnitTest/ltvDoc.pdf new file mode 100644 index 0000000000..208c6e80b0 Binary files /dev/null and b/sign/src/test/resources/com/itextpdf/signatures/LtvVerifierUnitTest/ltvDoc.pdf differ diff --git a/sign/src/test/resources/com/itextpdf/signatures/PdfPKCS7Test/embeddedTimeStampCorruptedSignature.pdf b/sign/src/test/resources/com/itextpdf/signatures/PdfPKCS7Test/embeddedTimeStampCorruptedSignature.pdf new file mode 100644 index 0000000000..bfe017d983 Binary files /dev/null and b/sign/src/test/resources/com/itextpdf/signatures/PdfPKCS7Test/embeddedTimeStampCorruptedSignature.pdf differ diff --git a/sign/src/test/resources/com/itextpdf/signatures/PdfPKCS7Test/embeddedTimeStampSignature.pdf b/sign/src/test/resources/com/itextpdf/signatures/PdfPKCS7Test/embeddedTimeStampSignature.pdf new file mode 100644 index 0000000000..63ddd78900 Binary files /dev/null and b/sign/src/test/resources/com/itextpdf/signatures/PdfPKCS7Test/embeddedTimeStampSignature.pdf differ diff --git a/sign/src/test/resources/com/itextpdf/signatures/PdfPKCS7Test/simpleSignature.pdf b/sign/src/test/resources/com/itextpdf/signatures/PdfPKCS7Test/simpleSignature.pdf new file mode 100644 index 0000000000..d6fb2f0fcb Binary files /dev/null and b/sign/src/test/resources/com/itextpdf/signatures/PdfPKCS7Test/simpleSignature.pdf differ diff --git a/sign/src/test/resources/com/itextpdf/signatures/PdfPKCS7Test/timeStampSignature.pdf b/sign/src/test/resources/com/itextpdf/signatures/PdfPKCS7Test/timeStampSignature.pdf new file mode 100644 index 0000000000..fb52fb9954 Binary files /dev/null and b/sign/src/test/resources/com/itextpdf/signatures/PdfPKCS7Test/timeStampSignature.pdf differ diff --git a/sign/src/test/resources/com/itextpdf/signatures/pdfa/sRGB Color Space Profile.icm b/sign/src/test/resources/com/itextpdf/signatures/pdfa/sRGB Color Space Profile.icm new file mode 100644 index 0000000000..7f9d18d097 Binary files /dev/null and b/sign/src/test/resources/com/itextpdf/signatures/pdfa/sRGB Color Space Profile.icm differ diff --git a/sign/src/test/resources/com/itextpdf/signatures/sign/LtvSigTest/cmp_ltvEnabledTsTest01.pdf b/sign/src/test/resources/com/itextpdf/signatures/sign/LtvSigTest/cmp_ltvEnabledTsTest01.pdf index 0c57b33cca..f91bdc50ff 100644 Binary files a/sign/src/test/resources/com/itextpdf/signatures/sign/LtvSigTest/cmp_ltvEnabledTsTest01.pdf and b/sign/src/test/resources/com/itextpdf/signatures/sign/LtvSigTest/cmp_ltvEnabledTsTest01.pdf differ diff --git a/sign/src/test/resources/com/itextpdf/signatures/sign/LtvSigTest/cmp_secondLtvOriginalHasNoVriTs01.pdf b/sign/src/test/resources/com/itextpdf/signatures/sign/LtvSigTest/cmp_secondLtvOriginalHasNoVriTs01.pdf new file mode 100644 index 0000000000..d19bfec371 Binary files /dev/null and b/sign/src/test/resources/com/itextpdf/signatures/sign/LtvSigTest/cmp_secondLtvOriginalHasNoVriTs01.pdf differ diff --git a/sign/src/test/resources/com/itextpdf/signatures/sign/PadesSignatureLevelTest/cmp_padesSignatureLevelTTest01.pdf b/sign/src/test/resources/com/itextpdf/signatures/sign/PadesSignatureLevelTest/cmp_padesSignatureLevelTTest01.pdf new file mode 100644 index 0000000000..63ddd78900 Binary files /dev/null and b/sign/src/test/resources/com/itextpdf/signatures/sign/PadesSignatureLevelTest/cmp_padesSignatureLevelTTest01.pdf differ diff --git a/sign/src/test/resources/com/itextpdf/signatures/sign/PdfASigningTest/cmp_simpleSignature.pdf b/sign/src/test/resources/com/itextpdf/signatures/sign/PdfASigningTest/cmp_simpleSignature.pdf index 568094803c..2d9fb83ca9 100644 Binary files a/sign/src/test/resources/com/itextpdf/signatures/sign/PdfASigningTest/cmp_simpleSignature.pdf and b/sign/src/test/resources/com/itextpdf/signatures/sign/PdfASigningTest/cmp_simpleSignature.pdf differ diff --git a/sign/src/test/resources/com/itextpdf/signatures/sign/PdfASigningTest/simplePdfA2Document.pdf b/sign/src/test/resources/com/itextpdf/signatures/sign/PdfASigningTest/simplePdfA2Document.pdf new file mode 100644 index 0000000000..a9c5f7fcf2 Binary files /dev/null and b/sign/src/test/resources/com/itextpdf/signatures/sign/PdfASigningTest/simplePdfA2Document.pdf differ diff --git a/sign/src/test/resources/com/itextpdf/signatures/sign/SequentialSignaturesTest/cmp_secondSignOfTagged.pdf b/sign/src/test/resources/com/itextpdf/signatures/sign/SequentialSignaturesTest/cmp_secondSignOfTagged.pdf new file mode 100644 index 0000000000..83daf0b55a Binary files /dev/null and b/sign/src/test/resources/com/itextpdf/signatures/sign/SequentialSignaturesTest/cmp_secondSignOfTagged.pdf differ diff --git a/sign/src/test/resources/com/itextpdf/signatures/sign/SequentialSignaturesTest/cmp_sequentialSignOfFileWithAnnots.pdf b/sign/src/test/resources/com/itextpdf/signatures/sign/SequentialSignaturesTest/cmp_sequentialSignOfFileWithAnnots.pdf index 5d67acd859..d0c88b069e 100644 Binary files a/sign/src/test/resources/com/itextpdf/signatures/sign/SequentialSignaturesTest/cmp_sequentialSignOfFileWithAnnots.pdf and b/sign/src/test/resources/com/itextpdf/signatures/sign/SequentialSignaturesTest/cmp_sequentialSignOfFileWithAnnots.pdf differ diff --git a/sign/src/test/resources/com/itextpdf/signatures/sign/SimpleSigningTest/cmp_signedWithTempFile.pdf b/sign/src/test/resources/com/itextpdf/signatures/sign/SimpleSigningTest/cmp_signedWithTempFile.pdf new file mode 100644 index 0000000000..8e1cadd8f6 Binary files /dev/null and b/sign/src/test/resources/com/itextpdf/signatures/sign/SimpleSigningTest/cmp_signedWithTempFile.pdf differ diff --git a/sign/src/test/resources/com/itextpdf/signatures/sign/SimpleSigningTest/cmp_signedWithoutPKey.pdf b/sign/src/test/resources/com/itextpdf/signatures/sign/SimpleSigningTest/cmp_signedWithoutPKey.pdf new file mode 100644 index 0000000000..0e7f05fe5c Binary files /dev/null and b/sign/src/test/resources/com/itextpdf/signatures/sign/SimpleSigningTest/cmp_signedWithoutPKey.pdf differ diff --git a/sign/src/test/resources/com/itextpdf/signatures/sign/SimpleSigningTest/emptySignatureWithoutPKey.pdf b/sign/src/test/resources/com/itextpdf/signatures/sign/SimpleSigningTest/emptySignatureWithoutPKey.pdf new file mode 100644 index 0000000000..ab737b0110 Binary files /dev/null and b/sign/src/test/resources/com/itextpdf/signatures/sign/SimpleSigningTest/emptySignatureWithoutPKey.pdf differ diff --git a/sign/src/test/resources/com/itextpdf/signatures/sign/TimestampSigTest/cmp_timestampTest01.pdf b/sign/src/test/resources/com/itextpdf/signatures/sign/TimestampSigTest/cmp_timestampTest01.pdf index 4fbbcaa35e..fb52fb9954 100644 Binary files a/sign/src/test/resources/com/itextpdf/signatures/sign/TimestampSigTest/cmp_timestampTest01.pdf and b/sign/src/test/resources/com/itextpdf/signatures/sign/TimestampSigTest/cmp_timestampTest01.pdf differ diff --git a/sign/src/test/resources/com/itextpdf/signatures/verify/OcspCertificateVerificationTest/notOcspAndOcspCertificates.p12 b/sign/src/test/resources/com/itextpdf/signatures/verify/OcspCertificateVerificationTest/notOcspAndOcspCertificates.p12 new file mode 100644 index 0000000000..04896d234c Binary files /dev/null and b/sign/src/test/resources/com/itextpdf/signatures/verify/OcspCertificateVerificationTest/notOcspAndOcspCertificates.p12 differ diff --git a/sign/src/test/resources/com/itextpdf/signatures/verify/OcspCertificateVerificationTest/ocspRootRsa.p12 b/sign/src/test/resources/com/itextpdf/signatures/verify/OcspCertificateVerificationTest/ocspRootRsa.p12 new file mode 100644 index 0000000000..c46159fd11 Binary files /dev/null and b/sign/src/test/resources/com/itextpdf/signatures/verify/OcspCertificateVerificationTest/ocspRootRsa.p12 differ diff --git a/sign/src/test/resources/com/itextpdf/signatures/verify/OcspCertificateVerificationTest/ocspSignRsa.p12 b/sign/src/test/resources/com/itextpdf/signatures/verify/OcspCertificateVerificationTest/ocspSignRsa.p12 new file mode 100644 index 0000000000..fa1606c325 Binary files /dev/null and b/sign/src/test/resources/com/itextpdf/signatures/verify/OcspCertificateVerificationTest/ocspSignRsa.p12 differ diff --git a/styled-xml-parser/pom.xml b/styled-xml-parser/pom.xml index bedf05319f..ff6a99d6d0 100644 --- a/styled-xml-parser/pom.xml +++ b/styled-xml-parser/pom.xml @@ -4,7 +4,7 @@ com.itextpdf root - 7.2.0 + 7.2.1 styled-xml-parser iText 7 - Styled XML Parser diff --git a/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/css/parse/CssSelectorParser.java b/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/css/parse/CssSelectorParser.java index eb51253015..609e0573b1 100644 --- a/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/css/parse/CssSelectorParser.java +++ b/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/css/parse/CssSelectorParser.java @@ -43,6 +43,7 @@ This file is part of the iText (R) project. package com.itextpdf.styledxmlparser.css.parse; import com.itextpdf.commons.utils.MessageFormatUtil; +import com.itextpdf.styledxmlparser.exceptions.StyledXmlParserExceptionMessage; import com.itextpdf.styledxmlparser.logs.StyledXmlParserLogMessageConstant; import com.itextpdf.styledxmlparser.css.selector.item.CssAttributeSelectorItem; import com.itextpdf.styledxmlparser.css.selector.item.CssClassSelectorItem; @@ -129,7 +130,9 @@ public static List parseSelectorItems(String selector) { case '>': case '~': if (selectorItems.size() == 0) { - throw new IllegalArgumentException(MessageFormatUtil.format("Invalid token detected in the start of the selector string: {0}", firstChar)); + throw new IllegalArgumentException(MessageFormatUtil.format( + StyledXmlParserExceptionMessage.INVALID_TOKEN_AT_THE_BEGINNING_OF_SELECTOR, + firstChar)); } ICssSelectorItem lastItem = selectorItems.get(selectorItems.size() - 1); CssSeparatorSelectorItem curItem = new CssSeparatorSelectorItem(firstChar); diff --git a/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/PropertiesState.java b/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/BlockState.java similarity index 94% rename from styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/PropertiesState.java rename to styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/BlockState.java index 3d06ada266..c665fe931d 100644 --- a/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/PropertiesState.java +++ b/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/BlockState.java @@ -45,8 +45,7 @@ This file is part of the iText (R) project. /** * {@link IParserState} implementation for the block state. */ -// TODO rename to BLOCK -class PropertiesState implements IParserState { +class BlockState implements IParserState { /** * The state machine that parses the CSS. @@ -54,11 +53,11 @@ class PropertiesState implements IParserState { private CssParserStateController controller; /** - * Creates a new {@link PropertiesState} instance. + * Creates a new {@link BlockState} instance. * * @param controller the state machine that parses the CSS */ - PropertiesState(CssParserStateController controller) { + BlockState(CssParserStateController controller) { this.controller = controller; } diff --git a/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/CssParserStateController.java b/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/CssParserStateController.java index d5ca3b152d..a921c18fc1 100644 --- a/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/CssParserStateController.java +++ b/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/CssParserStateController.java @@ -163,7 +163,7 @@ public CssParserStateController(String baseUrl) { commendInnerState = new CommentInnerState(this); unknownState = new UnknownState(this); ruleState = new RuleState(this); - propertiesState = new PropertiesState(this); + propertiesState = new BlockState(this); atRuleBlockState = new AtRuleBlockState(this); conditionalGroupAtRuleBlockState = new ConditionalGroupAtRuleBlockState(this); diff --git a/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/exceptions/StyledXmlParserExceptionMessage.java b/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/exceptions/StyledXmlParserExceptionMessage.java index 31661fc68b..10302f470e 100644 --- a/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/exceptions/StyledXmlParserExceptionMessage.java +++ b/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/exceptions/StyledXmlParserExceptionMessage.java @@ -26,6 +26,8 @@ This file is part of the iText (R) project. * Class containing constants to be used in exceptions in the SXP module. */ public final class StyledXmlParserExceptionMessage { + public static final String INVALID_TOKEN_AT_THE_BEGINNING_OF_SELECTOR + = "Invalid token detected at the beginning of the selector string: \"{0}\""; public static final String READING_BYTE_LIMIT_MUST_NOT_BE_LESS_ZERO = "The reading byte limit argument must not be less than zero."; private StyledXmlParserExceptionMessage() { diff --git a/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/jsoup/nodes/Element.java b/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/jsoup/nodes/Element.java index d7912cb071..13fa18f374 100644 --- a/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/jsoup/nodes/Element.java +++ b/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/jsoup/nodes/Element.java @@ -1259,31 +1259,7 @@ public Elements getAllElements() { */ public String text() { final StringBuilder accum = StringUtil.borrowBuilder(); - NodeTraversor.traverse(new NodeVisitor() { - public void head(Node node, int depth) { - if (node instanceof TextNode) { - TextNode textNode = (TextNode) node; - appendNormalisedText(accum, textNode); - } else if (node instanceof Element) { - Element element = (Element) node; - if (accum.length() > 0 && - (element.isBlock() || element.tag.getName().equals("br")) && - !TextNode.lastCharIsWhitespace(accum)) - accum.append(' '); - } - } - - public void tail(Node node, int depth) { - // make sure there is a space between block tags and immediately following text nodes
One
Two should be "One Two". - if (node instanceof Element) { - Element element = (Element) node; - if (element.isBlock() && (node.nextSibling() instanceof TextNode) && !TextNode.lastCharIsWhitespace(accum)) - accum.append(' '); - } - - } - }, this); - + NodeTraversor.traverse(new TextNodeVisitor(accum), this); return StringUtil.releaseBuilder(accum).trim(); } @@ -1296,17 +1272,7 @@ public void tail(Node node, int depth) { */ public String wholeText() { final StringBuilder accum = StringUtil.borrowBuilder(); - NodeTraversor.traverse(new NodeVisitor() { - public void head(Node node, int depth) { - if (node instanceof TextNode) { - TextNode textNode = (TextNode) node; - accum.append(textNode.getWholeText()); - } - } - - public void tail(Node node, int depth) { - } - }, this); + NodeTraversor.traverse(new WholeTextNodeVisitor(accum), this); return StringUtil.releaseBuilder(accum); } @@ -1756,4 +1722,55 @@ private boolean isInlineable(Document.OutputSettings out) { && previousSibling() != null && !out.outline(); } + + private static final class TextNodeVisitor implements NodeVisitor { + private StringBuilder accum; + + TextNodeVisitor(StringBuilder accum) { + this.accum = accum; + } + + public void head(Node node, int depth) { + if (node instanceof TextNode) { + TextNode textNode = (TextNode) node; + appendNormalisedText(accum, textNode); + } else if (node instanceof Element) { + Element element = (Element) node; + if (accum.length() > 0 && + (element.isBlock() || element.tag.getName().equals("br")) && + !TextNode.lastCharIsWhitespace(accum)) + accum.append(' '); + } + } + + public void tail(Node node, int depth) { + // make sure there is a space between block tags and immediately + // following text nodes
One
Two should be "One Two". + if (node instanceof Element) { + Element element = (Element) node; + if (element.isBlock() && (node.nextSibling() instanceof TextNode) + && !TextNode.lastCharIsWhitespace(accum)) + accum.append(' '); + } + + } + } + + private static final class WholeTextNodeVisitor implements NodeVisitor { + private StringBuilder accum; + + WholeTextNodeVisitor(StringBuilder accum) { + this.accum = accum; + } + + public void head(Node node, int depth) { + if (node instanceof TextNode) { + TextNode textNode = (TextNode) node; + accum.append(textNode.getWholeText()); + } + } + + public void tail(Node node, int depth) { + } + } } diff --git a/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/jsoup/parser/HtmlTreeBuilderState.java b/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/jsoup/parser/HtmlTreeBuilderState.java index 6cb8108dd7..e517c6f9dd 100644 --- a/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/jsoup/parser/HtmlTreeBuilderState.java +++ b/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/jsoup/parser/HtmlTreeBuilderState.java @@ -37,7 +37,129 @@ This file is part of the iText (R) project. */ abstract class HtmlTreeBuilderState { - public static HtmlTreeBuilderState Initial = new HtmlTreeBuilderState() { + public static HtmlTreeBuilderState Initial = new InitialBS(); + + public static HtmlTreeBuilderState BeforeHtml = new BeforeHtmlBS(); + + public static HtmlTreeBuilderState BeforeHead = new BeforeHeadBS(); + + public static HtmlTreeBuilderState InHead = new InHeadBS(); + + public static HtmlTreeBuilderState InHeadNoscript = new InHeadNoScriptBS(); + + public static HtmlTreeBuilderState AfterHead = new AfterHeadBS(); + + public static HtmlTreeBuilderState InBody = new InBodyBS(); + + public static HtmlTreeBuilderState Text = new TextBS(); + + public static HtmlTreeBuilderState InTable = new InTableBS(); + + public static HtmlTreeBuilderState InTableText = new InTableTextBS(); + + public static HtmlTreeBuilderState InCaption = new InCaptionBS(); + + public static HtmlTreeBuilderState InColumnGroup = new InColumnGroupBS(); + + public static HtmlTreeBuilderState InTableBody = new InTableBodyBS(); + + public static HtmlTreeBuilderState InRow = new InRowBS(); + + public static HtmlTreeBuilderState InCell = new InCellBS(); + + public static HtmlTreeBuilderState InSelect = new InSelectBS(); + + public static HtmlTreeBuilderState InSelectInTable = new InSelectInTableBS(); + + public static HtmlTreeBuilderState AfterBody = new AfterBodyBS(); + + public static HtmlTreeBuilderState InFrameset = new InFrameSetBS(); + + public static HtmlTreeBuilderState AfterFrameset = new AfterFrameSetBS(); + + public static HtmlTreeBuilderState AfterAfterBody = new AfterAfterBodyBS(); + + public static HtmlTreeBuilderState AfterAfterFrameset = new AfterAfterFrameSetBS(); + + public static HtmlTreeBuilderState ForeignContent = new ForeignContentBS(); + + private static final String nullString = String.valueOf('\u0000'); + + abstract boolean process(Token t, HtmlTreeBuilder tb); + + private static boolean isWhitespace(Token t) { + if (t.isCharacter()) { + String data = t.asCharacter().getData(); + return StringUtil.isBlank(data); + } + return false; + } + + private static boolean isWhitespace(String data) { + return StringUtil.isBlank(data); + } + + private static void handleRcData(Token.StartTag startTag, HtmlTreeBuilder tb) { + tb.tokeniser.transition(TokeniserState.Rcdata); + tb.markInsertionMode(); + tb.transition(Text); + tb.insert(startTag); + } + + private static void handleRawtext(Token.StartTag startTag, HtmlTreeBuilder tb) { + tb.tokeniser.transition(TokeniserState.Rawtext); + tb.markInsertionMode(); + tb.transition(Text); + tb.insert(startTag); + } + + // lists of tags to search through + static final class Constants { + static final String[] InHeadEmpty = new String[]{"base", "basefont", "bgsound", "command", "link"}; + static final String[] InHeadRaw = new String[]{"noframes", "style"}; + static final String[] InHeadEnd = new String[]{"body", "br", "html"}; + static final String[] AfterHeadBody = new String[]{"body", "html"}; + static final String[] BeforeHtmlToHead = new String[]{"body", "br", "head", "html", }; + static final String[] InHeadNoScriptHead = new String[]{"basefont", "bgsound", "link", "meta", "noframes", "style"}; + static final String[] InBodyStartToHead = new String[]{"base", "basefont", "bgsound", "command", "link", "meta", "noframes", "script", "style", "title"}; + static final String[] InBodyStartPClosers = new String[]{"address", "article", "aside", "blockquote", "center", "details", "dir", "div", "dl", + "fieldset", "figcaption", "figure", "footer", "header", "hgroup", "menu", "nav", "ol", + "p", "section", "summary", "ul"}; + static final String[] Headings = new String[]{"h1", "h2", "h3", "h4", "h5", "h6"}; + static final String[] InBodyStartLiBreakers = new String[]{"address", "div", "p"}; + static final String[] DdDt = new String[]{"dd", "dt"}; + static final String[] Formatters = new String[]{"b", "big", "code", "em", "font", "i", "s", "small", "strike", "strong", "tt", "u"}; + static final String[] InBodyStartApplets = new String[]{"applet", "marquee", "object"}; + static final String[] InBodyStartEmptyFormatters = new String[]{"area", "br", "embed", "img", "keygen", "wbr"}; + static final String[] InBodyStartMedia = new String[]{"param", "source", "track"}; + static final String[] InBodyStartInputAttribs = new String[]{"action", "name", "prompt"}; + static final String[] InBodyStartDrop = new String[]{"caption", "col", "colgroup", "frame", "head", "tbody", "td", "tfoot", "th", "thead", "tr"}; + static final String[] InBodyEndClosers = new String[]{"address", "article", "aside", "blockquote", "button", "center", "details", "dir", "div", + "dl", "fieldset", "figcaption", "figure", "footer", "header", "hgroup", "listing", "menu", + "nav", "ol", "pre", "section", "summary", "ul"}; + static final String[] InBodyEndAdoptionFormatters = new String[]{"a", "b", "big", "code", "em", "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u"}; + static final String[] InBodyEndTableFosters = new String[]{"table", "tbody", "tfoot", "thead", "tr"}; + static final String[] InTableToBody = new String[]{"tbody", "tfoot", "thead"}; + static final String[] InTableAddBody = new String[]{"td", "th", "tr"}; + static final String[] InTableToHead = new String[]{"script", "style"}; + static final String[] InCellNames = new String[]{"td", "th"}; + static final String[] InCellBody = new String[]{"body", "caption", "col", "colgroup", "html"}; + static final String[] InCellTable = new String[]{ "table", "tbody", "tfoot", "thead", "tr"}; + static final String[] InCellCol = new String[]{"caption", "col", "colgroup", "tbody", "td", "tfoot", "th", "thead", "tr"}; + static final String[] InTableEndErr = new String[]{"body", "caption", "col", "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr"}; + static final String[] InTableFoster = new String[]{"table", "tbody", "tfoot", "thead", "tr"}; + static final String[] InTableBodyExit = new String[]{"caption", "col", "colgroup", "tbody", "tfoot", "thead"}; + static final String[] InTableBodyEndIgnore = new String[]{"body", "caption", "col", "colgroup", "html", "td", "th", "tr"}; + static final String[] InRowMissing = new String[]{"caption", "col", "colgroup", "tbody", "tfoot", "thead", "tr"}; + static final String[] InRowIgnore = new String[]{"body", "caption", "col", "colgroup", "html", "td", "th"}; + static final String[] InSelectEnd = new String[]{"input", "keygen", "textarea"}; + static final String[] InSelecTableEnd = new String[]{"caption", "table", "tbody", "td", "tfoot", "th", "thead", "tr"}; + static final String[] InTableEndIgnore = new String[]{"tbody", "tfoot", "thead"}; + static final String[] InHeadNoscriptIgnore = new String[]{"head", "noscript"}; + static final String[] InCaptionIgnore = new String[]{"body", "col", "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr"}; + } + + private static final class InitialBS extends HtmlTreeBuilderState { @Override public String toString() { @@ -64,9 +186,9 @@ boolean process(Token t, HtmlTreeBuilder tb) { } return true; } - }; + } - public static HtmlTreeBuilderState BeforeHtml = new HtmlTreeBuilderState() { + private static final class BeforeHtmlBS extends HtmlTreeBuilderState { @Override public String toString() { @@ -100,9 +222,9 @@ private boolean anythingElse(Token t, HtmlTreeBuilder tb) { tb.transition(BeforeHead); return tb.process(t); } - }; + } - public static HtmlTreeBuilderState BeforeHead = new HtmlTreeBuilderState() { + private static final class BeforeHeadBS extends HtmlTreeBuilderState { @Override public String toString() { @@ -135,9 +257,9 @@ boolean process(Token t, HtmlTreeBuilder tb) { } return true; } - }; + } - public static HtmlTreeBuilderState InHead = new HtmlTreeBuilderState() { + private static final class InHeadBS extends HtmlTreeBuilderState { @Override public String toString() { @@ -214,9 +336,9 @@ private boolean anythingElse(Token t, TreeBuilder tb) { tb.processEndTag("head"); return tb.process(t); } - }; + } - public static HtmlTreeBuilderState InHeadNoscript = new HtmlTreeBuilderState() { + private static final class InHeadNoScriptBS extends HtmlTreeBuilderState { @Override public String toString() { @@ -253,9 +375,9 @@ private boolean anythingElse(Token t, HtmlTreeBuilder tb) { tb.insert(new Token.Character().data(t.toString())); return true; } - }; + } - public static HtmlTreeBuilderState AfterHead = new HtmlTreeBuilderState() { + private static final class AfterHeadBS extends HtmlTreeBuilderState { @Override public String toString() { @@ -311,9 +433,9 @@ private boolean anythingElse(Token t, HtmlTreeBuilder tb) { tb.framesetOk(true); return tb.process(t); } - }; + } - public static HtmlTreeBuilderState InBody = new HtmlTreeBuilderState() { + private static final class InBodyBS extends HtmlTreeBuilderState { @Override public String toString() { @@ -938,9 +1060,9 @@ else if (!tb.onStack(formatEl)) { } return true; } - }; + } - public static HtmlTreeBuilderState Text = new HtmlTreeBuilderState() { + private static final class TextBS extends HtmlTreeBuilderState { @Override public String toString() { @@ -964,9 +1086,9 @@ boolean process(Token t, HtmlTreeBuilder tb) { } return true; } - }; + } - public static HtmlTreeBuilderState InTable = new HtmlTreeBuilderState() { + private static final class InTableBS extends HtmlTreeBuilderState { @Override public String toString() { @@ -1070,9 +1192,9 @@ boolean anythingElse(Token t, HtmlTreeBuilder tb) { } return processed; } - }; + } - public static HtmlTreeBuilderState InTableText = new HtmlTreeBuilderState() { + private static final class InTableTextBS extends HtmlTreeBuilderState { @Override public String toString() { @@ -1111,9 +1233,9 @@ boolean process(Token t, HtmlTreeBuilder tb) { } return true; } - }; + } - public static HtmlTreeBuilderState InCaption = new HtmlTreeBuilderState() { + private static final class InCaptionBS extends HtmlTreeBuilderState { @Override public String toString() { @@ -1151,9 +1273,9 @@ boolean process(Token t, HtmlTreeBuilder tb) { } return true; } - }; + } - public static HtmlTreeBuilderState InColumnGroup = new HtmlTreeBuilderState() { + private static final class InColumnGroupBS extends HtmlTreeBuilderState { @Override public String toString() { @@ -1214,9 +1336,9 @@ private boolean anythingElse(Token t, TreeBuilder tb) { return tb.process(t); return true; } - }; + } - public static HtmlTreeBuilderState InTableBody = new HtmlTreeBuilderState() { + private static final class InTableBodyBS extends HtmlTreeBuilderState { @Override public String toString() { @@ -1284,9 +1406,9 @@ private boolean exitTableBody(Token t, HtmlTreeBuilder tb) { private boolean anythingElse(Token t, HtmlTreeBuilder tb) { return tb.process(t, InTable); } - }; + } - public static HtmlTreeBuilderState InRow = new HtmlTreeBuilderState() { + private static final class InRowBS extends HtmlTreeBuilderState { @Override public String toString() { @@ -1355,9 +1477,9 @@ private boolean handleMissingTr(Token t, TreeBuilder tb) { else return false; } - }; + } - public static HtmlTreeBuilderState InCell = new HtmlTreeBuilderState() { + private static final class InCellBS extends HtmlTreeBuilderState { @Override public String toString() { @@ -1418,9 +1540,9 @@ private void closeCell(HtmlTreeBuilder tb) { else tb.processEndTag("th"); // only here if th or td in scope } - }; + } - public static HtmlTreeBuilderState InSelect = new HtmlTreeBuilderState() { + private static final class InSelectBS extends HtmlTreeBuilderState { @Override public String toString() { @@ -1520,9 +1642,9 @@ private boolean anythingElse(Token t, HtmlTreeBuilder tb) { tb.error(this); return false; } - }; + } - public static HtmlTreeBuilderState InSelectInTable = new HtmlTreeBuilderState() { + private static final class InSelectInTableBS extends HtmlTreeBuilderState { @Override public String toString() { @@ -1545,9 +1667,9 @@ boolean process(Token t, HtmlTreeBuilder tb) { return tb.process(t, InSelect); } } - }; + } - public static HtmlTreeBuilderState AfterBody = new HtmlTreeBuilderState() { + private static final class AfterBodyBS extends HtmlTreeBuilderState { @Override public String toString() { @@ -1580,9 +1702,9 @@ boolean process(Token t, HtmlTreeBuilder tb) { } return true; } - }; + } - public static HtmlTreeBuilderState InFrameset = new HtmlTreeBuilderState() { + private static final class InFrameSetBS extends HtmlTreeBuilderState { @Override public String toString() { @@ -1635,9 +1757,9 @@ boolean process(Token t, HtmlTreeBuilder tb) { } return true; } - }; + } - public static HtmlTreeBuilderState AfterFrameset = new HtmlTreeBuilderState() { + private static final class AfterFrameSetBS extends HtmlTreeBuilderState { @Override public String toString() { @@ -1666,9 +1788,9 @@ boolean process(Token t, HtmlTreeBuilder tb) { } return true; } - }; + } - public static HtmlTreeBuilderState AfterAfterBody = new HtmlTreeBuilderState() { + private static final class AfterAfterBodyBS extends HtmlTreeBuilderState { @Override public String toString() { @@ -1695,9 +1817,9 @@ boolean process(Token t, HtmlTreeBuilder tb) { } return true; } - }; + } - public static HtmlTreeBuilderState AfterAfterFrameset = new HtmlTreeBuilderState() { + private static final class AfterAfterFrameSetBS extends HtmlTreeBuilderState { @Override public String toString() { @@ -1719,9 +1841,9 @@ boolean process(Token t, HtmlTreeBuilder tb) { } return true; } - }; + } - public static HtmlTreeBuilderState ForeignContent = new HtmlTreeBuilderState() { + private static final class ForeignContentBS extends HtmlTreeBuilderState { @Override public String toString() { @@ -1731,81 +1853,5 @@ public String toString() { boolean process(Token t, HtmlTreeBuilder tb) { return true; } - }; - - private static final String nullString = String.valueOf('\u0000'); - - abstract boolean process(Token t, HtmlTreeBuilder tb); - - private static boolean isWhitespace(Token t) { - if (t.isCharacter()) { - String data = t.asCharacter().getData(); - return StringUtil.isBlank(data); - } - return false; - } - - private static boolean isWhitespace(String data) { - return StringUtil.isBlank(data); - } - - private static void handleRcData(Token.StartTag startTag, HtmlTreeBuilder tb) { - tb.tokeniser.transition(TokeniserState.Rcdata); - tb.markInsertionMode(); - tb.transition(Text); - tb.insert(startTag); - } - - private static void handleRawtext(Token.StartTag startTag, HtmlTreeBuilder tb) { - tb.tokeniser.transition(TokeniserState.Rawtext); - tb.markInsertionMode(); - tb.transition(Text); - tb.insert(startTag); - } - - // lists of tags to search through - static final class Constants { - static final String[] InHeadEmpty = new String[]{"base", "basefont", "bgsound", "command", "link"}; - static final String[] InHeadRaw = new String[]{"noframes", "style"}; - static final String[] InHeadEnd = new String[]{"body", "br", "html"}; - static final String[] AfterHeadBody = new String[]{"body", "html"}; - static final String[] BeforeHtmlToHead = new String[]{"body", "br", "head", "html", }; - static final String[] InHeadNoScriptHead = new String[]{"basefont", "bgsound", "link", "meta", "noframes", "style"}; - static final String[] InBodyStartToHead = new String[]{"base", "basefont", "bgsound", "command", "link", "meta", "noframes", "script", "style", "title"}; - static final String[] InBodyStartPClosers = new String[]{"address", "article", "aside", "blockquote", "center", "details", "dir", "div", "dl", - "fieldset", "figcaption", "figure", "footer", "header", "hgroup", "menu", "nav", "ol", - "p", "section", "summary", "ul"}; - static final String[] Headings = new String[]{"h1", "h2", "h3", "h4", "h5", "h6"}; - static final String[] InBodyStartLiBreakers = new String[]{"address", "div", "p"}; - static final String[] DdDt = new String[]{"dd", "dt"}; - static final String[] Formatters = new String[]{"b", "big", "code", "em", "font", "i", "s", "small", "strike", "strong", "tt", "u"}; - static final String[] InBodyStartApplets = new String[]{"applet", "marquee", "object"}; - static final String[] InBodyStartEmptyFormatters = new String[]{"area", "br", "embed", "img", "keygen", "wbr"}; - static final String[] InBodyStartMedia = new String[]{"param", "source", "track"}; - static final String[] InBodyStartInputAttribs = new String[]{"action", "name", "prompt"}; - static final String[] InBodyStartDrop = new String[]{"caption", "col", "colgroup", "frame", "head", "tbody", "td", "tfoot", "th", "thead", "tr"}; - static final String[] InBodyEndClosers = new String[]{"address", "article", "aside", "blockquote", "button", "center", "details", "dir", "div", - "dl", "fieldset", "figcaption", "figure", "footer", "header", "hgroup", "listing", "menu", - "nav", "ol", "pre", "section", "summary", "ul"}; - static final String[] InBodyEndAdoptionFormatters = new String[]{"a", "b", "big", "code", "em", "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u"}; - static final String[] InBodyEndTableFosters = new String[]{"table", "tbody", "tfoot", "thead", "tr"}; - static final String[] InTableToBody = new String[]{"tbody", "tfoot", "thead"}; - static final String[] InTableAddBody = new String[]{"td", "th", "tr"}; - static final String[] InTableToHead = new String[]{"script", "style"}; - static final String[] InCellNames = new String[]{"td", "th"}; - static final String[] InCellBody = new String[]{"body", "caption", "col", "colgroup", "html"}; - static final String[] InCellTable = new String[]{ "table", "tbody", "tfoot", "thead", "tr"}; - static final String[] InCellCol = new String[]{"caption", "col", "colgroup", "tbody", "td", "tfoot", "th", "thead", "tr"}; - static final String[] InTableEndErr = new String[]{"body", "caption", "col", "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr"}; - static final String[] InTableFoster = new String[]{"table", "tbody", "tfoot", "thead", "tr"}; - static final String[] InTableBodyExit = new String[]{"caption", "col", "colgroup", "tbody", "tfoot", "thead"}; - static final String[] InTableBodyEndIgnore = new String[]{"body", "caption", "col", "colgroup", "html", "td", "th", "tr"}; - static final String[] InRowMissing = new String[]{"caption", "col", "colgroup", "tbody", "tfoot", "thead", "tr"}; - static final String[] InRowIgnore = new String[]{"body", "caption", "col", "colgroup", "html", "td", "th"}; - static final String[] InSelectEnd = new String[]{"input", "keygen", "textarea"}; - static final String[] InSelecTableEnd = new String[]{"caption", "table", "tbody", "td", "tfoot", "th", "thead", "tr"}; - static final String[] InTableEndIgnore = new String[]{"tbody", "tfoot", "thead"}; - static final String[] InHeadNoscriptIgnore = new String[]{"head", "noscript"}; - static final String[] InCaptionIgnore = new String[]{"body", "col", "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr"}; } } diff --git a/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/jsoup/parser/TokeniserState.java b/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/jsoup/parser/TokeniserState.java index ceb4cf0d84..4be76630f0 100644 --- a/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/jsoup/parser/TokeniserState.java +++ b/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/jsoup/parser/TokeniserState.java @@ -28,7 +28,266 @@ This file is part of the iText (R) project. * States and transition activations for the Tokeniser. */ abstract class TokeniserState { - static TokeniserState Data = new TokeniserState() { + static TokeniserState Data = new DataTS(); + + static TokeniserState CharacterReferenceInData = new CharacterReferenceInDataTS(); + + static TokeniserState Rcdata = new RcDataTS(); + + static TokeniserState CharacterReferenceInRcdata = new CharacterReferenceInRcdataTS(); + + static TokeniserState Rawtext = new RawTextTS(); + + static TokeniserState ScriptData = new ScriptDataTS(); + + static TokeniserState PLAINTEXT = new PlainTextTS(); + + static TokeniserState TagOpen = new TagOpenTS(); + + static TokeniserState EndTagOpen = new EndTagOpenTS(); + + static TokeniserState TagName = new TagNameTS(); + + static TokeniserState RcdataLessthanSign = new RcDataLessThanSignTS(); + + static TokeniserState RCDATAEndTagOpen = new RcDataEndTagOpenTS(); + + static TokeniserState RCDATAEndTagName = new RcDataEndTagNameTS(); + + static TokeniserState RawtextLessthanSign = new RawTextLessThanSignTS(); + + static TokeniserState RawtextEndTagOpen = new RawTextEndTagOpenTS(); + + static TokeniserState RawtextEndTagName = new RawTextEndTagNameTS(); + + static TokeniserState ScriptDataLessthanSign = new ScriptDataLessThanSignTS(); + + static TokeniserState ScriptDataEndTagOpen = new ScriptDataEndTagOpenTS(); + + static TokeniserState ScriptDataEndTagName = new ScriptDataEndTagNameTS(); + + static TokeniserState ScriptDataEscapeStart = new ScriptDataEscapeStartTS(); + + static TokeniserState ScriptDataEscapeStartDash = new ScriptDataEscapeStartDashTS(); + + static TokeniserState ScriptDataEscaped = new ScriptDataEscapedTS(); + + static TokeniserState ScriptDataEscapedDash = new ScriptDataEscapedDashTS(); + + static TokeniserState ScriptDataEscapedDashDash = new ScriptDataEscapedDashDashTS(); + + static TokeniserState ScriptDataEscapedLessthanSign = new ScriptDataEscapedLessThanSignTS(); + + static TokeniserState ScriptDataEscapedEndTagOpen = new ScriptDataEscapedEndTagOpenTS(); + + static TokeniserState ScriptDataEscapedEndTagName = new ScriptDataEscapedEndTagNameTS(); + + static TokeniserState ScriptDataDoubleEscapeStart = new ScriptDataDoubleEscapeStartTS(); + + static TokeniserState ScriptDataDoubleEscaped = new ScriptDataDoubleEscapedTS(); + + static TokeniserState ScriptDataDoubleEscapedDash = new ScriptDataDoubleEscapedDashTS(); + + static TokeniserState ScriptDataDoubleEscapedDashDash = new ScriptDataDoubleEscapedDashDashTS(); + + static TokeniserState ScriptDataDoubleEscapedLessthanSign = new ScriptDataDoubleEscapedLessThanSignTS(); + + static TokeniserState ScriptDataDoubleEscapeEnd = new ScriptDataDoubleEscapeEndTS(); + + static TokeniserState BeforeAttributeName = new BeforeAttributeNameTS(); + + static TokeniserState AttributeName = new AttributeNameTS(); + + static TokeniserState AfterAttributeName = new AfterAttributeNameTS(); + + static TokeniserState BeforeAttributeValue = new BeforeAttributeValueTS(); + + static TokeniserState AttributeValue_doubleQuoted = new AttributeValueDoubleQuotedTS(); + + static TokeniserState AttributeValue_singleQuoted = new AttributeValueSingleQuotedTS(); + + static TokeniserState AttributeValue_unquoted = new AttributeValueUnquotedTS(); + // CharacterReferenceInAttributeValue state handled inline + static TokeniserState AfterAttributeValue_quoted = new AfterAttributeValueQuotedTS(); + + static TokeniserState SelfClosingStartTag = new SelfClosingStartTagTS(); + + static TokeniserState BogusComment = new BogusCommentTS(); + + static TokeniserState MarkupDeclarationOpen = new MarkupDeclarationOpenTS(); + + static TokeniserState CommentStart = new CommentStartTS(); + + static TokeniserState CommentStartDash = new CommentStartDashTS(); + + static TokeniserState Comment = new CommentTS(); + + static TokeniserState CommentEndDash = new CommentEndDashTS(); + + static TokeniserState CommentEnd = new CommentEndTS(); + + static TokeniserState CommentEndBang = new CommentEndBangTS(); + + static TokeniserState Doctype = new DocTypeTS(); + + static TokeniserState BeforeDoctypeName = new BeforeDocTypeNameTS(); + + static TokeniserState DoctypeName = new DocTypeNameTS(); + + static TokeniserState AfterDoctypeName = new AfterDocTypeNameTS(); + + static TokeniserState AfterDoctypePublicKeyword = new AfterDocTypePublicKeywordTS(); + + static TokeniserState BeforeDoctypePublicIdentifier = new BeforeDocTypePublicIdentifierTS(); + + static TokeniserState DoctypePublicIdentifier_doubleQuoted = new DocTypePublicIdentifierDoubleQuotedTS(); + + static TokeniserState DoctypePublicIdentifier_singleQuoted = new DocTypePublicIdentifierSingleQuotedTS(); + + static TokeniserState AfterDoctypePublicIdentifier = new AfterDocTypePublicIdentifierTS(); + + static TokeniserState BetweenDoctypePublicAndSystemIdentifiers = new BetweenDocTypePublicAndSystemIdentifiersTS(); + + static TokeniserState AfterDoctypeSystemKeyword = new AfterDocTypeSystemKeywordTS(); + + static TokeniserState BeforeDoctypeSystemIdentifier = new BeforeDocTypeSystemIdentifierTS(); + + static TokeniserState DoctypeSystemIdentifier_doubleQuoted = new DocTypeSystemIdentifierDoubleQuotedTS(); + + static TokeniserState DoctypeSystemIdentifier_singleQuoted = new DocTypeSystemIdentifierSingleQuotedTS(); + + static TokeniserState AfterDoctypeSystemIdentifier = new AfterDocTypeSystemIdentifierTS(); + + static TokeniserState BogusDoctype = new BogusDocTypeTS(); + + static TokeniserState CdataSection = new CDataSectionTS(); + + + abstract void read(Tokeniser t, CharacterReader r); + + static final char nullChar = '\u0000'; + // char searches. must be sorted, used in inSorted. MUST update TokenisetStateTest if more arrays are added. + static final char[] attributeNameCharsSorted = new char[]{nullChar, '\t', '\n', '\f', '\r', ' ', '"', '\'', '/', '<', '=', '>'}; + static final char[] attributeValueUnquoted = new char[]{nullChar, '\t', '\n', '\f', '\r', ' ', '"', '&', '\'', '<', '=', '>', '`'}; + + private static final char replacementChar = Tokeniser.replacementChar; + private static final String replacementStr = String.valueOf(Tokeniser.replacementChar); + private static final char eof = CharacterReader.EOF; + + /** + * Handles RawtextEndTagName, ScriptDataEndTagName, and ScriptDataEscapedEndTagName. Same body impl, just + * different else exit transitions. + */ + private static void handleDataEndTag(Tokeniser t, CharacterReader r, TokeniserState elseTransition) { + if (r.matchesLetter()) { + String name = r.consumeLetterSequence(); + t.tagPending.appendTagName(name); + t.dataBuffer.append(name); + return; + } + + boolean needsExitTransition = false; + if (t.isAppropriateEndTagToken() && !r.isEmpty()) { + char c = r.consume(); + switch (c) { + case '\t': + case '\n': + case '\r': + case '\f': + case ' ': + t.transition(BeforeAttributeName); + break; + case '/': + t.transition(SelfClosingStartTag); + break; + case '>': + t.emitTagPending(); + t.transition(Data); + break; + default: + t.dataBuffer.append(c); + needsExitTransition = true; + } + } else { + needsExitTransition = true; + } + + if (needsExitTransition) { + t.emit("': + if (t.dataBuffer.toString().equals("script")) + t.transition(primary); + else + t.transition(fallback); + t.emit(c); + break; + default: + r.unconsume(); + t.transition(fallback); + } + } + + private static final class DataTS extends TokeniserState { @Override public String toString() { @@ -57,9 +316,9 @@ void read(Tokeniser t, CharacterReader r) { break; } } - }; - - static TokeniserState CharacterReferenceInData = new TokeniserState() { + } + + private static final class CharacterReferenceInDataTS extends TokeniserState { @Override public String toString() { @@ -70,9 +329,9 @@ public String toString() { void read(Tokeniser t, CharacterReader r) { readCharRef(t, Data); } - }; - - static TokeniserState Rcdata = new TokeniserState() { + } + + private static final class RcDataTS extends TokeniserState { @Override public String toString() { @@ -102,9 +361,9 @@ void read(Tokeniser t, CharacterReader r) { break; } } - }; - - static TokeniserState CharacterReferenceInRcdata = new TokeniserState() { + } + + private static final class CharacterReferenceInRcdataTS extends TokeniserState { @Override public String toString() { @@ -114,9 +373,9 @@ public String toString() { void read(Tokeniser t, CharacterReader r) { readCharRef(t, Rcdata); } - }; - - static TokeniserState Rawtext = new TokeniserState() { + } + + private static final class RawTextTS extends TokeniserState { @Override public String toString() { @@ -126,9 +385,9 @@ public String toString() { void read(Tokeniser t, CharacterReader r) { readRawData(t, r, this, RawtextLessthanSign); } - }; - - static TokeniserState ScriptData = new TokeniserState() { + } + + private static final class ScriptDataTS extends TokeniserState { @Override public String toString() { @@ -138,9 +397,9 @@ public String toString() { void read(Tokeniser t, CharacterReader r) { readRawData(t, r, this, ScriptDataLessthanSign); } - }; - - static TokeniserState PLAINTEXT = new TokeniserState() { + } + + private static final class PlainTextTS extends TokeniserState { @Override public String toString() { @@ -163,9 +422,9 @@ void read(Tokeniser t, CharacterReader r) { break; } } - }; - - static TokeniserState TagOpen = new TokeniserState() { + } + + private static final class TagOpenTS extends TokeniserState { @Override public String toString() { @@ -197,9 +456,9 @@ void read(Tokeniser t, CharacterReader r) { break; } } - }; - - static TokeniserState EndTagOpen = new TokeniserState() { + } + + private static final class EndTagOpenTS extends TokeniserState { @Override public String toString() { @@ -223,9 +482,9 @@ void read(Tokeniser t, CharacterReader r) { t.advanceTransition(BogusComment); } } - }; - - static TokeniserState TagName = new TokeniserState() { + } + + private static final class TagNameTS extends TokeniserState { @Override public String toString() { @@ -270,9 +529,9 @@ void read(Tokeniser t, CharacterReader r) { t.tagPending.appendTagName(c); } } - }; - - static TokeniserState RcdataLessthanSign = new TokeniserState() { + } + + private static final class RcDataLessThanSignTS extends TokeniserState { @Override public String toString() { @@ -295,9 +554,9 @@ void read(Tokeniser t, CharacterReader r) { t.transition(Rcdata); } } - }; - - static TokeniserState RCDATAEndTagOpen = new TokeniserState() { + } + + private static final class RcDataEndTagOpenTS extends TokeniserState { @Override public String toString() { @@ -315,9 +574,9 @@ void read(Tokeniser t, CharacterReader r) { t.transition(Rcdata); } } - }; - - static TokeniserState RCDATAEndTagName = new TokeniserState() { + } + + private static final class RcDataEndTagNameTS extends TokeniserState { @Override public String toString() { @@ -369,9 +628,9 @@ private void anythingElse(Tokeniser t, CharacterReader r) { r.unconsume(); t.transition(Rcdata); } - }; - - static TokeniserState RawtextLessthanSign = new TokeniserState() { + } + + private static final class RawTextLessThanSignTS extends TokeniserState { @Override public String toString() { @@ -387,9 +646,9 @@ void read(Tokeniser t, CharacterReader r) { t.transition(Rawtext); } } - }; - - static TokeniserState RawtextEndTagOpen = new TokeniserState() { + } + + private static final class RawTextEndTagOpenTS extends TokeniserState { @Override public String toString() { @@ -399,9 +658,9 @@ public String toString() { void read(Tokeniser t, CharacterReader r) { readEndTag(t, r, RawtextEndTagName, Rawtext); } - }; - - static TokeniserState RawtextEndTagName = new TokeniserState() { + } + + private static final class RawTextEndTagNameTS extends TokeniserState { @Override public String toString() { @@ -411,9 +670,9 @@ public String toString() { void read(Tokeniser t, CharacterReader r) { handleDataEndTag(t, r, Rawtext); } - }; - - static TokeniserState ScriptDataLessthanSign = new TokeniserState() { + } + + private static final class ScriptDataLessThanSignTS extends TokeniserState { @Override public String toString() { @@ -441,9 +700,9 @@ void read(Tokeniser t, CharacterReader r) { t.transition(ScriptData); } } - }; - - static TokeniserState ScriptDataEndTagOpen = new TokeniserState() { + } + + private static final class ScriptDataEndTagOpenTS extends TokeniserState { @Override public String toString() { @@ -453,9 +712,9 @@ public String toString() { void read(Tokeniser t, CharacterReader r) { readEndTag(t, r, ScriptDataEndTagName, ScriptData); } - }; - - static TokeniserState ScriptDataEndTagName = new TokeniserState() { + } + + private static final class ScriptDataEndTagNameTS extends TokeniserState { @Override public String toString() { @@ -465,9 +724,9 @@ public String toString() { void read(Tokeniser t, CharacterReader r) { handleDataEndTag(t, r, ScriptData); } - }; - - static TokeniserState ScriptDataEscapeStart = new TokeniserState() { + } + + private static final class ScriptDataEscapeStartTS extends TokeniserState { @Override public String toString() { @@ -482,9 +741,9 @@ void read(Tokeniser t, CharacterReader r) { t.transition(ScriptData); } } - }; - - static TokeniserState ScriptDataEscapeStartDash = new TokeniserState() { + } + + private static final class ScriptDataEscapeStartDashTS extends TokeniserState { @Override public String toString() { @@ -499,9 +758,9 @@ void read(Tokeniser t, CharacterReader r) { t.transition(ScriptData); } } - }; - - static TokeniserState ScriptDataEscaped = new TokeniserState() { + } + + private static final class ScriptDataEscapedTS extends TokeniserState { @Override public String toString() { @@ -533,9 +792,9 @@ void read(Tokeniser t, CharacterReader r) { t.emit(data); } } - }; - - static TokeniserState ScriptDataEscapedDash = new TokeniserState() { + } + + private static final class ScriptDataEscapedDashTS extends TokeniserState { @Override public String toString() { @@ -568,9 +827,9 @@ void read(Tokeniser t, CharacterReader r) { t.transition(ScriptDataEscaped); } } - }; - - static TokeniserState ScriptDataEscapedDashDash = new TokeniserState() { + } + + private static final class ScriptDataEscapedDashDashTS extends TokeniserState { @Override public String toString() { @@ -606,9 +865,9 @@ void read(Tokeniser t, CharacterReader r) { t.transition(ScriptDataEscaped); } } - }; - - static TokeniserState ScriptDataEscapedLessthanSign = new TokeniserState() { + } + + private static final class ScriptDataEscapedLessThanSignTS extends TokeniserState { @Override public String toString() { @@ -630,9 +889,9 @@ void read(Tokeniser t, CharacterReader r) { t.transition(ScriptDataEscaped); } } - }; - - static TokeniserState ScriptDataEscapedEndTagOpen = new TokeniserState() { + } + + private static final class ScriptDataEscapedEndTagOpenTS extends TokeniserState { @Override public String toString() { @@ -650,9 +909,9 @@ void read(Tokeniser t, CharacterReader r) { t.transition(ScriptDataEscaped); } } - }; - - static TokeniserState ScriptDataEscapedEndTagName = new TokeniserState() { + } + + private static final class ScriptDataEscapedEndTagNameTS extends TokeniserState { @Override public String toString() { @@ -662,9 +921,9 @@ public String toString() { void read(Tokeniser t, CharacterReader r) { handleDataEndTag(t, r, ScriptDataEscaped); } - }; - - static TokeniserState ScriptDataDoubleEscapeStart = new TokeniserState() { + } + + private static final class ScriptDataDoubleEscapeStartTS extends TokeniserState { @Override public String toString() { @@ -674,9 +933,9 @@ public String toString() { void read(Tokeniser t, CharacterReader r) { handleDataDoubleEscapeTag(t, r, ScriptDataDoubleEscaped, ScriptDataEscaped); } - }; - - static TokeniserState ScriptDataDoubleEscaped = new TokeniserState() { + } + + private static final class ScriptDataDoubleEscapedTS extends TokeniserState { @Override public String toString() { @@ -708,9 +967,9 @@ void read(Tokeniser t, CharacterReader r) { t.emit(data); } } - }; - - static TokeniserState ScriptDataDoubleEscapedDash = new TokeniserState() { + } + + private static final class ScriptDataDoubleEscapedDashTS extends TokeniserState { @Override public String toString() { @@ -728,23 +987,23 @@ void read(Tokeniser t, CharacterReader r) { t.emit(c); t.transition(ScriptDataDoubleEscapedLessthanSign); break; + case eof: + t.eofError(this); + t.transition(Data); + break; case nullChar: t.error(this); t.emit(replacementChar); t.transition(ScriptDataDoubleEscaped); break; - case eof: - t.eofError(this); - t.transition(Data); - break; default: t.emit(c); t.transition(ScriptDataDoubleEscaped); } } - }; - - static TokeniserState ScriptDataDoubleEscapedDashDash = new TokeniserState() { + } + + private static final class ScriptDataDoubleEscapedDashDashTS extends TokeniserState { @Override public String toString() { @@ -779,9 +1038,9 @@ void read(Tokeniser t, CharacterReader r) { t.transition(ScriptDataDoubleEscaped); } } - }; - - static TokeniserState ScriptDataDoubleEscapedLessthanSign = new TokeniserState() { + } + + private static final class ScriptDataDoubleEscapedLessThanSignTS extends TokeniserState { @Override public String toString() { @@ -797,9 +1056,9 @@ void read(Tokeniser t, CharacterReader r) { t.transition(ScriptDataDoubleEscaped); } } - }; - - static TokeniserState ScriptDataDoubleEscapeEnd = new TokeniserState() { + } + + private static final class ScriptDataDoubleEscapeEndTS extends TokeniserState { @Override public String toString() { @@ -809,9 +1068,9 @@ public String toString() { void read(Tokeniser t, CharacterReader r) { handleDataDoubleEscapeTag(t,r, ScriptDataEscaped, ScriptDataDoubleEscaped); } - }; - - static TokeniserState BeforeAttributeName = new TokeniserState() { + } + + private static final class BeforeAttributeNameTS extends TokeniserState { @Override public String toString() { @@ -863,9 +1122,9 @@ void read(Tokeniser t, CharacterReader r) { t.transition(AttributeName); } } - }; - - static TokeniserState AttributeName = new TokeniserState() { + } + + private static final class AttributeNameTS extends TokeniserState { @Override public String toString() { @@ -914,9 +1173,9 @@ void read(Tokeniser t, CharacterReader r) { t.tagPending.appendAttributeName(c); } } - }; - - static TokeniserState AfterAttributeName = new TokeniserState() { + } + + private static final class AfterAttributeNameTS extends TokeniserState { @Override public String toString() { @@ -948,27 +1207,27 @@ void read(Tokeniser t, CharacterReader r) { t.tagPending.appendAttributeName(replacementChar); t.transition(AttributeName); break; - case eof: - t.eofError(this); - t.transition(Data); - break; - case '"': case '\'': + case '"': case '<': t.error(this); t.tagPending.newAttribute(); t.tagPending.appendAttributeName(c); t.transition(AttributeName); break; + case eof: + t.eofError(this); + t.transition(Data); + break; default: // A-Z, anything else t.tagPending.newAttribute(); r.unconsume(); t.transition(AttributeName); } } - }; - - static TokeniserState BeforeAttributeValue = new TokeniserState() { + } + + private static final class BeforeAttributeValueTS extends TokeniserState { @Override public String toString() { @@ -1022,9 +1281,9 @@ void read(Tokeniser t, CharacterReader r) { t.transition(AttributeValue_unquoted); } } - }; - - static TokeniserState AttributeValue_doubleQuoted = new TokeniserState() { + } + + private static final class AttributeValueDoubleQuotedTS extends TokeniserState { @Override public String toString() { @@ -1033,16 +1292,14 @@ public String toString() { void read(Tokeniser t, CharacterReader r) { String value = r.consumeAttributeQuoted(false); - if (value.length() > 0) + if (value.length() > 0) { t.tagPending.appendAttributeValue(value); - else + } else { t.tagPending.setEmptyAttributeValue(); + } char c = r.consume(); switch (c) { - case '"': - t.transition(AfterAttributeValue_quoted); - break; case '&': int[] ref = t.consumeCharacterReference('"', true); if (ref != null) @@ -1050,21 +1307,24 @@ void read(Tokeniser t, CharacterReader r) { else t.tagPending.appendAttributeValue('&'); break; - case nullChar: - t.error(this); - t.tagPending.appendAttributeValue(replacementChar); + case '"': + t.transition(AfterAttributeValue_quoted); break; case eof: t.eofError(this); t.transition(Data); break; + case nullChar: + t.error(this); + t.tagPending.appendAttributeValue(replacementChar); + break; default: // hit end of buffer in first read, still in attribute t.tagPending.appendAttributeValue(c); } } - }; - - static TokeniserState AttributeValue_singleQuoted = new TokeniserState() { + } + + private static final class AttributeValueSingleQuotedTS extends TokeniserState { @Override public String toString() { @@ -1102,9 +1362,9 @@ void read(Tokeniser t, CharacterReader r) { t.tagPending.appendAttributeValue(c); } } - }; - - static TokeniserState AttributeValue_unquoted = new TokeniserState() { + } + + private static final class AttributeValueUnquotedTS extends TokeniserState { @Override public String toString() { @@ -1157,9 +1417,9 @@ void read(Tokeniser t, CharacterReader r) { } } - }; - // CharacterReferenceInAttributeValue state handled inline - static TokeniserState AfterAttributeValue_quoted = new TokeniserState() { + } + + private static final class AfterAttributeValueQuotedTS extends TokeniserState { @Override public String toString() { @@ -1194,9 +1454,9 @@ void read(Tokeniser t, CharacterReader r) { } } - }; - - static TokeniserState SelfClosingStartTag = new TokeniserState() { + } + + private static final class SelfClosingStartTagTS extends TokeniserState { @Override public String toString() { @@ -1221,9 +1481,9 @@ void read(Tokeniser t, CharacterReader r) { t.transition(BeforeAttributeName); } } - }; - - static TokeniserState BogusComment = new TokeniserState() { + } + + private static final class BogusCommentTS extends TokeniserState { @Override public String toString() { @@ -1240,9 +1500,9 @@ void read(Tokeniser t, CharacterReader r) { t.transition(Data); } } - }; - - static TokeniserState MarkupDeclarationOpen = new TokeniserState() { + } + + private static final class MarkupDeclarationOpenTS extends TokeniserState { @Override public String toString() { @@ -1266,9 +1526,9 @@ void read(Tokeniser t, CharacterReader r) { t.advanceTransition(BogusComment); // advance so this character gets in bogus comment data's rewind } } - }; - - static TokeniserState CommentStart = new TokeniserState() { + } + + private static final class CommentStartTS extends TokeniserState { @Override public String toString() { @@ -1278,32 +1538,32 @@ public String toString() { void read(Tokeniser t, CharacterReader r) { char c = r.consume(); switch (c) { + case eof: + t.eofError(this); + t.emitCommentPending(); + t.transition(Data); + break; case '-': t.transition(CommentStartDash); break; - case nullChar: - t.error(this); - t.commentPending.append(replacementChar); - t.transition(Comment); - break; case '>': t.error(this); t.emitCommentPending(); t.transition(Data); break; - case eof: - t.eofError(this); - t.emitCommentPending(); - t.transition(Data); + case nullChar: + t.error(this); + t.commentPending.append(replacementChar); + t.transition(Comment); break; default: r.unconsume(); t.transition(Comment); } } - }; - - static TokeniserState CommentStartDash = new TokeniserState() { + } + + private static final class CommentStartDashTS extends TokeniserState { @Override public String toString() { @@ -1336,9 +1596,9 @@ void read(Tokeniser t, CharacterReader r) { t.transition(Comment); } } - }; - - static TokeniserState Comment = new TokeniserState() { + } + + private static final class CommentTS extends TokeniserState { @Override public String toString() { @@ -1365,9 +1625,9 @@ void read(Tokeniser t, CharacterReader r) { t.commentPending.append(r.consumeToAny('-', nullChar)); } } - }; - - static TokeniserState CommentEndDash = new TokeniserState() { + } + + private static final class CommentEndDashTS extends TokeniserState { @Override public String toString() { @@ -1380,24 +1640,24 @@ void read(Tokeniser t, CharacterReader r) { case '-': t.transition(CommentEnd); break; - case nullChar: - t.error(this); - t.commentPending.append('-').append(replacementChar); - t.transition(Comment); - break; case eof: t.eofError(this); t.emitCommentPending(); t.transition(Data); break; + case nullChar: + t.error(this); + t.commentPending.append('-').append(replacementChar); + t.transition(Comment); + break; default: t.commentPending.append('-').append(c); t.transition(Comment); } } - }; - - static TokeniserState CommentEnd = new TokeniserState() { + } + + private static final class CommentEndTS extends TokeniserState { @Override public String toString() { @@ -1435,9 +1695,9 @@ void read(Tokeniser t, CharacterReader r) { t.transition(Comment); } } - }; - - static TokeniserState CommentEndBang = new TokeniserState() { + } + + private static final class CommentEndBangTS extends TokeniserState { @Override public String toString() { @@ -1470,9 +1730,9 @@ void read(Tokeniser t, CharacterReader r) { t.transition(Comment); } } - }; - - static TokeniserState Doctype = new TokeniserState() { + } + + private static final class DocTypeTS extends TokeniserState { @Override public String toString() { @@ -1504,9 +1764,9 @@ void read(Tokeniser t, CharacterReader r) { t.transition(BeforeDoctypeName); } } - }; - - static TokeniserState BeforeDoctypeName = new TokeniserState() { + } + + private static final class BeforeDocTypeNameTS extends TokeniserState { @Override public String toString() { @@ -1546,9 +1806,9 @@ void read(Tokeniser t, CharacterReader r) { t.transition(DoctypeName); } } - }; - - static TokeniserState DoctypeName = new TokeniserState() { + } + + private static final class DocTypeNameTS extends TokeniserState { @Override public String toString() { @@ -1588,9 +1848,9 @@ void read(Tokeniser t, CharacterReader r) { t.doctypePending.name.append(c); } } - }; - - static TokeniserState AfterDoctypeName = new TokeniserState() { + } + + private static final class AfterDocTypeNameTS extends TokeniserState { @Override public String toString() { @@ -1623,9 +1883,9 @@ else if (r.matches('>')) { } } - }; - - static TokeniserState AfterDoctypePublicKeyword = new TokeniserState() { + } + + private static final class AfterDocTypePublicKeywordTS extends TokeniserState { @Override public String toString() { @@ -1652,14 +1912,14 @@ void read(Tokeniser t, CharacterReader r) { // set public id to empty string t.transition(DoctypePublicIdentifier_singleQuoted); break; - case '>': - t.error(this); + case eof: + t.eofError(this); t.doctypePending.forceQuirks = true; t.emitDoctypePending(); t.transition(Data); break; - case eof: - t.eofError(this); + case '>': + t.error(this); t.doctypePending.forceQuirks = true; t.emitDoctypePending(); t.transition(Data); @@ -1670,9 +1930,9 @@ void read(Tokeniser t, CharacterReader r) { t.transition(BogusDoctype); } } - }; - - static TokeniserState BeforeDoctypePublicIdentifier = new TokeniserState() { + } + + private static final class BeforeDocTypePublicIdentifierTS extends TokeniserState { @Override public String toString() { @@ -1714,9 +1974,9 @@ void read(Tokeniser t, CharacterReader r) { t.transition(BogusDoctype); } } - }; - - static TokeniserState DoctypePublicIdentifier_doubleQuoted = new TokeniserState() { + } + + private static final class DocTypePublicIdentifierDoubleQuotedTS extends TokeniserState { @Override public String toString() { @@ -1729,29 +1989,29 @@ void read(Tokeniser t, CharacterReader r) { case '"': t.transition(AfterDoctypePublicIdentifier); break; - case nullChar: - t.error(this); - t.doctypePending.publicIdentifier.append(replacementChar); - break; - case '>': - t.error(this); + case eof: + t.eofError(this); t.doctypePending.forceQuirks = true; t.emitDoctypePending(); t.transition(Data); break; - case eof: - t.eofError(this); + case '>': + t.error(this); t.doctypePending.forceQuirks = true; t.emitDoctypePending(); t.transition(Data); break; + case nullChar: + t.error(this); + t.doctypePending.publicIdentifier.append(replacementChar); + break; default: t.doctypePending.publicIdentifier.append(c); } } - }; - - static TokeniserState DoctypePublicIdentifier_singleQuoted = new TokeniserState() { + } + + private static final class DocTypePublicIdentifierSingleQuotedTS extends TokeniserState { @Override public String toString() { @@ -1784,9 +2044,9 @@ void read(Tokeniser t, CharacterReader r) { t.doctypePending.publicIdentifier.append(c); } } - }; - - static TokeniserState AfterDoctypePublicIdentifier = new TokeniserState() { + } + + private static final class AfterDocTypePublicIdentifierTS extends TokeniserState { @Override public String toString() { @@ -1803,19 +2063,14 @@ void read(Tokeniser t, CharacterReader r) { case ' ': t.transition(BetweenDoctypePublicAndSystemIdentifiers); break; - case '>': - t.emitDoctypePending(); - t.transition(Data); - break; case '"': t.error(this); // system id empty t.transition(DoctypeSystemIdentifier_doubleQuoted); break; - case '\'': - t.error(this); - // system id empty - t.transition(DoctypeSystemIdentifier_singleQuoted); + case '>': + t.emitDoctypePending(); + t.transition(Data); break; case eof: t.eofError(this); @@ -1823,15 +2078,20 @@ void read(Tokeniser t, CharacterReader r) { t.emitDoctypePending(); t.transition(Data); break; + case '\'': + t.error(this); + // system id empty + t.transition(DoctypeSystemIdentifier_singleQuoted); + break; default: t.error(this); t.doctypePending.forceQuirks = true; t.transition(BogusDoctype); } } - }; - - static TokeniserState BetweenDoctypePublicAndSystemIdentifiers = new TokeniserState() { + } + + private static final class BetweenDocTypePublicAndSystemIdentifiersTS extends TokeniserState { @Override public String toString() { @@ -1873,9 +2133,9 @@ void read(Tokeniser t, CharacterReader r) { t.transition(BogusDoctype); } } - }; - - static TokeniserState AfterDoctypeSystemKeyword = new TokeniserState() { + } + + private static final class AfterDocTypeSystemKeywordTS extends TokeniserState { @Override public String toString() { @@ -1885,6 +2145,12 @@ public String toString() { void read(Tokeniser t, CharacterReader r) { char c = r.consume(); switch (c) { + case '>': + t.error(this); + t.doctypePending.forceQuirks = true; + t.emitDoctypePending(); + t.transition(Data); + break; case '\t': case '\n': case '\r': @@ -1892,37 +2158,31 @@ void read(Tokeniser t, CharacterReader r) { case ' ': t.transition(BeforeDoctypeSystemIdentifier); break; - case '>': - t.error(this); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - t.transition(Data); - break; case '"': t.error(this); // system id empty t.transition(DoctypeSystemIdentifier_doubleQuoted); break; - case '\'': - t.error(this); - // system id empty - t.transition(DoctypeSystemIdentifier_singleQuoted); - break; case eof: t.eofError(this); t.doctypePending.forceQuirks = true; t.emitDoctypePending(); t.transition(Data); break; + case '\'': + t.error(this); + // system id empty + t.transition(DoctypeSystemIdentifier_singleQuoted); + break; default: t.error(this); t.doctypePending.forceQuirks = true; t.emitDoctypePending(); } } - }; - - static TokeniserState BeforeDoctypeSystemIdentifier = new TokeniserState() { + } + + private static final class BeforeDocTypeSystemIdentifierTS extends TokeniserState { @Override public String toString() { @@ -1932,6 +2192,12 @@ public String toString() { void read(Tokeniser t, CharacterReader r) { char c = r.consume(); switch (c) { + case eof: + t.eofError(this); + t.doctypePending.forceQuirks = true; + t.emitDoctypePending(); + t.transition(Data); + break; case '\t': case '\n': case '\r': @@ -1952,21 +2218,15 @@ void read(Tokeniser t, CharacterReader r) { t.emitDoctypePending(); t.transition(Data); break; - case eof: - t.eofError(this); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - t.transition(Data); - break; default: t.error(this); t.doctypePending.forceQuirks = true; t.transition(BogusDoctype); } } - }; - - static TokeniserState DoctypeSystemIdentifier_doubleQuoted = new TokeniserState() { + } + + private static final class DocTypeSystemIdentifierDoubleQuotedTS extends TokeniserState { @Override public String toString() { @@ -1976,32 +2236,32 @@ public String toString() { void read(Tokeniser t, CharacterReader r) { char c = r.consume(); switch (c) { - case '"': - t.transition(AfterDoctypeSystemIdentifier); + case eof: + t.eofError(this); + t.doctypePending.forceQuirks = true; + t.emitDoctypePending(); + t.transition(Data); break; case nullChar: t.error(this); t.doctypePending.systemIdentifier.append(replacementChar); break; + case '"': + t.transition(AfterDoctypeSystemIdentifier); + break; case '>': t.error(this); t.doctypePending.forceQuirks = true; t.emitDoctypePending(); t.transition(Data); break; - case eof: - t.eofError(this); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - t.transition(Data); - break; default: t.doctypePending.systemIdentifier.append(c); } } - }; - - static TokeniserState DoctypeSystemIdentifier_singleQuoted = new TokeniserState() { + } + + private static final class DocTypeSystemIdentifierSingleQuotedTS extends TokeniserState { @Override public String toString() { @@ -2014,16 +2274,16 @@ void read(Tokeniser t, CharacterReader r) { case '\'': t.transition(AfterDoctypeSystemIdentifier); break; - case nullChar: - t.error(this); - t.doctypePending.systemIdentifier.append(replacementChar); - break; case '>': t.error(this); t.doctypePending.forceQuirks = true; t.emitDoctypePending(); t.transition(Data); break; + case nullChar: + t.error(this); + t.doctypePending.systemIdentifier.append(replacementChar); + break; case eof: t.eofError(this); t.doctypePending.forceQuirks = true; @@ -2034,9 +2294,9 @@ void read(Tokeniser t, CharacterReader r) { t.doctypePending.systemIdentifier.append(c); } } - }; - - static TokeniserState AfterDoctypeSystemIdentifier = new TokeniserState() { + } + + private static final class AfterDocTypeSystemIdentifierTS extends TokeniserState { @Override public String toString() { @@ -2052,25 +2312,25 @@ void read(Tokeniser t, CharacterReader r) { case '\f': case ' ': break; - case '>': - t.emitDoctypePending(); - t.transition(Data); - break; case eof: t.eofError(this); t.doctypePending.forceQuirks = true; t.emitDoctypePending(); t.transition(Data); break; + case '>': + t.emitDoctypePending(); + t.transition(Data); + break; default: t.error(this); t.transition(BogusDoctype); // NOT force quirks } } - }; - - static TokeniserState BogusDoctype = new TokeniserState() { + } + + private static final class BogusDocTypeTS extends TokeniserState { @Override public String toString() { @@ -2093,9 +2353,9 @@ void read(Tokeniser t, CharacterReader r) { break; } } - }; - - static TokeniserState CdataSection = new TokeniserState() { + } + + private static final class CDataSectionTS extends TokeniserState { @Override public String toString() { @@ -2110,130 +2370,5 @@ void read(Tokeniser t, CharacterReader r) { t.transition(Data); }// otherwise, buffer underrun, stay in data section } - }; - - - abstract void read(Tokeniser t, CharacterReader r); - - static final char nullChar = '\u0000'; - // char searches. must be sorted, used in inSorted. MUST update TokenisetStateTest if more arrays are added. - static final char[] attributeNameCharsSorted = new char[]{nullChar, '\t', '\n', '\f', '\r', ' ', '"', '\'', '/', '<', '=', '>'}; - static final char[] attributeValueUnquoted = new char[]{nullChar, '\t', '\n', '\f', '\r', ' ', '"', '&', '\'', '<', '=', '>', '`'}; - - private static final char replacementChar = Tokeniser.replacementChar; - private static final String replacementStr = String.valueOf(Tokeniser.replacementChar); - private static final char eof = CharacterReader.EOF; - - /** - * Handles RawtextEndTagName, ScriptDataEndTagName, and ScriptDataEscapedEndTagName. Same body impl, just - * different else exit transitions. - */ - private static void handleDataEndTag(Tokeniser t, CharacterReader r, TokeniserState elseTransition) { - if (r.matchesLetter()) { - String name = r.consumeLetterSequence(); - t.tagPending.appendTagName(name); - t.dataBuffer.append(name); - return; - } - - boolean needsExitTransition = false; - if (t.isAppropriateEndTagToken() && !r.isEmpty()) { - char c = r.consume(); - switch (c) { - case '\t': - case '\n': - case '\r': - case '\f': - case ' ': - t.transition(BeforeAttributeName); - break; - case '/': - t.transition(SelfClosingStartTag); - break; - case '>': - t.emitTagPending(); - t.transition(Data); - break; - default: - t.dataBuffer.append(c); - needsExitTransition = true; - } - } else { - needsExitTransition = true; - } - - if (needsExitTransition) { - t.emit("': - if (t.dataBuffer.toString().equals("script")) - t.transition(primary); - else - t.transition(fallback); - t.emit(c); - break; - default: - r.unconsume(); - t.transition(fallback); - } } } diff --git a/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/DefaultResourceRetriever.java b/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/DefaultResourceRetriever.java index 47db56d8cb..38c4bee7ee 100644 --- a/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/DefaultResourceRetriever.java +++ b/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/DefaultResourceRetriever.java @@ -24,6 +24,7 @@ This file is part of the iText (R) project. import com.itextpdf.commons.utils.MessageFormatUtil; import com.itextpdf.io.util.StreamUtil; +import com.itextpdf.io.util.UrlUtil; import com.itextpdf.styledxmlparser.logs.StyledXmlParserLogMessageConstant; import com.itextpdf.styledxmlparser.exceptions.ReadingByteLimitException; @@ -90,7 +91,7 @@ public InputStream getInputStreamByUrl(URL url) throws IOException { url)); return null; } - return new LimitedInputStream(url.openStream(), resourceSizeByteLimit); + return new LimitedInputStream(UrlUtil.getInputStreamOfFinalConnection(url), resourceSizeByteLimit); } /** diff --git a/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolver.java b/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolver.java index 870894c09f..503009964b 100644 --- a/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolver.java +++ b/styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolver.java @@ -45,7 +45,6 @@ This file is part of the iText (R) project. import com.itextpdf.commons.utils.Base64; import com.itextpdf.commons.utils.MessageFormatUtil; import com.itextpdf.io.image.ImageDataFactory; -import com.itextpdf.io.util.UrlUtil; import com.itextpdf.kernel.pdf.xobject.PdfImageXObject; import com.itextpdf.kernel.pdf.xobject.PdfXObject; import com.itextpdf.styledxmlparser.logs.StyledXmlParserLogMessageConstant; @@ -277,7 +276,6 @@ protected PdfXObject tryResolveBase64ImageSource(String src) { protected PdfXObject tryResolveUrlImageSource(String uri) { try { URL url = uriResolver.resolveAgainstBaseUri(uri); - url = UrlUtil.getFinalURL(url); String imageResolvedSrc = url.toExternalForm(); PdfXObject imageXObject = imageCache.getImage(imageResolvedSrc); if (imageXObject == null) { @@ -295,9 +293,9 @@ protected PdfXObject tryResolveUrlImageSource(String uri) { /** * Create a iText XObject based on the image stored at the passed location. * - * @param url location of the Image file - * @return {@link PdfXObject} containing the Image loaded in - * @throws Exception thrown if error occurred during fetching or constructing the image + * @param url location of the Image file. + * @return {@link PdfXObject} containing the Image loaded in. + * @throws Exception thrown if error occurred during fetching or constructing the image. */ protected PdfXObject createImageByUrl(URL url) throws Exception { byte[] bytes = retriever.getByteArrayByUrl(url); diff --git a/styled-xml-parser/src/test/java/com/itextpdf/styledxmlparser/css/parse/CssSelectorParserTest.java b/styled-xml-parser/src/test/java/com/itextpdf/styledxmlparser/css/parse/CssSelectorParserTest.java new file mode 100644 index 0000000000..5f26a8ce8e --- /dev/null +++ b/styled-xml-parser/src/test/java/com/itextpdf/styledxmlparser/css/parse/CssSelectorParserTest.java @@ -0,0 +1,50 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2021 iText Group NV + Authors: iText Software. + + This program is offered under a commercial and under the AGPL license. + For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + + AGPL licensing: + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +package com.itextpdf.styledxmlparser.css.parse; + +import com.itextpdf.commons.utils.MessageFormatUtil; +import com.itextpdf.io.exceptions.IOException; +import com.itextpdf.styledxmlparser.exceptions.StyledXmlParserExceptionMessage; +import com.itextpdf.test.ExtendedITextTest; +import com.itextpdf.test.annotations.type.UnitTest; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +@Category(UnitTest.class) +public class CssSelectorParserTest extends ExtendedITextTest { + + @Test + public void selectorBeginsWithSpaceTest() throws IOException { + String space = " "; + String selectorWithSpaceAtTheBeginning = space + ".spaceBefore"; + + Exception expectedException = Assert.assertThrows(IllegalArgumentException.class, + () -> CssSelectorParser.parseSelectorItems(selectorWithSpaceAtTheBeginning)); + Assert.assertEquals( + MessageFormatUtil.format(StyledXmlParserExceptionMessage.INVALID_TOKEN_AT_THE_BEGINNING_OF_SELECTOR, + space), + expectedException.getMessage()); + } +} diff --git a/styled-xml-parser/src/test/java/com/itextpdf/styledxmlparser/jsoup/parser/TokeniserStateTest.java b/styled-xml-parser/src/test/java/com/itextpdf/styledxmlparser/jsoup/parser/TokeniserStateTest.java index f709b0eadb..a54d460f95 100644 --- a/styled-xml-parser/src/test/java/com/itextpdf/styledxmlparser/jsoup/parser/TokeniserStateTest.java +++ b/styled-xml-parser/src/test/java/com/itextpdf/styledxmlparser/jsoup/parser/TokeniserStateTest.java @@ -311,4 +311,435 @@ public void attributeValUnquoted() { doc = Jsoup.parse("

", doc.body().html()); } + + @Test + public void testRCDATAEndTagNameDiffTag() { + String body = ""; + Document doc = Jsoup.parse(body); + Elements els = doc.select("textarea"); + Assert.assertEquals("data", els.text()); + } + + @Test + public void testRCDATAEndTagNameInvalidSlash() { + String body = "