From bb0345e2c350bc4bed6e16327a174c1fd0d3a942 Mon Sep 17 00:00:00 2001 From: "iText Software (Community)" Date: Mon, 16 Apr 2018 15:41:09 +0200 Subject: [PATCH 01/23] [RELEASE] 7.1.2-SNAPSHOT -> 7.1.3-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4e345fcf66..d4d788a8aa 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.itextpdf root - 7.1.2-SNAPSHOT + 7.1.3-SNAPSHOT From d4faa4d6dcc5c7a705d4c542d48f201c2e326fd3 Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 20 Apr 2018 15:22:09 +0200 Subject: [PATCH 02/23] Move external style sheet loading from pdfHTML to styled-xml-parser RND-864 --- pom.xml | 10 + .../styledxmlparser/LogMessageConstant.java | 6 + .../resolver/font/DefaultFontProvider.java | 118 ++++++++++ .../resolver/font/package-info.java | 1 + .../resolver/resource/ResourceResolver.java | 193 ++++++++++++++++ .../resolver/resource/SimpleImageCache.java | 154 +++++++++++++ .../resource/SimpleImageCacheTest.java | 165 +++++++++++++ .../resolver/resource/UriResolverTest.java | 217 ++++++++++++++++++ 8 files changed, 864 insertions(+) create mode 100644 src/main/java/com/itextpdf/styledxmlparser/resolver/font/DefaultFontProvider.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/resolver/font/package-info.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolver.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/resolver/resource/SimpleImageCache.java create mode 100644 src/test/java/com/itextpdf/styledxmlparser/resolver/resource/SimpleImageCacheTest.java create mode 100644 src/test/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolverTest.java diff --git a/pom.xml b/pom.xml index d4d788a8aa..2ff8717b79 100644 --- a/pom.xml +++ b/pom.xml @@ -31,6 +31,16 @@ pdftest ${project.version} + + com.itextpdf + kernel + ${project.version} + + + com.itextpdf + layout + ${project.version} + diff --git a/src/main/java/com/itextpdf/styledxmlparser/LogMessageConstant.java b/src/main/java/com/itextpdf/styledxmlparser/LogMessageConstant.java index d2206aa4ff..75f699d616 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/LogMessageConstant.java +++ b/src/main/java/com/itextpdf/styledxmlparser/LogMessageConstant.java @@ -60,6 +60,12 @@ public final class LogMessageConstant { /** The Constant RULE_IS_NOT_SUPPORTED. */ public static final String RULE_IS_NOT_SUPPORTED = "The rule @{0} is unsupported. All selectors in this rule will be ignored."; public static final String NAN = "The passed value (@{0}) is not a number"; + /** The Constant UNABLE_TO_RETRIEVE_IMAGE_WITH_GIVEN_BASE_URI. */ + public static final String UNABLE_TO_RETRIEVE_IMAGE_WITH_GIVEN_BASE_URI = "Unable to retrieve image with given base URI ({0}) and image source path ({1})"; + /** The Constant UNABLE_TO_RETRIEVE_STREAM_WITH_GIVEN_BASE_URI. */ + public static final String UNABLE_TO_RETRIEVE_STREAM_WITH_GIVEN_BASE_URI = "Unable to retrieve stream with given base URI ({0}) and source path ({1})"; + public static final String UNABLE_TO_PROCESS_EXTERNAL_CSS_FILE = "Unable to process external css file" ; + /** * Instantiates a new log message constant. diff --git a/src/main/java/com/itextpdf/styledxmlparser/resolver/font/DefaultFontProvider.java b/src/main/java/com/itextpdf/styledxmlparser/resolver/font/DefaultFontProvider.java new file mode 100644 index 0000000000..ae11861eb5 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/resolver/font/DefaultFontProvider.java @@ -0,0 +1,118 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.resolver.font; + +import com.itextpdf.io.util.ResourceUtil; +import com.itextpdf.io.util.StreamUtil; +import com.itextpdf.layout.font.FontProvider; + +import java.io.InputStream; + +/** + * The default {@link FontProvider} that, as opposed to + * the font provider in iText 7, also includes a series of fonts that + * are shipped with the implementation. + */ +public class DefaultFontProvider extends FontProvider { + + /** The path to the shipped fonts. */ + private static final String SHIPPED_FONT_RESOURCE_PATH = "com/itextpdf/html2pdf/font/"; + + /** The file names of the shipped fonts. */ + private static final String[] SHIPPED_FONT_NAMES = new String[] { + "FreeMono.ttf", + "FreeMonoBold.ttf", + "FreeMonoBoldOblique.ttf", + "FreeMonoOblique.ttf", + "FreeSans.ttf", + "FreeSansBold.ttf", + "FreeSansBoldOblique.ttf", + "FreeSansOblique.ttf", + "FreeSerif.ttf", + "FreeSerifBold.ttf", + "FreeSerifBoldItalic.ttf", + "FreeSerifItalic.ttf", + }; + + /** + * Creates a new {@link DefaultFontProvider} instance. + */ + public DefaultFontProvider() { + this(true, true, false); + } + + /** + * Creates a new {@link DefaultFontProvider} instance. + * + * @param registerStandardPdfFonts use true if you want to register the standard Type 1 fonts (can't be embedded) + * @param registerShippedFreeFonts use true if you want to register the shipped fonts (can be embedded) + * @param registerSystemFonts use true if you want to register the system fonts (can require quite some resources) + */ + public DefaultFontProvider(boolean registerStandardPdfFonts, boolean registerShippedFreeFonts, boolean registerSystemFonts) { + super(); + if (registerStandardPdfFonts) { + addStandardPdfFonts(); + } + if (registerShippedFreeFonts) { + addShippedFreeFonts(); + } + if (registerSystemFonts) { + addSystemFonts(); + } + } + + /** + * Adds the shipped free fonts. + */ + private void addShippedFreeFonts() { + for (String fontName : SHIPPED_FONT_NAMES) { + InputStream stream = ResourceUtil.getResourceStream(SHIPPED_FONT_RESOURCE_PATH + fontName); + try { + byte[] fontProgramBytes = StreamUtil.inputStreamToArray(stream); + addFont(fontProgramBytes); + } catch (Exception exc) { + } + } + } + +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/resolver/font/package-info.java b/src/main/java/com/itextpdf/styledxmlparser/resolver/font/package-info.java new file mode 100644 index 0000000000..4c7e1fc2b2 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/resolver/font/package-info.java @@ -0,0 +1 @@ +package com.itextpdf.styledxmlparser.resolver.font; \ No newline at end of file diff --git a/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolver.java b/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolver.java new file mode 100644 index 0000000000..c4e7d777da --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolver.java @@ -0,0 +1,193 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.resolver.resource; + + +import com.itextpdf.io.codec.Base64; +import com.itextpdf.io.image.ImageDataFactory; +import com.itextpdf.io.util.MessageFormatUtil; +import com.itextpdf.io.util.StreamUtil; +import com.itextpdf.io.util.UrlUtil; +import com.itextpdf.kernel.pdf.xobject.PdfImageXObject; +import com.itextpdf.styledxmlparser.LogMessageConstant; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; + +/** + * Utilities class to resolve resources. + */ +// TODO handle tag? +public class ResourceResolver { + + /** The {@link UriResolver} instance. */ + private UriResolver uriResolver; + + /** The {@link SimpleImageCache} instance. */ + // TODO provide a way to configure capacity, manually reset or disable the image cache? + private SimpleImageCache imageCache; + + /** + * Creates {@link ResourceResolver} instance. If {@code baseUri} is a string that represents an absolute URI with any schema + * except "file" - resources url values will be resolved exactly as "new URL(baseUrl, uriString)". Otherwise base URI + * will be handled as path in local file system. + *

+ * The main difference between those two is handling of the relative URIs of resources with slashes in the beginning + * of them (e.g. "/test/uri", or "//itextpdf.com/example_resources/logo.img"): if base URI is handled as local file + * system path, then in those cases resources URIs will be simply concatenated to the base path, rather than processed + * with URI resolution rules (See RFC 3986 "5.4. Reference Resolution Examples"). However absolute resource URIs will + * be processed correctly. + *

+ *

+ * If empty string or relative URI string is passed as base URI, then it will be resolved against current working + * directory of this application instance. + *

+ * + * @param baseUri base URI against which all relative resource URIs will be resolved. + */ + public ResourceResolver(String baseUri) { + this.uriResolver = new UriResolver(baseUri); + this.imageCache = new SimpleImageCache(); + } + + /** + * Retrieve {@link PdfImageXObject}. + * + * @param src either link to file or base64 encoded stream. + * @return PdfImageXObject on success, otherwise null. + */ + public PdfImageXObject retrieveImage(String src) { + if (src == null) { + return null; + } + if (src.contains("base64")) { + try { + String fixedSrc = src.replaceAll("\\s", ""); + fixedSrc = fixedSrc.substring(fixedSrc.indexOf("base64") + 7); + PdfImageXObject imageXObject = imageCache.getImage(fixedSrc); + if (imageXObject == null) { + imageXObject = new PdfImageXObject( ImageDataFactory.create( Base64.decode(fixedSrc))); + imageCache.putImage(fixedSrc, imageXObject); + } + + return imageXObject; + } catch (Exception ignored) { + } + } + + try { + URL url = uriResolver.resolveAgainstBaseUri(src); + url = UrlUtil.getFinalURL(url); + String imageResolvedSrc = url.toExternalForm(); + PdfImageXObject imageXObject = imageCache.getImage(imageResolvedSrc); + if (imageXObject == null) { + imageXObject = new PdfImageXObject( ImageDataFactory.create(url)); + imageCache.putImage(imageResolvedSrc, imageXObject); + } + return imageXObject; + } catch (Exception e) { + Logger logger = LoggerFactory.getLogger(ResourceResolver.class); + logger.error( MessageFormatUtil.format( LogMessageConstant.UNABLE_TO_RETRIEVE_IMAGE_WITH_GIVEN_BASE_URI, uriResolver.getBaseUri(), src), e); + return null; + } + } + + /** + * Open an {@link InputStream} to a style sheet URI. + * + * @param uri the URI + * @return the {@link InputStream} + * @throws IOException Signals that an I/O exception has occurred. + */ + public InputStream retrieveStyleSheet(String uri) throws IOException { + return uriResolver.resolveAgainstBaseUri(uri).openStream(); + } + + /** + * Retrieve a resource as a byte array from a source that + * can either be a link to a file, or a base64 encoded {@link String}. + * + * @param src either link to file or base64 encoded stream. + * @return byte[] on success, otherwise null. + */ + public byte[] retrieveStream(String src) { + if (src.contains("base64")) { + try { + String fixedSrc = src.replaceAll("\\s", ""); + fixedSrc = fixedSrc.substring(fixedSrc.indexOf("base64") + 7); + return Base64.decode(fixedSrc); + } catch (Exception ignored) { + } + } + + try { + return StreamUtil.inputStreamToArray(uriResolver.resolveAgainstBaseUri(src).openStream()); + } catch (Exception e) { + Logger logger = LoggerFactory.getLogger(ResourceResolver.class); + logger.error( MessageFormatUtil.format(LogMessageConstant.UNABLE_TO_RETRIEVE_STREAM_WITH_GIVEN_BASE_URI, uriResolver.getBaseUri(), src), e); + return null; + } + } + + /** + * Resolves a given URI against the base URI. + * + * @param uri the uri + * @return the url + * @throws MalformedURLException the malformed URL exception + */ + public URL resolveAgainstBaseUri(String uri) throws MalformedURLException { + return uriResolver.resolveAgainstBaseUri(uri); + } + + /** + * Resets the simple image cache. + */ + public void resetCache() { + imageCache.reset(); + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/SimpleImageCache.java b/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/SimpleImageCache.java new file mode 100644 index 0000000000..0862279e21 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/SimpleImageCache.java @@ -0,0 +1,154 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.resolver.resource; + +import com.itextpdf.kernel.pdf.xobject.PdfImageXObject; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Simple implementation of an image cache. + */ +class SimpleImageCache { + + /** The cache mapping a source path to an Image XObject. */ + private Map cache = new LinkedHashMap<>(); + + /** Stores how many times each image is used. */ + private Map imagesFrequency = new LinkedHashMap<>(); + + /** The capacity of the cache. */ + private int capacity; + + /** + * Creates a new {@link SimpleImageCache} instance. + */ + SimpleImageCache() { + this.capacity = 100; + } + + /** + * Creates a new {@link SimpleImageCache} instance. + * + * @param capacity the capacity + */ + SimpleImageCache(int capacity) { + if (capacity < 1) { + throw new IllegalArgumentException("capacity"); + } + this.capacity = capacity; + } + + /** + * Adds an image to the cache. + * + * @param src the source path + * @param imageXObject the image XObject to be cached + */ + void putImage(String src, PdfImageXObject imageXObject) { + if (cache.containsKey(src)) { + return; + } + ensureCapacity(); + cache.put(src, imageXObject); + } + + /** + * Gets an image from the cache. + * + * @param src the source path + * @return the image XObject + */ + PdfImageXObject getImage(String src) { + Integer frequency = imagesFrequency.get(src); + if (frequency != null) { + imagesFrequency.put(src, frequency + 1); + } else { + imagesFrequency.put(src, 1); + } + + return cache.get(src); + } + + /** + * Gets the size of the cache. + * + * @return the cache size + */ + int size() { + return cache.size(); + } + + /** + * Resets the cache. + */ + void reset() { + cache.clear(); + imagesFrequency.clear(); + } + + /** + * Ensures the capacity of the cache by removing the least important images + * (based on the number of times an image is used). + */ + private void ensureCapacity() { + if (cache.size() >= capacity) { + String mostUnpopularImg = null; + int minFrequency = Integer.MAX_VALUE; + for (String imgSrc : cache.keySet()) { // TODO keySet preserves order of LinkedList? and in .net? + Integer imgFrequency = imagesFrequency.get(imgSrc); + if (imgFrequency == null || imgFrequency < minFrequency) { + mostUnpopularImg = imgSrc; + if (imgFrequency == null) { + break; + } else { + minFrequency = (int) imgFrequency; + } + } + } + + cache.remove(mostUnpopularImg); + } + } +} diff --git a/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/SimpleImageCacheTest.java b/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/SimpleImageCacheTest.java new file mode 100644 index 0000000000..4c4c46701b --- /dev/null +++ b/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/SimpleImageCacheTest.java @@ -0,0 +1,165 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 iText Group NV + Authors: iText Software. + + 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.styledxmlparser.resolver.resource; + +import com.itextpdf.kernel.pdf.PdfStream; +import com.itextpdf.kernel.pdf.xobject.PdfImageXObject; +import com.itextpdf.test.ExtendedITextTest; +import com.itextpdf.test.annotations.type.UnitTest; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +@Category(UnitTest.class) +public class SimpleImageCacheTest extends ExtendedITextTest { + + @Before + public void before() { + ImageXObjectStub.resetNumbering(); + } + + @Test + public void simpleImageCacheTest01() { + SimpleImageCache cache = new SimpleImageCache(); + String imgSrc = "src1.jpg"; + ImageXObjectStub imageData = new ImageXObjectStub(); + Assert.assertEquals(0, cache.size()); + cache.putImage(imgSrc, imageData); + Assert.assertEquals(1, cache.size()); + Assert.assertEquals(imageData, cache.getImage(imgSrc)); + } + + @Test + public void simpleImageCacheTest02() { + String[] imgSrc = {"src0.jpg", "src1.jpg", "src2.jpg", "src3.jpg", "src4.jpg", "src5.jpg"}; + ImageXObjectStub[] imgData = {new ImageXObjectStub(), new ImageXObjectStub(), new ImageXObjectStub(), new ImageXObjectStub(), + new ImageXObjectStub(), new ImageXObjectStub()}; + + SimpleImageCache cache = new SimpleImageCache(4); + + // imgs frequency is increased on getImage call + cache.getImage(imgSrc[1]); + cache.getImage(imgSrc[2]); + + cache.putImage(imgSrc[0], imgData[0]); + cache.putImage(imgSrc[1], imgData[1]); + cache.putImage(imgSrc[2], imgData[2]); + Assert.assertEquals(3, cache.size()); + + cache.getImage(imgSrc[0]); + cache.getImage(imgSrc[1]); + cache.getImage(imgSrc[2]); + + cache.putImage(imgSrc[3], imgData[3]); + Assert.assertEquals(4, cache.size()); + + cache.putImage(imgSrc[4], imgData[4]); + Assert.assertEquals(4, cache.size()); + Assert.assertNull(cache.getImage(imgSrc[3])); + Assert.assertEquals(imgData[0], cache.getImage(imgSrc[0])); + Assert.assertEquals(imgData[1], cache.getImage(imgSrc[1])); + Assert.assertEquals(imgData[2], cache.getImage(imgSrc[2])); + Assert.assertEquals(imgData[4], cache.getImage(imgSrc[4])); + + cache.getImage(imgSrc[0]); + cache.getImage(imgSrc[1]); + cache.getImage(imgSrc[2]); + cache.getImage(imgSrc[4]); + + cache.putImage(imgSrc[5], imgData[5]); + Assert.assertEquals(4, cache.size()); + Assert.assertNull(cache.getImage(imgSrc[4])); + Assert.assertEquals(imgData[0], cache.getImage(imgSrc[0])); + Assert.assertEquals(imgData[1], cache.getImage(imgSrc[1])); + Assert.assertEquals(imgData[2], cache.getImage(imgSrc[2])); + Assert.assertEquals(imgData[5], cache.getImage(imgSrc[5])); + + + cache.putImage(imgSrc[3], imgData[3]); + Assert.assertEquals(4, cache.size()); + Assert.assertEquals(imgData[3], cache.getImage(imgSrc[3])); + Assert.assertNull(cache.getImage(imgSrc[5])); + + cache.putImage(imgSrc[5], imgData[5]); + Assert.assertEquals(4, cache.size()); + Assert.assertEquals(imgData[5], cache.getImage(imgSrc[5])); + Assert.assertNull(cache.getImage(imgSrc[3])); + + cache.putImage(imgSrc[3], imgData[3]); + Assert.assertEquals(4, cache.size()); + Assert.assertEquals(imgData[3], cache.getImage(imgSrc[3])); + Assert.assertNull(cache.getImage(imgSrc[5])); + + cache.putImage(imgSrc[5], imgData[5]); + Assert.assertEquals(4, cache.size()); + Assert.assertEquals(imgData[5], cache.getImage(imgSrc[5])); + Assert.assertEquals(imgData[3], cache.getImage(imgSrc[3])); + + + Assert.assertEquals(imgData[1], cache.getImage(imgSrc[1])); + Assert.assertEquals(imgData[2], cache.getImage(imgSrc[2])); + Assert.assertNull(cache.getImage(imgSrc[0])); + Assert.assertNull(cache.getImage(imgSrc[4])); + + } + + private static class ImageXObjectStub extends PdfImageXObject { + private static int totalNum = 0; + private int num = 0; + + ImageXObjectStub() { + super(new PdfStream()); + num = totalNum++; + } + + public static void resetNumbering() { + totalNum = 0; + } + + @Override + public String toString() { + return "ImageXObjectStub_" + String.valueOf(num); + } + } +} diff --git a/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolverTest.java b/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolverTest.java new file mode 100644 index 0000000000..9bd98f3d2d --- /dev/null +++ b/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolverTest.java @@ -0,0 +1,217 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 iText Group NV + Authors: iText Software. + + 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.styledxmlparser.resolver.resource; + +import com.itextpdf.test.ExtendedITextTest; +import com.itextpdf.test.annotations.type.UnitTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.ExpectedException; + +import java.net.MalformedURLException; +import java.nio.file.Paths; + +@Category(UnitTest.class) +public class UriResolverTest extends ExtendedITextTest { + + @Rule + public ExpectedException junitExpectedException = ExpectedException.none(); + + @Test + public void uriResolverTest01() throws MalformedURLException { + String absolutePathRoot = "file://" + Paths.get("").toAbsolutePath().getRoot().toString().replace('\\', '/').replaceFirst("^/", ""); + String absoluteBaseUri = absolutePathRoot + "test/folder/index.svg"; + UriResolver resolver = new UriResolver(absoluteBaseUri); + Assert.assertEquals(absolutePathRoot + "test/folder/index.svg", resolver.getBaseUri()); + Assert.assertEquals(absolutePathRoot + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); + Assert.assertEquals(absolutePathRoot + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); + Assert.assertEquals(absolutePathRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertEquals(absolutePathRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); + } + + @Test + public void uriResolverTest02() throws MalformedURLException { + UriResolver resolver = new UriResolver("test/folder/index.svg"); + String runFolder = Paths.get("").toUri().toURL().toExternalForm(); + Assert.assertEquals(runFolder + "test/folder/index.svg", resolver.getBaseUri()); + Assert.assertEquals(runFolder + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); + Assert.assertEquals(runFolder + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); + Assert.assertEquals(runFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertEquals(runFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); + } + + @Test + public void uriResolverTest03() throws MalformedURLException { + UriResolver resolver = new UriResolver("/test/folder/index.svg"); + String rootFolder = Paths.get("").toAbsolutePath().getRoot().toUri().toURL().toExternalForm(); + Assert.assertEquals(rootFolder + "test/folder/index.svg", resolver.getBaseUri()); + Assert.assertEquals(rootFolder + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); + Assert.assertEquals(rootFolder + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); + Assert.assertEquals(rootFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertEquals(rootFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); + } + + @Test + public void uriResolverTest04() throws MalformedURLException { + UriResolver resolver = new UriResolver("index.svg"); + String runFolder = Paths.get("").toUri().toURL().toExternalForm(); + Assert.assertEquals(runFolder + "index.svg", resolver.getBaseUri()); + Assert.assertEquals(runFolder + "innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); + Assert.assertEquals(runFolder + "folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertEquals(runFolder + "folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); + } + + @Test + public void uriResolverTest05() throws MalformedURLException { + UriResolver resolver = new UriResolver("/../test/folder/index.svg"); + String rootFolder = Paths.get("").toAbsolutePath().getRoot().toUri().toURL().toExternalForm(); + Assert.assertEquals(rootFolder + "test/folder/index.svg", resolver.getBaseUri()); + Assert.assertEquals(rootFolder + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); + Assert.assertEquals(rootFolder + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); + Assert.assertEquals(rootFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertEquals(rootFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); + } + + @Test + public void uriResolverTest06() throws MalformedURLException { + UriResolver resolver = new UriResolver("../test/folder/index.svg"); + String parentFolder = Paths.get("").toAbsolutePath().getParent().toUri().toURL().toExternalForm(); + Assert.assertEquals(parentFolder + "test/folder/index.svg", resolver.getBaseUri()); + Assert.assertEquals(parentFolder + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); + Assert.assertEquals(parentFolder + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); + Assert.assertEquals(parentFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertEquals(parentFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); + } + + @Test + public void uriResolverTest07() throws MalformedURLException { + UriResolver resolver = new UriResolver("http://itextpdf.com/itext7"); + Assert.assertEquals("http://itextpdf.com/itext7", resolver.getBaseUri()); + Assert.assertEquals("http://itextpdf.com/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); + Assert.assertEquals("http://itextpdf.com/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertEquals("http://folder2.com/innerTest2", resolver.resolveAgainstBaseUri("//folder2.com/innerTest2").toExternalForm()); + } + + @Test + public void uriResolverTest08() throws MalformedURLException { + UriResolver resolver = new UriResolver("http://itextpdf.com/itext7/"); + Assert.assertEquals("http://itextpdf.com/itext7/", resolver.getBaseUri()); + Assert.assertEquals("http://itextpdf.com/itext7/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); + Assert.assertEquals("http://itextpdf.com/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertEquals("http://folder2.com/innerTest2", resolver.resolveAgainstBaseUri("//folder2.com/innerTest2").toExternalForm()); + } + + @Test + public void uriResolverTest09() throws MalformedURLException { + String absolutePathRoot = Paths.get("").toAbsolutePath().getRoot().toString().replace('\\', '/'); + String absoluteBaseUri = absolutePathRoot + "test/folder/index.svg"; + UriResolver resolver = new UriResolver(absoluteBaseUri); + + String uriRoot = Paths.get("").toAbsolutePath().getRoot().toUri().toURL().toExternalForm(); + Assert.assertEquals(uriRoot + "test/folder/index.svg", resolver.getBaseUri()); + Assert.assertEquals(uriRoot + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); + Assert.assertEquals(uriRoot + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); + Assert.assertEquals(uriRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertEquals(uriRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); + } + + @Test + public void uriResolverTest13() throws MalformedURLException { + UriResolver resolver = new UriResolver(""); + String runFolder = Paths.get("").toUri().toURL().toExternalForm(); + Assert.assertEquals(runFolder, resolver.getBaseUri()); + Assert.assertEquals(runFolder + "innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); + String parentToRunFolder = Paths.get("").toAbsolutePath().getParent().toUri().toURL().toExternalForm(); + Assert.assertEquals(parentToRunFolder + "folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); + Assert.assertEquals(runFolder + "folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertEquals(runFolder + "folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); + } + + @Test + public void uriResolverTest14() throws MalformedURLException { + UriResolver resolver = new UriResolver("base/uri/index.svg"); + String runFolder = Paths.get("").toUri().toURL().toExternalForm(); + Assert.assertEquals(runFolder + "base/uri/index.svg", resolver.getBaseUri()); + Assert.assertEquals("file:/c:/test/folder/img.txt", resolver.resolveAgainstBaseUri("file:/c:/test/folder/img.txt").toExternalForm()); + Assert.assertEquals("file://c:/test/folder/img.txt", resolver.resolveAgainstBaseUri("file://c:/test/folder/img.txt").toExternalForm()); + Assert.assertEquals("file:/c:/test/folder/data.jpg", resolver.resolveAgainstBaseUri("file:///c:/test/folder/data.jpg").toExternalForm()); + + // It is windows specific to assume this to work. On unix it shall fail, as it will assume that it is + // an absolute URI with scheme 'c', and will not recognize this scheme. + // Assert.assertEquals("file:/c:/test/folder/data.jpg", resolver.resolveAgainstBaseUri("c:/test/folder/data.jpg").toExternalForm()); + } + + @Test + public void uriResolverTest15() throws MalformedURLException { + String absolutePathRoot = "file:/" + Paths.get("").toAbsolutePath().getRoot().toString().replace('\\', '/').replaceFirst("^/", ""); + String absoluteBaseUri = absolutePathRoot + "test/folder/index.svg"; + UriResolver resolver = new UriResolver(absoluteBaseUri); + Assert.assertEquals(absolutePathRoot + "test/folder/index.svg", resolver.getBaseUri()); + Assert.assertEquals(absolutePathRoot + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); + Assert.assertEquals(absolutePathRoot + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); + Assert.assertEquals(absolutePathRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertEquals(absolutePathRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); + } + + @Test + public void uriResolverTest16() throws MalformedURLException { + String absolutePathRoot = "file:///" + Paths.get("").toAbsolutePath().getRoot().toString().replace('\\', '/').replaceFirst("^/", ""); + String absoluteBaseUri = absolutePathRoot + "test/folder/index.svg"; + UriResolver resolver = new UriResolver(absoluteBaseUri); + String singleSlashRootPath = absolutePathRoot.replace("///", "/"); + Assert.assertEquals(singleSlashRootPath + "test/folder/index.svg", resolver.getBaseUri()); + Assert.assertEquals(singleSlashRootPath + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); + Assert.assertEquals(singleSlashRootPath + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); + Assert.assertEquals(singleSlashRootPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertEquals(singleSlashRootPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); + } + + @Test + public void uriResolverTest17() throws MalformedURLException { + String absolutePathRoot = "file:///" + Paths.get("").toAbsolutePath().getRoot().toString().replace('\\', '/').replaceFirst("^/", ""); + String absoluteBaseUri = absolutePathRoot + "test/fol ders/wi@th/diffe#rent/$characters/index.svg\t\t\t\t\t\t"; + UriResolver resolver = new UriResolver(absoluteBaseUri); + } +} From 60db899b0d5f6d7bf0d1fec0214789df85d69f53 Mon Sep 17 00:00:00 2001 From: Pavel Alay Date: Wed, 2 May 2018 12:47:46 +0300 Subject: [PATCH 03/23] Port UriResolver from pdfHTML RND-864 --- .../resolver/resource/UriResolver.java | 69 ++++++++++--------- .../resolver/resource/UriResolverTest.java | 56 +++++++++------ 2 files changed, 70 insertions(+), 55 deletions(-) diff --git a/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolver.java b/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolver.java index 45bcd61602..d60ddf8451 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolver.java +++ b/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolver.java @@ -43,26 +43,27 @@ This file is part of the iText (R) project. package com.itextpdf.styledxmlparser.resolver.resource; import com.itextpdf.io.util.MessageFormatUtil; -import com.itextpdf.styledxmlparser.exceptions.StyledXMLParserException; import java.net.MalformedURLException; import java.net.URI; -import java.net.URISyntaxException; import java.net.URL; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * Utilities class to resolve URIs. */ public class UriResolver { - /** The base url. */ + /** + * The base url. + */ private URL baseUrl; - /** Indicates if the Uri refers to a local resource. */ + /** + * Indicates if the Uri refers to a local resource. + */ private boolean isLocalBaseUri; /** @@ -94,7 +95,6 @@ public URL resolveAgainstBaseUri(String uriString) throws MalformedURLException URL resolvedUrl = null; uriString = uriString.trim(); // decode and then encode uri string in order to process unsafe characters correctly - String scheme = getUriStringScheme(uriString); uriString = UriEncodeUtil.encode(uriString); if (isLocalBaseUri) { // remove leading slashes in order to always concatenate such resource URIs: we don't want to scatter all @@ -120,6 +120,15 @@ public URL resolveAgainstBaseUri(String uriString) throws MalformedURLException return resolvedUrl; } + /** + * Check if baseURI is local + * + * @return true if baseURI is local, otherwise false + */ + public boolean isLocalBaseUri() { + return isLocalBaseUri; + } + /** * Resolves the base URI to an URL or path. * @@ -127,15 +136,14 @@ public URL resolveAgainstBaseUri(String uriString) throws MalformedURLException */ private void resolveBaseUrlOrPath(String base) { base = base.trim(); - String scheme = getUriStringScheme(base); - base = UriEncodeUtil.encode(base); - baseUrl = baseUriAsUrl(base); + baseUrl = baseUriAsUrl(UriEncodeUtil.encode(base)); if (baseUrl == null) { baseUrl = uriAsFileUrl(base); } if (baseUrl == null) { - throw new StyledXMLParserException(MessageFormatUtil.format("Invalid base URI: {0}", base)); + // TODO Html2PdfException? + throw new IllegalArgumentException(MessageFormatUtil.format("Invalid base URI: {0}", base)); } } @@ -171,7 +179,14 @@ private URL uriAsFileUrl(String baseUriString) { URL baseAsFileUrl = null; try { Path path = Paths.get(baseUriString); - baseAsFileUrl = path.toAbsolutePath().normalize().toUri().toURL(); + if (isPathRooted(path, baseUriString)) { + String str = "file:///" + encode(path, path.toAbsolutePath().normalize().toString()); + baseAsFileUrl = new URI(str).toURL(); + } else { + String str = encode(path, baseUriString); + URL base = Paths.get("").toUri().toURL(); + baseAsFileUrl = new URL(base, str); + } isLocalBaseUri = true; } catch (Exception ignored) { } @@ -179,29 +194,17 @@ private URL uriAsFileUrl(String baseUriString) { return baseAsFileUrl; } - /** - * Get the scheme component of this URI. - */ - private String getUriStringScheme(String uriString) { - String result = null; - Matcher matcher = Pattern.compile("^[a-zA-Z]([a-zA-Z]|\\d|\\+|-|\\.)*:").matcher(uriString); - if (matcher.find()) { - result = matcher.group().substring(0, matcher.group().indexOf(':')); - } else if (null != baseUrl) { - try { - result = baseUrl.toURI().getScheme(); - } catch (URISyntaxException ignored) { - } + private String encode(Path path, String str) { + str = str.replace("\\", "/"); + str = UriEncodeUtil.encode(str); + if (Files.isDirectory(path) && !str.endsWith("/")) { + str += "/"; } - return result; + str = str.replaceFirst("/*\\\\*", ""); + return str; } - /** - * Check if baseURI is local - * - * @return true if baseURI is local, otherwise false - */ - public boolean isLocalBaseUri() { - return isLocalBaseUri; + private boolean isPathRooted(Path path, String str) { + return path.isAbsolute() || str.startsWith("/"); } } diff --git a/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolverTest.java b/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolverTest.java index 9bd98f3d2d..da4cf8d442 100644 --- a/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolverTest.java +++ b/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolverTest.java @@ -61,10 +61,22 @@ public class UriResolverTest extends ExtendedITextTest { @Test public void uriResolverTest01() throws MalformedURLException { - String absolutePathRoot = "file://" + Paths.get("").toAbsolutePath().getRoot().toString().replace('\\', '/').replaceFirst("^/", ""); - String absoluteBaseUri = absolutePathRoot + "test/folder/index.svg"; + String absolutePathRoot = Paths.get("").toAbsolutePath().getRoot().toUri().toURL().toExternalForm().replace('\\', '/').replaceFirst("^/", ""); + String absoluteBaseUri = absolutePathRoot + "test/folder/index.html"; UriResolver resolver = new UriResolver(absoluteBaseUri); - Assert.assertEquals(absolutePathRoot + "test/folder/index.svg", resolver.getBaseUri()); + Assert.assertEquals(absolutePathRoot + "test/folder/index.html", resolver.getBaseUri()); + Assert.assertEquals(absolutePathRoot + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); + Assert.assertEquals(absolutePathRoot + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); + Assert.assertEquals(absolutePathRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertEquals(absolutePathRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); + } + + @Test + public void uriResolverTest01A() throws MalformedURLException { + String absolutePathRoot = Paths.get("").toAbsolutePath().toUri().toURL().toExternalForm().replace('\\', '/').replaceFirst("^/", ""); + String absoluteBaseUri = absolutePathRoot + "test/folder/index.html"; + UriResolver resolver = new UriResolver(absoluteBaseUri); + Assert.assertEquals(absolutePathRoot + "test/folder/index.html", resolver.getBaseUri()); Assert.assertEquals(absolutePathRoot + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); Assert.assertEquals(absolutePathRoot + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); Assert.assertEquals(absolutePathRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); @@ -73,9 +85,9 @@ public void uriResolverTest01() throws MalformedURLException { @Test public void uriResolverTest02() throws MalformedURLException { - UriResolver resolver = new UriResolver("test/folder/index.svg"); + UriResolver resolver = new UriResolver("test/folder/index.html"); String runFolder = Paths.get("").toUri().toURL().toExternalForm(); - Assert.assertEquals(runFolder + "test/folder/index.svg", resolver.getBaseUri()); + Assert.assertEquals(runFolder + "test/folder/index.html", resolver.getBaseUri()); Assert.assertEquals(runFolder + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); Assert.assertEquals(runFolder + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); Assert.assertEquals(runFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); @@ -84,9 +96,9 @@ public void uriResolverTest02() throws MalformedURLException { @Test public void uriResolverTest03() throws MalformedURLException { - UriResolver resolver = new UriResolver("/test/folder/index.svg"); + UriResolver resolver = new UriResolver("/test/folder/index.html"); String rootFolder = Paths.get("").toAbsolutePath().getRoot().toUri().toURL().toExternalForm(); - Assert.assertEquals(rootFolder + "test/folder/index.svg", resolver.getBaseUri()); + Assert.assertEquals(rootFolder + "test/folder/index.html", resolver.getBaseUri()); Assert.assertEquals(rootFolder + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); Assert.assertEquals(rootFolder + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); Assert.assertEquals(rootFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); @@ -95,9 +107,9 @@ public void uriResolverTest03() throws MalformedURLException { @Test public void uriResolverTest04() throws MalformedURLException { - UriResolver resolver = new UriResolver("index.svg"); + UriResolver resolver = new UriResolver("index.html"); String runFolder = Paths.get("").toUri().toURL().toExternalForm(); - Assert.assertEquals(runFolder + "index.svg", resolver.getBaseUri()); + Assert.assertEquals(runFolder + "index.html", resolver.getBaseUri()); Assert.assertEquals(runFolder + "innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); Assert.assertEquals(runFolder + "folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); Assert.assertEquals(runFolder + "folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); @@ -105,9 +117,9 @@ public void uriResolverTest04() throws MalformedURLException { @Test public void uriResolverTest05() throws MalformedURLException { - UriResolver resolver = new UriResolver("/../test/folder/index.svg"); + UriResolver resolver = new UriResolver("/../test/folder/index.html"); String rootFolder = Paths.get("").toAbsolutePath().getRoot().toUri().toURL().toExternalForm(); - Assert.assertEquals(rootFolder + "test/folder/index.svg", resolver.getBaseUri()); + Assert.assertEquals(rootFolder + "test/folder/index.html", resolver.getBaseUri()); Assert.assertEquals(rootFolder + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); Assert.assertEquals(rootFolder + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); Assert.assertEquals(rootFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); @@ -116,9 +128,9 @@ public void uriResolverTest05() throws MalformedURLException { @Test public void uriResolverTest06() throws MalformedURLException { - UriResolver resolver = new UriResolver("../test/folder/index.svg"); + UriResolver resolver = new UriResolver("../test/folder/index.html"); String parentFolder = Paths.get("").toAbsolutePath().getParent().toUri().toURL().toExternalForm(); - Assert.assertEquals(parentFolder + "test/folder/index.svg", resolver.getBaseUri()); + Assert.assertEquals(parentFolder + "test/folder/index.html", resolver.getBaseUri()); Assert.assertEquals(parentFolder + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); Assert.assertEquals(parentFolder + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); Assert.assertEquals(parentFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); @@ -146,11 +158,11 @@ public void uriResolverTest08() throws MalformedURLException { @Test public void uriResolverTest09() throws MalformedURLException { String absolutePathRoot = Paths.get("").toAbsolutePath().getRoot().toString().replace('\\', '/'); - String absoluteBaseUri = absolutePathRoot + "test/folder/index.svg"; + String absoluteBaseUri = absolutePathRoot + "test/folder/index.html"; UriResolver resolver = new UriResolver(absoluteBaseUri); String uriRoot = Paths.get("").toAbsolutePath().getRoot().toUri().toURL().toExternalForm(); - Assert.assertEquals(uriRoot + "test/folder/index.svg", resolver.getBaseUri()); + Assert.assertEquals(uriRoot + "test/folder/index.html", resolver.getBaseUri()); Assert.assertEquals(uriRoot + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); Assert.assertEquals(uriRoot + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); Assert.assertEquals(uriRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); @@ -171,9 +183,9 @@ public void uriResolverTest13() throws MalformedURLException { @Test public void uriResolverTest14() throws MalformedURLException { - UriResolver resolver = new UriResolver("base/uri/index.svg"); + UriResolver resolver = new UriResolver("base/uri/index.html"); String runFolder = Paths.get("").toUri().toURL().toExternalForm(); - Assert.assertEquals(runFolder + "base/uri/index.svg", resolver.getBaseUri()); + Assert.assertEquals(runFolder + "base/uri/index.html", resolver.getBaseUri()); Assert.assertEquals("file:/c:/test/folder/img.txt", resolver.resolveAgainstBaseUri("file:/c:/test/folder/img.txt").toExternalForm()); Assert.assertEquals("file://c:/test/folder/img.txt", resolver.resolveAgainstBaseUri("file://c:/test/folder/img.txt").toExternalForm()); Assert.assertEquals("file:/c:/test/folder/data.jpg", resolver.resolveAgainstBaseUri("file:///c:/test/folder/data.jpg").toExternalForm()); @@ -186,9 +198,9 @@ public void uriResolverTest14() throws MalformedURLException { @Test public void uriResolverTest15() throws MalformedURLException { String absolutePathRoot = "file:/" + Paths.get("").toAbsolutePath().getRoot().toString().replace('\\', '/').replaceFirst("^/", ""); - String absoluteBaseUri = absolutePathRoot + "test/folder/index.svg"; + String absoluteBaseUri = absolutePathRoot + "test/folder/index.html"; UriResolver resolver = new UriResolver(absoluteBaseUri); - Assert.assertEquals(absolutePathRoot + "test/folder/index.svg", resolver.getBaseUri()); + Assert.assertEquals(absolutePathRoot + "test/folder/index.html", resolver.getBaseUri()); Assert.assertEquals(absolutePathRoot + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); Assert.assertEquals(absolutePathRoot + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); Assert.assertEquals(absolutePathRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); @@ -198,10 +210,10 @@ public void uriResolverTest15() throws MalformedURLException { @Test public void uriResolverTest16() throws MalformedURLException { String absolutePathRoot = "file:///" + Paths.get("").toAbsolutePath().getRoot().toString().replace('\\', '/').replaceFirst("^/", ""); - String absoluteBaseUri = absolutePathRoot + "test/folder/index.svg"; + String absoluteBaseUri = absolutePathRoot + "test/folder/index.html"; UriResolver resolver = new UriResolver(absoluteBaseUri); String singleSlashRootPath = absolutePathRoot.replace("///", "/"); - Assert.assertEquals(singleSlashRootPath + "test/folder/index.svg", resolver.getBaseUri()); + Assert.assertEquals(singleSlashRootPath + "test/folder/index.html", resolver.getBaseUri()); Assert.assertEquals(singleSlashRootPath + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); Assert.assertEquals(singleSlashRootPath + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); Assert.assertEquals(singleSlashRootPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); @@ -211,7 +223,7 @@ public void uriResolverTest16() throws MalformedURLException { @Test public void uriResolverTest17() throws MalformedURLException { String absolutePathRoot = "file:///" + Paths.get("").toAbsolutePath().getRoot().toString().replace('\\', '/').replaceFirst("^/", ""); - String absoluteBaseUri = absolutePathRoot + "test/fol ders/wi@th/diffe#rent/$characters/index.svg\t\t\t\t\t\t"; + String absoluteBaseUri = absolutePathRoot + "test/fol ders/wi@th/diffe#rent/$characters/index.html\t\t\t\t\t\t"; UriResolver resolver = new UriResolver(absoluteBaseUri); } } From 33a8f7b35aaf3c0e7770a67fb08f2fbd1e6099da Mon Sep 17 00:00:00 2001 From: Michael Demey Date: Mon, 30 Apr 2018 14:36:30 +0200 Subject: [PATCH 04/23] Add method to ICssResolver interface. RND-928 --- .../com/itextpdf/styledxmlparser/css/ICssResolver.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/ICssResolver.java b/src/main/java/com/itextpdf/styledxmlparser/css/ICssResolver.java index 54818fe88a..32e235c24c 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/ICssResolver.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/ICssResolver.java @@ -44,6 +44,7 @@ This file is part of the iText (R) project. import com.itextpdf.styledxmlparser.node.INode; +import com.itextpdf.styledxmlparser.resolver.resource.ResourceResolver; import java.util.Map; @@ -52,6 +53,14 @@ This file is part of the iText (R) project. */ public interface ICssResolver { + /** + * Collect all CSS declarations from the provided INode tree. + * + * @param rootNode tree from which to collect CSS + * @param resourceResolver ResourceResolver used to resolve resources + */ + void collectCssDeclarations(INode rootNode, ResourceResolver resourceResolver); + /** * Resolves the styles of a node given the passed context. * From d6ea80599b2363258fa5dedcde40628a25d3bb35 Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 9 May 2018 10:37:51 +0200 Subject: [PATCH 05/23] RND-864 add extra tests to improve coverage results --- .../resource/ResourceResolverTest.java | 241 ++++++++++++++++++ .../resolver/resource/UriResolverTest.java | 5 +- .../resourceResolverTest.png | Bin 0 -> 4313 bytes .../retrieveStyleSheetTest.css | 8 + .../simpleImageCacheTest.png | Bin 0 -> 4313 bytes 5 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolverTest.java create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/resolver/resources/retrieveStreamTest/resourceResolverTest.png create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/resolver/resources/retrieveStreamTest/retrieveStyleSheetTest.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/resolver/resources/simpleImageCacheTest/simpleImageCacheTest.png diff --git a/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolverTest.java b/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolverTest.java new file mode 100644 index 0000000000..23d7ecbe78 --- /dev/null +++ b/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolverTest.java @@ -0,0 +1,241 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 iText Group NV + Authors: iText Software. + + 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.styledxmlparser.resolver.resource; + +import com.itextpdf.kernel.pdf.xobject.PdfImageXObject; +import com.itextpdf.test.ExtendedITextTest; +import com.itextpdf.test.annotations.type.UnitTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.ExpectedException; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.nio.file.Files; +import java.nio.file.Paths; + +@Category(UnitTest.class) +public class ResourceResolverTest extends ExtendedITextTest { + private final String baseUri = "./src/test/resources/com/itextpdf/styledxmlparser/resolver/resources/retrieveStreamTest/"; + @Rule + public ExpectedException junitExpectedException = ExpectedException.none(); + + @Test + public void resourceResolverTest01() throws MalformedURLException { + String absolutePathRoot = Paths.get( "" ).toAbsolutePath().getRoot().toUri().toURL().toExternalForm().replace( '\\', '/' ).replaceFirst( "^/", "" ); + String absoluteBaseUri = absolutePathRoot + "test/folder/index.html"; + ResourceResolver resolver = new ResourceResolver( absoluteBaseUri ); + Assert.assertEquals( absolutePathRoot + "test/folder/innerTest", resolver.resolveAgainstBaseUri( "innerTest" ).toExternalForm() ); + Assert.assertEquals( absolutePathRoot + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri( "../folder2/innerTest2" ).toExternalForm() ); + Assert.assertEquals( absolutePathRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "/folder2/innerTest2" ).toExternalForm() ); + Assert.assertEquals( absolutePathRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "//folder2/innerTest2" ).toExternalForm() ); + } + + @Test + public void resourceResolverTest01A() throws MalformedURLException { + String absolutePathRoot = Paths.get( "" ).toAbsolutePath().toUri().toURL().toExternalForm().replace( '\\', '/' ).replaceFirst( "^/", "" ); + String absoluteBaseUri = absolutePathRoot + "test/folder/index.html"; + ResourceResolver resolver = new ResourceResolver( absoluteBaseUri ); + Assert.assertEquals( absolutePathRoot + "test/folder/innerTest", resolver.resolveAgainstBaseUri( "innerTest" ).toExternalForm() ); + Assert.assertEquals( absolutePathRoot + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri( "../folder2/innerTest2" ).toExternalForm() ); + Assert.assertEquals( absolutePathRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "/folder2/innerTest2" ).toExternalForm() ); + Assert.assertEquals( absolutePathRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "//folder2/innerTest2" ).toExternalForm() ); + } + + @Test + public void resourceResolverTest02() throws MalformedURLException { + ResourceResolver resolver = new ResourceResolver( "test/folder/index.html" ); + String runFolder = Paths.get( "" ).toUri().toURL().toExternalForm(); + Assert.assertEquals( runFolder + "test/folder/innerTest", resolver.resolveAgainstBaseUri( "innerTest" ).toExternalForm() ); + Assert.assertEquals( runFolder + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri( "../folder2/innerTest2" ).toExternalForm() ); + Assert.assertEquals( runFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "/folder2/innerTest2" ).toExternalForm() ); + Assert.assertEquals( runFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "//folder2/innerTest2" ).toExternalForm() ); + } + + @Test + public void resourceResolverTest03() throws MalformedURLException { + ResourceResolver resolver = new ResourceResolver( "/test/folder/index.html" ); + String rootFolder = Paths.get( "" ).toAbsolutePath().getRoot().toUri().toURL().toExternalForm(); + Assert.assertEquals( rootFolder + "test/folder/innerTest", resolver.resolveAgainstBaseUri( "innerTest" ).toExternalForm() ); + Assert.assertEquals( rootFolder + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri( "../folder2/innerTest2" ).toExternalForm() ); + Assert.assertEquals( rootFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "/folder2/innerTest2" ).toExternalForm() ); + Assert.assertEquals( rootFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "//folder2/innerTest2" ).toExternalForm() ); + } + + @Test + public void resourceResolverTest04() throws MalformedURLException { + ResourceResolver resolver = new ResourceResolver( "index.html" ); + String runFolder = Paths.get( "" ).toUri().toURL().toExternalForm(); + Assert.assertEquals( runFolder + "innerTest", resolver.resolveAgainstBaseUri( "innerTest" ).toExternalForm() ); + Assert.assertEquals( runFolder + "folder2/innerTest2", resolver.resolveAgainstBaseUri( "/folder2/innerTest2" ).toExternalForm() ); + Assert.assertEquals( runFolder + "folder2/innerTest2", resolver.resolveAgainstBaseUri( "//folder2/innerTest2" ).toExternalForm() ); + } + + @Test + public void resourceResolverTest05() throws MalformedURLException { + ResourceResolver resolver = new ResourceResolver( "/../test/folder/index.html" ); + String rootFolder = Paths.get( "" ).toAbsolutePath().getRoot().toUri().toURL().toExternalForm(); + Assert.assertEquals( rootFolder + "test/folder/innerTest", resolver.resolveAgainstBaseUri( "innerTest" ).toExternalForm() ); + Assert.assertEquals( rootFolder + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri( "../folder2/innerTest2" ).toExternalForm() ); + Assert.assertEquals( rootFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "/folder2/innerTest2" ).toExternalForm() ); + Assert.assertEquals( rootFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "//folder2/innerTest2" ).toExternalForm() ); + } + + @Test + public void resourceResolverTest06() throws MalformedURLException { + ResourceResolver resolver = new ResourceResolver( "../test/folder/index.html" ); + String parentFolder = Paths.get( "" ).toAbsolutePath().getParent().toUri().toURL().toExternalForm(); + Assert.assertEquals( parentFolder + "test/folder/innerTest", resolver.resolveAgainstBaseUri( "innerTest" ).toExternalForm() ); + Assert.assertEquals( parentFolder + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri( "../folder2/innerTest2" ).toExternalForm() ); + Assert.assertEquals( parentFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "/folder2/innerTest2" ).toExternalForm() ); + Assert.assertEquals( parentFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "//folder2/innerTest2" ).toExternalForm() ); + } + + @Test + public void resourceResolverTest07() throws MalformedURLException { + ResourceResolver resolver = new ResourceResolver( "http://itextpdf.com/itext7" ); + Assert.assertEquals( "http://itextpdf.com/innerTest", resolver.resolveAgainstBaseUri( "innerTest" ).toExternalForm() ); + Assert.assertEquals( "http://itextpdf.com/folder2/innerTest2", resolver.resolveAgainstBaseUri( "/folder2/innerTest2" ).toExternalForm() ); + Assert.assertEquals( "http://folder2.com/innerTest2", resolver.resolveAgainstBaseUri( "//folder2.com/innerTest2" ).toExternalForm() ); + } + + @Test + public void resourceResolverTest08() throws MalformedURLException { + ResourceResolver resolver = new ResourceResolver( "http://itextpdf.com/itext7/" ); + Assert.assertEquals( "http://itextpdf.com/itext7/innerTest", resolver.resolveAgainstBaseUri( "innerTest" ).toExternalForm() ); + Assert.assertEquals( "http://itextpdf.com/folder2/innerTest2", resolver.resolveAgainstBaseUri( "/folder2/innerTest2" ).toExternalForm() ); + Assert.assertEquals( "http://folder2.com/innerTest2", resolver.resolveAgainstBaseUri( "//folder2.com/innerTest2" ).toExternalForm() ); + } + + @Test + public void resourceResolverTest09() throws MalformedURLException { + String absolutePathRoot = Paths.get( "" ).toAbsolutePath().getRoot().toString().replace( '\\', '/' ); + String absoluteBaseUri = absolutePathRoot + "test/folder/index.html"; + ResourceResolver resolver = new ResourceResolver( absoluteBaseUri ); + String uriRoot = Paths.get( "" ).toAbsolutePath().getRoot().toUri().toURL().toExternalForm(); + Assert.assertEquals( uriRoot + "test/folder/innerTest", resolver.resolveAgainstBaseUri( "innerTest" ).toExternalForm() ); + Assert.assertEquals( uriRoot + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri( "../folder2/innerTest2" ).toExternalForm() ); + Assert.assertEquals( uriRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "/folder2/innerTest2" ).toExternalForm() ); + Assert.assertEquals( uriRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "//folder2/innerTest2" ).toExternalForm() ); + } + + @Test + public void resourceResolverTest13() throws MalformedURLException { + ResourceResolver resolver = new ResourceResolver( "" ); + String runFolder = Paths.get( "" ).toUri().toURL().toExternalForm(); + Assert.assertEquals( runFolder + "innerTest", resolver.resolveAgainstBaseUri( "innerTest" ).toExternalForm() ); + String parentToRunFolder = Paths.get( "" ).toAbsolutePath().getParent().toUri().toURL().toExternalForm(); + Assert.assertEquals( parentToRunFolder + "folder2/innerTest2", resolver.resolveAgainstBaseUri( "../folder2/innerTest2" ).toExternalForm() ); + Assert.assertEquals( runFolder + "folder2/innerTest2", resolver.resolveAgainstBaseUri( "/folder2/innerTest2" ).toExternalForm() ); + Assert.assertEquals( runFolder + "folder2/innerTest2", resolver.resolveAgainstBaseUri( "//folder2/innerTest2" ).toExternalForm() ); + } + + @Test + public void resourceResolverTest14() throws MalformedURLException { + ResourceResolver resolver = new ResourceResolver( "base/uri/index.html" ); + String runFolder = Paths.get( "" ).toUri().toURL().toExternalForm(); + Assert.assertEquals( "file:/c:/test/folder/img.txt", resolver.resolveAgainstBaseUri( "file:/c:/test/folder/img.txt" ).toExternalForm() ); + Assert.assertEquals( "file://c:/test/folder/img.txt", resolver.resolveAgainstBaseUri( "file://c:/test/folder/img.txt" ).toExternalForm() ); + Assert.assertEquals( "file:/c:/test/folder/data.jpg", resolver.resolveAgainstBaseUri( "file:///c:/test/folder/data.jpg" ).toExternalForm() ); + } + + @Test + public void resourceResolverTest15() throws MalformedURLException { + String absolutePathRoot = "file:/" + Paths.get( "" ).toAbsolutePath().getRoot().toString().replace( '\\', '/' ).replaceFirst( "^/", "" ); + String absoluteBaseUri = absolutePathRoot + "test/folder/index.html"; + ResourceResolver resolver = new ResourceResolver( absoluteBaseUri ); + Assert.assertEquals( absolutePathRoot + "test/folder/innerTest", resolver.resolveAgainstBaseUri( "innerTest" ).toExternalForm() ); + Assert.assertEquals( absolutePathRoot + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri( "../folder2/innerTest2" ).toExternalForm() ); + Assert.assertEquals( absolutePathRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "/folder2/innerTest2" ).toExternalForm() ); + Assert.assertEquals( absolutePathRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "//folder2/innerTest2" ).toExternalForm() ); + } + + @Test + public void resourceResolverTest16() throws MalformedURLException { + String absolutePathRoot = "file:///" + Paths.get( "" ).toAbsolutePath().getRoot().toString().replace( '\\', '/' ).replaceFirst( "^/", "" ); + String absoluteBaseUri = absolutePathRoot + "test/folder/index.html"; + ResourceResolver resolver = new ResourceResolver( absoluteBaseUri ); + String singleSlashRootPath = absolutePathRoot.replace( "///", "/" ); + Assert.assertEquals( singleSlashRootPath + "test/folder/innerTest", resolver.resolveAgainstBaseUri( "innerTest" ).toExternalForm() ); + Assert.assertEquals( singleSlashRootPath + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri( "../folder2/innerTest2" ).toExternalForm() ); + Assert.assertEquals( singleSlashRootPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "/folder2/innerTest2" ).toExternalForm() ); + Assert.assertEquals( singleSlashRootPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "//folder2/innerTest2" ).toExternalForm() ); + } + + @Test + public void retrieveStreamTest() throws IOException { + String fileName = "resourceResolverTest.png"; + byte[] expected = Files.readAllBytes( new File( baseUri+fileName ).toPath()); + ResourceResolver resourceResolver = new ResourceResolver( baseUri ); + byte[] stream = resourceResolver.retrieveStream( "resourceResolverTest.png" ); + Assert.assertNotNull( stream ); + Assert.assertEquals( expected.length, stream.length ); + } + + @Test + public void retrieveStyleSheetTest() throws IOException { + String fileName = "retrieveStyleSheetTest.css"; + + InputStream expected = new FileInputStream(baseUri+fileName); + ResourceResolver resourceResolver = new ResourceResolver( baseUri ); + InputStream stream = resourceResolver.retrieveStyleSheet( "retrieveStyleSheetTest.css" ); + Assert.assertNotNull( stream ); + Assert.assertEquals( expected.read(), stream.read() ); + } + + @Test + public void retrieveImageTest() throws IOException { + String fileName = "resourceResolverTest.png"; + ResourceResolver resourceResolver = new ResourceResolver( baseUri ); + PdfImageXObject image = resourceResolver.retrieveImage( fileName ); + Assert.assertNotNull( image ); + Assert.assertTrue( image.identifyImageFileExtension().equalsIgnoreCase( "png" ) ); + } + + +} diff --git a/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolverTest.java b/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolverTest.java index da4cf8d442..9f0240b733 100644 --- a/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolverTest.java +++ b/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolverTest.java @@ -185,6 +185,7 @@ public void uriResolverTest13() throws MalformedURLException { public void uriResolverTest14() throws MalformedURLException { UriResolver resolver = new UriResolver("base/uri/index.html"); String runFolder = Paths.get("").toUri().toURL().toExternalForm(); + Assert.assertTrue( resolver.isLocalBaseUri() ); Assert.assertEquals(runFolder + "base/uri/index.html", resolver.getBaseUri()); Assert.assertEquals("file:/c:/test/folder/img.txt", resolver.resolveAgainstBaseUri("file:/c:/test/folder/img.txt").toExternalForm()); Assert.assertEquals("file://c:/test/folder/img.txt", resolver.resolveAgainstBaseUri("file://c:/test/folder/img.txt").toExternalForm()); @@ -222,8 +223,10 @@ public void uriResolverTest16() throws MalformedURLException { @Test public void uriResolverTest17() throws MalformedURLException { - String absolutePathRoot = "file:///" + Paths.get("").toAbsolutePath().getRoot().toString().replace('\\', '/').replaceFirst("^/", ""); + String absolutePathRoot = "http://"; String absoluteBaseUri = absolutePathRoot + "test/fol ders/wi@th/diffe#rent/$characters/index.html\t\t\t\t\t\t"; UriResolver resolver = new UriResolver(absoluteBaseUri); + Assert.assertFalse( resolver.isLocalBaseUri() ); } + } diff --git a/src/test/resources/com/itextpdf/styledxmlparser/resolver/resources/retrieveStreamTest/resourceResolverTest.png b/src/test/resources/com/itextpdf/styledxmlparser/resolver/resources/retrieveStreamTest/resourceResolverTest.png new file mode 100644 index 0000000000000000000000000000000000000000..7dbc85a25b3a8ca794111be24d7c059326aa87fc GIT binary patch literal 4313 zcmeAS@N?(olHy`uVBq!ia0y~yU}<1rVCvvt0*bVIibVk_#^NA%Cx&(BWL^R}Ea{HE zjtmSN`?>!lvI6;>1s;*b3=BdgAk26#O}>JGK_Ji5#WAEJ?(JRsBH?g`1BqVKH8qP{ zrc9XvAzx}(GO4-9 z-2=LH0M0uDRQmMtUxwR!s%#7lcQ)*<mD!qJ5a|vBR8s?-ducjc>d!^ z_os*BUwh42XCq^GbocYeug&?7Uj|0WOpXofcRohvoO?B@6K|Fg#N}kay2@bGrIt%juhHie9zP zxgHy=c94PL0SCv1OOevmJf@|Zmw#E+@a0-@0t4*Kk?S94>d3$Edhvm+`uFX3v9E2- z#2$Zi&biM4k=&_sjdg49qV;Asj*G9p&R_OCe%n5_+uwm1!1!ZnjoWhRH%)I1ubuz& zYtPg_2I~Uio8R7^?tfgFfx*GM;cRxshW7cJU(Erk*q)#J`t_4nKTUissuh_S4#=?F zxU=kb@|=wVg&S`>7FK-xc(mdNS6k8TxD#<5z+h)*EMr*~t^Cfn;O#dXo1e>m-Lep^ z7E@wkaPV!AZGL$+VX}I&uef|%xc=Lu_g?)9z#Oozk-=K1`+V${zw$Hn>}m|;cC*FD z0lm@jL#)o^+pdi7C)U4?sIl0(_d+9oA<*yZIvK2`c3*AtSKD59_rTex+uV_@K;^oO zWhT@5%P($~eeGTsyZvPu&^Zn#!aqDN{I&DU;T^Y_r}J;j-0*bq$MryQrv}-nNAqeQ zoV^N+AOm5>vJ^9J!R!29Vet$MANC3+0F$U7BhW5^QRZkkj3$E7%rIIKjFyO_)xl`B tINBx{Z5xd?3`bkVG;I}6h*!lvI6;>1s;*b3=BdgAk26#O}>JGK_Ji5#WAEJ?(JRsBH?g`1BqVKH8qP{ zrc9XvAzx}(GO4-9 z-2=LH0M0uDRQmMtUxwR!s%#7lcQ)*<mD!qJ5a|vBR8s?-ducjc>d!^ z_os*BUwh42XCq^GbocYeug&?7Uj|0WOpXofcRohvoO?B@6K|Fg#N}kay2@bGrIt%juhHie9zP zxgHy=c94PL0SCv1OOevmJf@|Zmw#E+@a0-@0t4*Kk?S94>d3$Edhvm+`uFX3v9E2- z#2$Zi&biM4k=&_sjdg49qV;Asj*G9p&R_OCe%n5_+uwm1!1!ZnjoWhRH%)I1ubuz& zYtPg_2I~Uio8R7^?tfgFfx*GM;cRxshW7cJU(Erk*q)#J`t_4nKTUissuh_S4#=?F zxU=kb@|=wVg&S`>7FK-xc(mdNS6k8TxD#<5z+h)*EMr*~t^Cfn;O#dXo1e>m-Lep^ z7E@wkaPV!AZGL$+VX}I&uef|%xc=Lu_g?)9z#Oozk-=K1`+V${zw$Hn>}m|;cC*FD z0lm@jL#)o^+pdi7C)U4?sIl0(_d+9oA<*yZIvK2`c3*AtSKD59_rTex+uV_@K;^oO zWhT@5%P($~eeGTsyZvPu&^Zn#!aqDN{I&DU;T^Y_r}J;j-0*bq$MryQrv}-nNAqeQ zoV^N+AOm5>vJ^9J!R!29Vet$MANC3+0F$U7BhW5^QRZkkj3$E7%rIIKjFyO_)xl`B tINBx{Z5xd?3`bkVG;I}6h* Date: Tue, 15 May 2018 10:59:43 +0200 Subject: [PATCH 06/23] Revert "RND-864 add extra tests to improve coverage results" This reverts commit d6ea80599b2363258fa5dedcde40628a25d3bb35. --- .../resource/ResourceResolverTest.java | 241 ------------------ .../resolver/resource/UriResolverTest.java | 5 +- .../resourceResolverTest.png | Bin 4313 -> 0 bytes .../retrieveStyleSheetTest.css | 8 - .../simpleImageCacheTest.png | Bin 4313 -> 0 bytes 5 files changed, 1 insertion(+), 253 deletions(-) delete mode 100644 src/test/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolverTest.java delete mode 100644 src/test/resources/com/itextpdf/styledxmlparser/resolver/resources/retrieveStreamTest/resourceResolverTest.png delete mode 100644 src/test/resources/com/itextpdf/styledxmlparser/resolver/resources/retrieveStreamTest/retrieveStyleSheetTest.css delete mode 100644 src/test/resources/com/itextpdf/styledxmlparser/resolver/resources/simpleImageCacheTest/simpleImageCacheTest.png diff --git a/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolverTest.java b/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolverTest.java deleted file mode 100644 index 23d7ecbe78..0000000000 --- a/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolverTest.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - This file is part of the iText (R) project. - Copyright (c) 1998-2017 iText Group NV - Authors: iText Software. - - 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.styledxmlparser.resolver.resource; - -import com.itextpdf.kernel.pdf.xobject.PdfImageXObject; -import com.itextpdf.test.ExtendedITextTest; -import com.itextpdf.test.annotations.type.UnitTest; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.nio.file.Files; -import java.nio.file.Paths; - -@Category(UnitTest.class) -public class ResourceResolverTest extends ExtendedITextTest { - private final String baseUri = "./src/test/resources/com/itextpdf/styledxmlparser/resolver/resources/retrieveStreamTest/"; - @Rule - public ExpectedException junitExpectedException = ExpectedException.none(); - - @Test - public void resourceResolverTest01() throws MalformedURLException { - String absolutePathRoot = Paths.get( "" ).toAbsolutePath().getRoot().toUri().toURL().toExternalForm().replace( '\\', '/' ).replaceFirst( "^/", "" ); - String absoluteBaseUri = absolutePathRoot + "test/folder/index.html"; - ResourceResolver resolver = new ResourceResolver( absoluteBaseUri ); - Assert.assertEquals( absolutePathRoot + "test/folder/innerTest", resolver.resolveAgainstBaseUri( "innerTest" ).toExternalForm() ); - Assert.assertEquals( absolutePathRoot + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri( "../folder2/innerTest2" ).toExternalForm() ); - Assert.assertEquals( absolutePathRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "/folder2/innerTest2" ).toExternalForm() ); - Assert.assertEquals( absolutePathRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "//folder2/innerTest2" ).toExternalForm() ); - } - - @Test - public void resourceResolverTest01A() throws MalformedURLException { - String absolutePathRoot = Paths.get( "" ).toAbsolutePath().toUri().toURL().toExternalForm().replace( '\\', '/' ).replaceFirst( "^/", "" ); - String absoluteBaseUri = absolutePathRoot + "test/folder/index.html"; - ResourceResolver resolver = new ResourceResolver( absoluteBaseUri ); - Assert.assertEquals( absolutePathRoot + "test/folder/innerTest", resolver.resolveAgainstBaseUri( "innerTest" ).toExternalForm() ); - Assert.assertEquals( absolutePathRoot + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri( "../folder2/innerTest2" ).toExternalForm() ); - Assert.assertEquals( absolutePathRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "/folder2/innerTest2" ).toExternalForm() ); - Assert.assertEquals( absolutePathRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "//folder2/innerTest2" ).toExternalForm() ); - } - - @Test - public void resourceResolverTest02() throws MalformedURLException { - ResourceResolver resolver = new ResourceResolver( "test/folder/index.html" ); - String runFolder = Paths.get( "" ).toUri().toURL().toExternalForm(); - Assert.assertEquals( runFolder + "test/folder/innerTest", resolver.resolveAgainstBaseUri( "innerTest" ).toExternalForm() ); - Assert.assertEquals( runFolder + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri( "../folder2/innerTest2" ).toExternalForm() ); - Assert.assertEquals( runFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "/folder2/innerTest2" ).toExternalForm() ); - Assert.assertEquals( runFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "//folder2/innerTest2" ).toExternalForm() ); - } - - @Test - public void resourceResolverTest03() throws MalformedURLException { - ResourceResolver resolver = new ResourceResolver( "/test/folder/index.html" ); - String rootFolder = Paths.get( "" ).toAbsolutePath().getRoot().toUri().toURL().toExternalForm(); - Assert.assertEquals( rootFolder + "test/folder/innerTest", resolver.resolveAgainstBaseUri( "innerTest" ).toExternalForm() ); - Assert.assertEquals( rootFolder + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri( "../folder2/innerTest2" ).toExternalForm() ); - Assert.assertEquals( rootFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "/folder2/innerTest2" ).toExternalForm() ); - Assert.assertEquals( rootFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "//folder2/innerTest2" ).toExternalForm() ); - } - - @Test - public void resourceResolverTest04() throws MalformedURLException { - ResourceResolver resolver = new ResourceResolver( "index.html" ); - String runFolder = Paths.get( "" ).toUri().toURL().toExternalForm(); - Assert.assertEquals( runFolder + "innerTest", resolver.resolveAgainstBaseUri( "innerTest" ).toExternalForm() ); - Assert.assertEquals( runFolder + "folder2/innerTest2", resolver.resolveAgainstBaseUri( "/folder2/innerTest2" ).toExternalForm() ); - Assert.assertEquals( runFolder + "folder2/innerTest2", resolver.resolveAgainstBaseUri( "//folder2/innerTest2" ).toExternalForm() ); - } - - @Test - public void resourceResolverTest05() throws MalformedURLException { - ResourceResolver resolver = new ResourceResolver( "/../test/folder/index.html" ); - String rootFolder = Paths.get( "" ).toAbsolutePath().getRoot().toUri().toURL().toExternalForm(); - Assert.assertEquals( rootFolder + "test/folder/innerTest", resolver.resolveAgainstBaseUri( "innerTest" ).toExternalForm() ); - Assert.assertEquals( rootFolder + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri( "../folder2/innerTest2" ).toExternalForm() ); - Assert.assertEquals( rootFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "/folder2/innerTest2" ).toExternalForm() ); - Assert.assertEquals( rootFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "//folder2/innerTest2" ).toExternalForm() ); - } - - @Test - public void resourceResolverTest06() throws MalformedURLException { - ResourceResolver resolver = new ResourceResolver( "../test/folder/index.html" ); - String parentFolder = Paths.get( "" ).toAbsolutePath().getParent().toUri().toURL().toExternalForm(); - Assert.assertEquals( parentFolder + "test/folder/innerTest", resolver.resolveAgainstBaseUri( "innerTest" ).toExternalForm() ); - Assert.assertEquals( parentFolder + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri( "../folder2/innerTest2" ).toExternalForm() ); - Assert.assertEquals( parentFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "/folder2/innerTest2" ).toExternalForm() ); - Assert.assertEquals( parentFolder + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "//folder2/innerTest2" ).toExternalForm() ); - } - - @Test - public void resourceResolverTest07() throws MalformedURLException { - ResourceResolver resolver = new ResourceResolver( "http://itextpdf.com/itext7" ); - Assert.assertEquals( "http://itextpdf.com/innerTest", resolver.resolveAgainstBaseUri( "innerTest" ).toExternalForm() ); - Assert.assertEquals( "http://itextpdf.com/folder2/innerTest2", resolver.resolveAgainstBaseUri( "/folder2/innerTest2" ).toExternalForm() ); - Assert.assertEquals( "http://folder2.com/innerTest2", resolver.resolveAgainstBaseUri( "//folder2.com/innerTest2" ).toExternalForm() ); - } - - @Test - public void resourceResolverTest08() throws MalformedURLException { - ResourceResolver resolver = new ResourceResolver( "http://itextpdf.com/itext7/" ); - Assert.assertEquals( "http://itextpdf.com/itext7/innerTest", resolver.resolveAgainstBaseUri( "innerTest" ).toExternalForm() ); - Assert.assertEquals( "http://itextpdf.com/folder2/innerTest2", resolver.resolveAgainstBaseUri( "/folder2/innerTest2" ).toExternalForm() ); - Assert.assertEquals( "http://folder2.com/innerTest2", resolver.resolveAgainstBaseUri( "//folder2.com/innerTest2" ).toExternalForm() ); - } - - @Test - public void resourceResolverTest09() throws MalformedURLException { - String absolutePathRoot = Paths.get( "" ).toAbsolutePath().getRoot().toString().replace( '\\', '/' ); - String absoluteBaseUri = absolutePathRoot + "test/folder/index.html"; - ResourceResolver resolver = new ResourceResolver( absoluteBaseUri ); - String uriRoot = Paths.get( "" ).toAbsolutePath().getRoot().toUri().toURL().toExternalForm(); - Assert.assertEquals( uriRoot + "test/folder/innerTest", resolver.resolveAgainstBaseUri( "innerTest" ).toExternalForm() ); - Assert.assertEquals( uriRoot + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri( "../folder2/innerTest2" ).toExternalForm() ); - Assert.assertEquals( uriRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "/folder2/innerTest2" ).toExternalForm() ); - Assert.assertEquals( uriRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "//folder2/innerTest2" ).toExternalForm() ); - } - - @Test - public void resourceResolverTest13() throws MalformedURLException { - ResourceResolver resolver = new ResourceResolver( "" ); - String runFolder = Paths.get( "" ).toUri().toURL().toExternalForm(); - Assert.assertEquals( runFolder + "innerTest", resolver.resolveAgainstBaseUri( "innerTest" ).toExternalForm() ); - String parentToRunFolder = Paths.get( "" ).toAbsolutePath().getParent().toUri().toURL().toExternalForm(); - Assert.assertEquals( parentToRunFolder + "folder2/innerTest2", resolver.resolveAgainstBaseUri( "../folder2/innerTest2" ).toExternalForm() ); - Assert.assertEquals( runFolder + "folder2/innerTest2", resolver.resolveAgainstBaseUri( "/folder2/innerTest2" ).toExternalForm() ); - Assert.assertEquals( runFolder + "folder2/innerTest2", resolver.resolveAgainstBaseUri( "//folder2/innerTest2" ).toExternalForm() ); - } - - @Test - public void resourceResolverTest14() throws MalformedURLException { - ResourceResolver resolver = new ResourceResolver( "base/uri/index.html" ); - String runFolder = Paths.get( "" ).toUri().toURL().toExternalForm(); - Assert.assertEquals( "file:/c:/test/folder/img.txt", resolver.resolveAgainstBaseUri( "file:/c:/test/folder/img.txt" ).toExternalForm() ); - Assert.assertEquals( "file://c:/test/folder/img.txt", resolver.resolveAgainstBaseUri( "file://c:/test/folder/img.txt" ).toExternalForm() ); - Assert.assertEquals( "file:/c:/test/folder/data.jpg", resolver.resolveAgainstBaseUri( "file:///c:/test/folder/data.jpg" ).toExternalForm() ); - } - - @Test - public void resourceResolverTest15() throws MalformedURLException { - String absolutePathRoot = "file:/" + Paths.get( "" ).toAbsolutePath().getRoot().toString().replace( '\\', '/' ).replaceFirst( "^/", "" ); - String absoluteBaseUri = absolutePathRoot + "test/folder/index.html"; - ResourceResolver resolver = new ResourceResolver( absoluteBaseUri ); - Assert.assertEquals( absolutePathRoot + "test/folder/innerTest", resolver.resolveAgainstBaseUri( "innerTest" ).toExternalForm() ); - Assert.assertEquals( absolutePathRoot + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri( "../folder2/innerTest2" ).toExternalForm() ); - Assert.assertEquals( absolutePathRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "/folder2/innerTest2" ).toExternalForm() ); - Assert.assertEquals( absolutePathRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "//folder2/innerTest2" ).toExternalForm() ); - } - - @Test - public void resourceResolverTest16() throws MalformedURLException { - String absolutePathRoot = "file:///" + Paths.get( "" ).toAbsolutePath().getRoot().toString().replace( '\\', '/' ).replaceFirst( "^/", "" ); - String absoluteBaseUri = absolutePathRoot + "test/folder/index.html"; - ResourceResolver resolver = new ResourceResolver( absoluteBaseUri ); - String singleSlashRootPath = absolutePathRoot.replace( "///", "/" ); - Assert.assertEquals( singleSlashRootPath + "test/folder/innerTest", resolver.resolveAgainstBaseUri( "innerTest" ).toExternalForm() ); - Assert.assertEquals( singleSlashRootPath + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri( "../folder2/innerTest2" ).toExternalForm() ); - Assert.assertEquals( singleSlashRootPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "/folder2/innerTest2" ).toExternalForm() ); - Assert.assertEquals( singleSlashRootPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri( "//folder2/innerTest2" ).toExternalForm() ); - } - - @Test - public void retrieveStreamTest() throws IOException { - String fileName = "resourceResolverTest.png"; - byte[] expected = Files.readAllBytes( new File( baseUri+fileName ).toPath()); - ResourceResolver resourceResolver = new ResourceResolver( baseUri ); - byte[] stream = resourceResolver.retrieveStream( "resourceResolverTest.png" ); - Assert.assertNotNull( stream ); - Assert.assertEquals( expected.length, stream.length ); - } - - @Test - public void retrieveStyleSheetTest() throws IOException { - String fileName = "retrieveStyleSheetTest.css"; - - InputStream expected = new FileInputStream(baseUri+fileName); - ResourceResolver resourceResolver = new ResourceResolver( baseUri ); - InputStream stream = resourceResolver.retrieveStyleSheet( "retrieveStyleSheetTest.css" ); - Assert.assertNotNull( stream ); - Assert.assertEquals( expected.read(), stream.read() ); - } - - @Test - public void retrieveImageTest() throws IOException { - String fileName = "resourceResolverTest.png"; - ResourceResolver resourceResolver = new ResourceResolver( baseUri ); - PdfImageXObject image = resourceResolver.retrieveImage( fileName ); - Assert.assertNotNull( image ); - Assert.assertTrue( image.identifyImageFileExtension().equalsIgnoreCase( "png" ) ); - } - - -} diff --git a/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolverTest.java b/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolverTest.java index 9f0240b733..da4cf8d442 100644 --- a/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolverTest.java +++ b/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolverTest.java @@ -185,7 +185,6 @@ public void uriResolverTest13() throws MalformedURLException { public void uriResolverTest14() throws MalformedURLException { UriResolver resolver = new UriResolver("base/uri/index.html"); String runFolder = Paths.get("").toUri().toURL().toExternalForm(); - Assert.assertTrue( resolver.isLocalBaseUri() ); Assert.assertEquals(runFolder + "base/uri/index.html", resolver.getBaseUri()); Assert.assertEquals("file:/c:/test/folder/img.txt", resolver.resolveAgainstBaseUri("file:/c:/test/folder/img.txt").toExternalForm()); Assert.assertEquals("file://c:/test/folder/img.txt", resolver.resolveAgainstBaseUri("file://c:/test/folder/img.txt").toExternalForm()); @@ -223,10 +222,8 @@ public void uriResolverTest16() throws MalformedURLException { @Test public void uriResolverTest17() throws MalformedURLException { - String absolutePathRoot = "http://"; + String absolutePathRoot = "file:///" + Paths.get("").toAbsolutePath().getRoot().toString().replace('\\', '/').replaceFirst("^/", ""); String absoluteBaseUri = absolutePathRoot + "test/fol ders/wi@th/diffe#rent/$characters/index.html\t\t\t\t\t\t"; UriResolver resolver = new UriResolver(absoluteBaseUri); - Assert.assertFalse( resolver.isLocalBaseUri() ); } - } diff --git a/src/test/resources/com/itextpdf/styledxmlparser/resolver/resources/retrieveStreamTest/resourceResolverTest.png b/src/test/resources/com/itextpdf/styledxmlparser/resolver/resources/retrieveStreamTest/resourceResolverTest.png deleted file mode 100644 index 7dbc85a25b3a8ca794111be24d7c059326aa87fc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4313 zcmeAS@N?(olHy`uVBq!ia0y~yU}<1rVCvvt0*bVIibVk_#^NA%Cx&(BWL^R}Ea{HE zjtmSN`?>!lvI6;>1s;*b3=BdgAk26#O}>JGK_Ji5#WAEJ?(JRsBH?g`1BqVKH8qP{ zrc9XvAzx}(GO4-9 z-2=LH0M0uDRQmMtUxwR!s%#7lcQ)*<mD!qJ5a|vBR8s?-ducjc>d!^ z_os*BUwh42XCq^GbocYeug&?7Uj|0WOpXofcRohvoO?B@6K|Fg#N}kay2@bGrIt%juhHie9zP zxgHy=c94PL0SCv1OOevmJf@|Zmw#E+@a0-@0t4*Kk?S94>d3$Edhvm+`uFX3v9E2- z#2$Zi&biM4k=&_sjdg49qV;Asj*G9p&R_OCe%n5_+uwm1!1!ZnjoWhRH%)I1ubuz& zYtPg_2I~Uio8R7^?tfgFfx*GM;cRxshW7cJU(Erk*q)#J`t_4nKTUissuh_S4#=?F zxU=kb@|=wVg&S`>7FK-xc(mdNS6k8TxD#<5z+h)*EMr*~t^Cfn;O#dXo1e>m-Lep^ z7E@wkaPV!AZGL$+VX}I&uef|%xc=Lu_g?)9z#Oozk-=K1`+V${zw$Hn>}m|;cC*FD z0lm@jL#)o^+pdi7C)U4?sIl0(_d+9oA<*yZIvK2`c3*AtSKD59_rTex+uV_@K;^oO zWhT@5%P($~eeGTsyZvPu&^Zn#!aqDN{I&DU;T^Y_r}J;j-0*bq$MryQrv}-nNAqeQ zoV^N+AOm5>vJ^9J!R!29Vet$MANC3+0F$U7BhW5^QRZkkj3$E7%rIIKjFyO_)xl`B tINBx{Z5xd?3`bkVG;I}6h*!lvI6;>1s;*b3=BdgAk26#O}>JGK_Ji5#WAEJ?(JRsBH?g`1BqVKH8qP{ zrc9XvAzx}(GO4-9 z-2=LH0M0uDRQmMtUxwR!s%#7lcQ)*<mD!qJ5a|vBR8s?-ducjc>d!^ z_os*BUwh42XCq^GbocYeug&?7Uj|0WOpXofcRohvoO?B@6K|Fg#N}kay2@bGrIt%juhHie9zP zxgHy=c94PL0SCv1OOevmJf@|Zmw#E+@a0-@0t4*Kk?S94>d3$Edhvm+`uFX3v9E2- z#2$Zi&biM4k=&_sjdg49qV;Asj*G9p&R_OCe%n5_+uwm1!1!ZnjoWhRH%)I1ubuz& zYtPg_2I~Uio8R7^?tfgFfx*GM;cRxshW7cJU(Erk*q)#J`t_4nKTUissuh_S4#=?F zxU=kb@|=wVg&S`>7FK-xc(mdNS6k8TxD#<5z+h)*EMr*~t^Cfn;O#dXo1e>m-Lep^ z7E@wkaPV!AZGL$+VX}I&uef|%xc=Lu_g?)9z#Oozk-=K1`+V${zw$Hn>}m|;cC*FD z0lm@jL#)o^+pdi7C)U4?sIl0(_d+9oA<*yZIvK2`c3*AtSKD59_rTex+uV_@K;^oO zWhT@5%P($~eeGTsyZvPu&^Zn#!aqDN{I&DU;T^Y_r}J;j-0*bq$MryQrv}-nNAqeQ zoV^N+AOm5>vJ^9J!R!29Vet$MANC3+0F$U7BhW5^QRZkkj3$E7%rIIKjFyO_)xl`B tINBx{Z5xd?3`bkVG;I}6h* Date: Fri, 4 May 2018 14:45:48 +0200 Subject: [PATCH 07/23] Support SVG processing in pdfHTML RND-918 --- .../com/itextpdf/styledxmlparser/AttributeConstants.java | 9 +++++++++ .../com/itextpdf/styledxmlparser/LogMessageConstant.java | 2 ++ .../styledxmlparser/node/impl/jsoup/JsoupXmlParser.java | 3 ++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/itextpdf/styledxmlparser/AttributeConstants.java b/src/main/java/com/itextpdf/styledxmlparser/AttributeConstants.java index b174a00fb6..b3d9b68e61 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/AttributeConstants.java +++ b/src/main/java/com/itextpdf/styledxmlparser/AttributeConstants.java @@ -91,6 +91,9 @@ private AttributeConstants() { /** The Constant CONTENT. */ public static final String CONTENT = "content"; + /** The Constant DATA */ + public static final String DATA = "data"; + /** The Constant DESCRIPTION. */ public static final String DESCRIPTION = "description"; @@ -240,9 +243,15 @@ private AttributeConstants() { /**The Constant start*/ public static final String START = "start"; + public static final String PLACEHOLDER = "placeholder"; + // iText custom attributes /** The Constant PARENT_TABLE_BORDER. */ public static final String PARENT_TABLE_BORDER = "parenttableborder"; + public final class ObjectTypes{ + public static final String SVGIMAGE = "image/svg+xml"; + } + } diff --git a/src/main/java/com/itextpdf/styledxmlparser/LogMessageConstant.java b/src/main/java/com/itextpdf/styledxmlparser/LogMessageConstant.java index 75f699d616..7630400bc6 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/LogMessageConstant.java +++ b/src/main/java/com/itextpdf/styledxmlparser/LogMessageConstant.java @@ -47,6 +47,8 @@ This file is part of the iText (R) project. */ public final class LogMessageConstant { + /** The Constant ERROR_PARSING_COULD_NOT_MAP_NODE */ + public static final String ERROR_PARSING_COULD_NOT_MAP_NODE = "Could not map node type: {0}"; /** The Constant ERROR_PARSING_CSS_SELECTOR. */ public static final String ERROR_PARSING_CSS_SELECTOR = "Error while parsing css selector: {0}"; /** The Constant UNKNOWN_ABSOLUTE_METRIC_LENGTH_PARSED. */ diff --git a/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/JsoupXmlParser.java b/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/JsoupXmlParser.java index 1e5d4b0a59..9b428b5ede 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/JsoupXmlParser.java +++ b/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/JsoupXmlParser.java @@ -44,6 +44,7 @@ This file is part of the iText (R) project. import com.itextpdf.io.util.MessageFormatUtil; import com.itextpdf.styledxmlparser.IHtmlParser; +import com.itextpdf.styledxmlparser.LogMessageConstant; import com.itextpdf.styledxmlparser.jsoup.Jsoup; import com.itextpdf.styledxmlparser.jsoup.nodes.Comment; import com.itextpdf.styledxmlparser.jsoup.nodes.DataNode; @@ -124,7 +125,7 @@ private INode wrapJsoupHierarchy(Node jsoupNode) { resultNode = new JsoupDocumentTypeNode((DocumentType) jsoupNode); } else if (jsoupNode instanceof Comment) { } else { - logger.error(MessageFormatUtil.format("Could not map node type: {0}", jsoupNode.getClass())); + logger.error(MessageFormatUtil.format(LogMessageConstant.ERROR_PARSING_COULD_NOT_MAP_NODE, jsoupNode.getClass())); } for (Node node : jsoupNode.childNodes()) { From fb20bd130208ea8af667b02537ca16ecee823a22 Mon Sep 17 00:00:00 2001 From: Alexey Subach Date: Tue, 29 May 2018 17:46:12 +0300 Subject: [PATCH 08/23] Make pdftest a test dependency rather than a compile one DEVSIX-1987 --- pom.xml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 2ff8717b79..82ba8d69c1 100644 --- a/pom.xml +++ b/pom.xml @@ -28,19 +28,20 @@ com.itextpdf - pdftest + kernel ${project.version} - - com.itextpdf - kernel - ${project.version} - com.itextpdf layout ${project.version} + + com.itextpdf + pdftest + ${project.version} + test + From 7763b91c7d3d287f0ed4fe0734f1b2ab1a8bbb88 Mon Sep 17 00:00:00 2001 From: Ilya Idamkin Date: Wed, 30 May 2018 18:31:30 +0300 Subject: [PATCH 09/23] Refactor time-based system utils to better represent there purpose --- .../itextpdf/styledxmlparser/jsoup/parser/HtmlParserTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/itextpdf/styledxmlparser/jsoup/parser/HtmlParserTest.java b/src/test/java/com/itextpdf/styledxmlparser/jsoup/parser/HtmlParserTest.java index 1f4f6abdd5..86361d9892 100644 --- a/src/test/java/com/itextpdf/styledxmlparser/jsoup/parser/HtmlParserTest.java +++ b/src/test/java/com/itextpdf/styledxmlparser/jsoup/parser/HtmlParserTest.java @@ -896,12 +896,12 @@ public class HtmlParserTest { } // Act - long start = SystemUtil.getSystemTimeMillis(); + long start = SystemUtil.getRelativeTimeMillis(); Document doc = Parser.parseBodyFragment(longBody.toString(), ""); // Assert assertEquals(50000, doc.body().childNodeSize()); - assertTrue(SystemUtil.getSystemTimeMillis() - start < 1000); + assertTrue(SystemUtil.getRelativeTimeMillis() - start < 1000); } @Test From 5b040d9dbe084d727d840ab6aaee2b75fa6e26a8 Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 4 May 2018 13:50:41 +0200 Subject: [PATCH 10/23] RND-883 font resolution initial commit RND-883 extract media expressions/rules from pdfhtml and add them to styledxmlparser RND-883 add fontface rule to the Css rule factory RND-883 improve test results RND_883 remove spaces surrounding method arguments RND-883 fix a broken depedency to itext.io --- .../styledxmlparser/LogMessageConstant.java | 2 +- .../styledxmlparser/css/CssFontFaceRule.java | 102 +++++++ .../css/CssNestedAtRuleFactory.java | 2 +- .../css/media/CssMediaRule.java | 103 +++++++ .../css/media/MediaExpression.java | 214 +++++++++++++++ .../css/media/MediaFeature.java | 146 ++++++++++ .../styledxmlparser/css/media/MediaQuery.java | 113 ++++++++ .../css/media/MediaQueryParser.java | 167 +++++++++++ .../css/media/MediaRuleConstants.java | 71 +++++ .../shorthand/ShorthandResolverFactory.java | 2 + .../shorthand/impl/FontShorthandResolver.java | 170 ++++++++++++ .../css/media/CssMediaRuleTest.java | 33 +++ .../css/media/MediaExpressionTest.java | 143 ++++++++++ .../css/media/MediaQueryTest.java | 22 ++ .../shorthand/CssShorthandResolverTest.java | 259 ++++++++++++++++++ 15 files changed, 1547 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/CssFontFaceRule.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/media/CssMediaRule.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/media/MediaExpression.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/media/MediaFeature.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/media/MediaQuery.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/media/MediaQueryParser.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/media/MediaRuleConstants.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/FontShorthandResolver.java create mode 100644 src/test/java/com/itextpdf/styledxmlparser/css/media/CssMediaRuleTest.java create mode 100644 src/test/java/com/itextpdf/styledxmlparser/css/media/MediaExpressionTest.java create mode 100644 src/test/java/com/itextpdf/styledxmlparser/css/media/MediaQueryTest.java create mode 100644 src/test/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/CssShorthandResolverTest.java diff --git a/src/main/java/com/itextpdf/styledxmlparser/LogMessageConstant.java b/src/main/java/com/itextpdf/styledxmlparser/LogMessageConstant.java index 7630400bc6..3d7ad946dc 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/LogMessageConstant.java +++ b/src/main/java/com/itextpdf/styledxmlparser/LogMessageConstant.java @@ -67,7 +67,7 @@ public final class LogMessageConstant { /** The Constant UNABLE_TO_RETRIEVE_STREAM_WITH_GIVEN_BASE_URI. */ public static final String UNABLE_TO_RETRIEVE_STREAM_WITH_GIVEN_BASE_URI = "Unable to retrieve stream with given base URI ({0}) and source path ({1})"; public static final String UNABLE_TO_PROCESS_EXTERNAL_CSS_FILE = "Unable to process external css file" ; - + public static final String UNABLE_TO_RETRIEVE_FONT = "Unable to retrieve font:\n {0}"; /** * Instantiates a new log message constant. diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/CssFontFaceRule.java b/src/main/java/com/itextpdf/styledxmlparser/css/CssFontFaceRule.java new file mode 100644 index 0000000000..9189c13660 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/CssFontFaceRule.java @@ -0,0 +1,102 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css; + +import com.itextpdf.io.util.MessageFormatUtil; + +import java.util.List; + +/** + * Class to store a CSS font face At rule. + */ +public class CssFontFaceRule extends CssNestedAtRule { + + /** + * Properties in the form of a list of CSS declarations. + */ + private List properties; + + /** + * Instantiates a new CSS font face rule. + * + * @param ruleParameters the rule parameters + */ + public CssFontFaceRule(String ruleParameters) { + super(CssRuleName.FONT_FACE, ruleParameters); + } + + /** + * Gets the properties. + * + * @return the properties + */ + public List getProperties() { + return properties; + } + + /* (non-Javadoc) + * @see com.itextpdf.html2pdf.css.CssNestedAtRule#addBodyCssDeclarations(java.util.List) + */ + @Override + public void addBodyCssDeclarations(List cssDeclarations) { + properties = cssDeclarations; + } + + /* (non-Javadoc) + * @see com.itextpdf.html2pdf.css.CssNestedAtRule#toString() + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(MessageFormatUtil.format("@{0} ", ruleName)); + sb.append("{"); + sb.append("\n"); + for (CssDeclaration declaration : properties) { + sb.append(" "); + sb.append(declaration); + sb.append("\n"); + } + sb.append("}"); + return sb.toString(); + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/CssNestedAtRuleFactory.java b/src/main/java/com/itextpdf/styledxmlparser/css/CssNestedAtRuleFactory.java index d772da9111..7779b36766 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/CssNestedAtRuleFactory.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/CssNestedAtRuleFactory.java @@ -88,7 +88,7 @@ public static CssNestedAtRule createNestedRule(String ruleDeclaration) { case CssRuleName.BOTTOM_RIGHT_CORNER: //return new CssMarginRule(ruleName, ruleParameters); case CssRuleName.FONT_FACE: - //return new CssFontFaceRule(ruleParameters); + return new CssFontFaceRule(ruleParameters); default: return new CssNestedAtRule(ruleName, ruleParameters); } diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/media/CssMediaRule.java b/src/main/java/com/itextpdf/styledxmlparser/css/media/CssMediaRule.java new file mode 100644 index 0000000000..ac5fbfd09e --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/media/CssMediaRule.java @@ -0,0 +1,103 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.media; + +import com.itextpdf.styledxmlparser.css.CssNestedAtRule; +import com.itextpdf.styledxmlparser.css.CssRuleName; +import com.itextpdf.styledxmlparser.css.CssRuleSet; +import com.itextpdf.styledxmlparser.css.CssStatement; +import com.itextpdf.styledxmlparser.node.INode; + +import java.util.ArrayList; +import java.util.List; + +/** + * The {@link CssNestedAtRule} implementation for media rules. + */ +public class CssMediaRule extends CssNestedAtRule { + + /** The media queries. */ + private List mediaQueries; + + /** + * Creates a {@link CssMediaRule}. + * + * @param ruleParameters the rule parameters + */ + public CssMediaRule(String ruleParameters) { + super(CssRuleName.MEDIA, ruleParameters); + mediaQueries = MediaQueryParser.parseMediaQueries(ruleParameters); + } + + /* (non-Javadoc) + * @see com.itextpdf.html2pdf.css.CssNestedAtRule#getCssRuleSets(com.itextpdf.html2pdf.html.node.INode, com.itextpdf.html2pdf.css.media.MediaDeviceDescription) + */ + @Override + public List getCssRuleSets(INode element, MediaDeviceDescription deviceDescription) { + List result = new ArrayList<>(); + for (MediaQuery mediaQuery : mediaQueries) { + if (mediaQuery.matches(deviceDescription)) { + for (CssStatement childStatement : body) { + result.addAll(childStatement.getCssRuleSets(element, deviceDescription)); + } + break; + } + } + return result; + } + + /** + * Tries to match a media device. + * + * @param deviceDescription the device description + * @return true, if successful + */ + public boolean matchMediaDevice(MediaDeviceDescription deviceDescription) { + for (MediaQuery mediaQuery : mediaQueries) { + if (mediaQuery.matches(deviceDescription)) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/media/MediaExpression.java b/src/main/java/com/itextpdf/styledxmlparser/css/media/MediaExpression.java new file mode 100644 index 0000000000..cecfbb664d --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/media/MediaExpression.java @@ -0,0 +1,214 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.media; + +import com.itextpdf.styledxmlparser.css.util.CssUtils; +import java.util.Objects; + +/** + * Class that bundles all the media expression properties. + */ +public class MediaExpression { + + /** + * The default font size. + */ + private static final float DEFAULT_FONT_SIZE = 12; + + /** + * Indicates if there's a "min-" prefix. + */ + private boolean minPrefix; + + /** + * Indicates if there's a "max-" prefix. + */ + private boolean maxPrefix; + + /** + * The feature. + */ + private String feature; + + /** + * The value. + */ + private String value; + + /** + * Creates a new {@link MediaExpression} instance. + * + * @param feature the feature + * @param value the value + */ + MediaExpression(String feature, String value) { + this.feature = feature.trim().toLowerCase(); + if (value != null) { + this.value = value.trim().toLowerCase(); + } + + String minPref = MediaRuleConstants.MIN + "-"; + String maxPref = MediaRuleConstants.MAX + "-"; + minPrefix = feature.startsWith(minPref); + if (minPrefix) { + this.feature = feature.substring(minPref.length()); + } + maxPrefix = feature.startsWith(maxPref); + if (maxPrefix) { + this.feature = feature.substring(maxPref.length()); + } + } + + /** + * Tries to match a {@link MediaDeviceDescription}. + * + * @param deviceDescription the device description + * @return true, if successful + */ + public boolean matches(MediaDeviceDescription deviceDescription) { + switch (feature) { + case MediaFeature.COLOR: { + Integer val = CssUtils.parseInteger(value); + if (minPrefix) { + return val != null && deviceDescription.getBitsPerComponent() >= val; + } else if (maxPrefix) { + return val != null && deviceDescription.getBitsPerComponent() <= val; + } else { + return val == null ? deviceDescription.getBitsPerComponent() != 0 : val == deviceDescription.getBitsPerComponent(); + } + } + case MediaFeature.COLOR_INDEX: { + Integer val = CssUtils.parseInteger(value); + if (minPrefix) { + return val != null && deviceDescription.getColorIndex() >= val; + } else if (maxPrefix) { + return val != null && deviceDescription.getColorIndex() <= val; + } else { + return val == null ? deviceDescription.getColorIndex() != 0 : val == deviceDescription.getColorIndex(); + } + } + case MediaFeature.ASPECT_RATIO: { + int[] aspectRatio = CssUtils.parseAspectRatio(value); + if (minPrefix) { + return aspectRatio != null && aspectRatio[0] * deviceDescription.getHeight() >= aspectRatio[1] * deviceDescription.getWidth(); + } else if (maxPrefix) { + return aspectRatio != null && aspectRatio[0] * deviceDescription.getHeight() <= aspectRatio[1] * deviceDescription.getWidth(); + } else { + return aspectRatio != null && equals(aspectRatio[0] * deviceDescription.getHeight(), aspectRatio[1] * deviceDescription.getWidth(), 0.000001); + } + } + case MediaFeature.GRID: { + Integer val = CssUtils.parseInteger(value); + return val != null && val == 0 && !deviceDescription.isGrid() || deviceDescription.isGrid(); + } + case MediaFeature.SCAN: { + return Objects.equals(value, deviceDescription.getScan()); + } + case MediaFeature.ORIENTATION: { + return Objects.equals(value, deviceDescription.getOrientation()); + } + case MediaFeature.MONOCHROME: { + Integer val = CssUtils.parseInteger(value); + if (minPrefix) { + return val != null && deviceDescription.getMonochrome() >= val; + } else if (maxPrefix) { + return val != null && deviceDescription.getMonochrome() <= val; + } else { + return val == null ? deviceDescription.getMonochrome() > 0 : val == deviceDescription.getMonochrome(); + } + } + case MediaFeature.HEIGHT: { + float val = parseAbsoluteLength(value); + if (minPrefix) { + return deviceDescription.getHeight() >= val; + } else if (maxPrefix) { + return deviceDescription.getHeight() <= val; + } else { + return deviceDescription.getHeight() > 0; + } + } + case MediaFeature.WIDTH: { + float val = parseAbsoluteLength(value); + if (minPrefix) { + return deviceDescription.getWidth() >= val; + } else if (maxPrefix) { + return deviceDescription.getWidth() <= val; + } else { + return deviceDescription.getWidth() > 0; + } + } + case MediaFeature.RESOLUTION: { + float val = CssUtils.parseResolution(value); + if (minPrefix) { + return deviceDescription.getResolution() >= val; + } else if (maxPrefix) { + return deviceDescription.getResolution() <= val; + } else { + return deviceDescription.getResolution() > 0; + } + } + default: + return false; + } + } + + /** + * Parses an absolute length. + * + * @param value the absolute length as a {@link String} value + * @return the absolute length as a {@code float} value + */ + private static float parseAbsoluteLength(String value) { + if (CssUtils.isRelativeValue(value)) { + // TODO here should be used default font size of the browser, it probably should be fetched from the more generic place than private class constant + return CssUtils.parseRelativeValue(value, DEFAULT_FONT_SIZE); + } else { + return CssUtils.parseAbsoluteLength(value); + } + } + + private static boolean equals(double a, double b, double epsilon) { + return a == b ? true : Math.abs(a - b) < epsilon; + } + +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/media/MediaFeature.java b/src/main/java/com/itextpdf/styledxmlparser/css/media/MediaFeature.java new file mode 100644 index 0000000000..379043f966 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/media/MediaFeature.java @@ -0,0 +1,146 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.media; + +/** + * Class that bundles all the media feature values. + */ +public final class MediaFeature { + + /** + * Creates a new {@link MediaFeature} instance. + */ + private MediaFeature() { + } + + /** + * Value: <integer>
+ * Media: visual
+ * Accepts min/max prefixes: yes
+ * Indicates the number of bits per color component of the output device. If the device is not a color device, this value is zero. + */ + public static final String COLOR = "color"; + + /** + * Value: <integer>
+ * Media: visual
+ * Accepts min/max prefixes: yes
+ * Indicates the number of entries in the color look-up table for the output device. + */ + public static final String COLOR_INDEX = "color-index"; + + /** + * Value: <ratio>
+ * Media: visual, tactile
+ * Accepts min/max prefixes: yes
+ * Describes the aspect ratio of the targeted display area of the output device. + * This value consists of two positive integers separated by a slash ("/") character. + * This represents the ratio of horizontal pixels (first term) to vertical pixels (second term). + */ + public static final String ASPECT_RATIO = "aspect-ratio"; + + /** + * Value: <mq-boolean> which is an <integer> that can only have the 0 and 1 value.
+ * Media: all
+ * Accepts min/max prefixes: no
+ * Determines whether the output device is a grid device or a bitmap device. + * If the device is grid-based (such as a TTY terminal or a phone display with only one font), + * the value is 1. Otherwise it is zero. + */ + public static final String GRID = "grid"; + + /** + * Value: progressive | interlace
+ * Media: tv
+ * Accepts min/max prefixes: no
+ * Describes the scanning process of television output devices. + */ + public static final String SCAN = "scan"; + + /** + * Value: landscape | portrait
+ * Media: visual
+ * Accepts min/max prefixes: no
+ * Indicates whether the viewport is in landscape (the display is wider than it is tall) or + * portrait (the display is taller than it is wide) mode. + */ + public static final String ORIENTATION = "orientation"; + + /** + * Value: <integer>
+ * Media: visual
+ * Accepts min/max prefixes: yes
+ * Indicates the number of bits per pixel on a monochrome (greyscale) device. + * If the device isn't monochrome, the device's value is 0. + */ + public static final String MONOCHROME = "monochrome"; + + /** + * Value: <length>
+ * Media: visual, tactile
+ * Accepts min/max prefixes: yes
+ * The height media feature describes the height of the output device's rendering surface + * (such as the height of the viewport or of the page box on a printer). + */ + public static final String HEIGHT = "height"; + + /** + * Value: <resolution>
+ * Media: bitmap
+ * Accepts min/max prefixes: yes
+ * Indicates the resolution (pixel density) of the output device. The resolution may be specified in + * either dots per inch (dpi) or dots per centimeter (dpcm). + */ + public static final String RESOLUTION = "resolution"; + + /** + * Value: <length>
+ * Media: visual, tactile
+ * Accepts min/max prefixes: yes
+ * The width media feature describes the width of the rendering surface of the output device + * (such as the width of the document window, or the width of the page box on a printer). + */ + public static final String WIDTH = "width"; + + +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/media/MediaQuery.java b/src/main/java/com/itextpdf/styledxmlparser/css/media/MediaQuery.java new file mode 100644 index 0000000000..dd858102e6 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/media/MediaQuery.java @@ -0,0 +1,113 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.media; + +import java.util.List; +import java.util.Objects; + +/** + * Class that bundles all the media query properties. + */ +public class MediaQuery { + + /** + * The logical "only" value. + */ + private boolean only; + + /** + * The logical "not" value. + */ + private boolean not; + + /** + * The type. + */ + private String type; + + /** + * The expressions. + */ + private List expressions; + + /** + * Creates a new {@link MediaQuery} instance. + * + * @param type the type + * @param expressions the expressions + * @param only logical "only" value + * @param not logical "not" value + */ + MediaQuery(String type, List expressions, boolean only, boolean not) { + this.type = type; + this.expressions = expressions; + this.only = only; + this.not = not; + } + + /** + * Tries to match a device description with the media query. + * + * @param deviceDescription the device description + * @return true, if successful + */ + public boolean matches(MediaDeviceDescription deviceDescription) { + boolean typeMatches = type == null || MediaType.ALL.equals(type) || Objects.equals(type, deviceDescription.getType()); + + boolean matchesExpressions = true; + for (MediaExpression expression : expressions) { + if (!expression.matches(deviceDescription)) { + matchesExpressions = false; + break; + } + } + + boolean expressionResult = typeMatches && matchesExpressions; + if (not) { + expressionResult = !expressionResult; + } + + return expressionResult; + } + +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/media/MediaQueryParser.java b/src/main/java/com/itextpdf/styledxmlparser/css/media/MediaQueryParser.java new file mode 100644 index 0000000000..b85318e66b --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/media/MediaQueryParser.java @@ -0,0 +1,167 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.media; + +import java.util.ArrayList; +import java.util.List; + +/** + * Utilities class that parses {@link String} values into {@link MediaQuery} or {@link MediaExpression} values. + */ +public final class MediaQueryParser { + + /** + * Creates a {@link MediaQueryParser} instance. + */ + private MediaQueryParser() { + } + + /** + * Parses a {@link String} into a {@link List} of {@link MediaQuery} values. + * + * @param mediaQueriesStr the media queries in the form of a {@link String} + * @return the resulting {@link List} of {@link MediaQuery} values + */ + static List parseMediaQueries(String mediaQueriesStr) { + String[] mediaQueryStrs = mediaQueriesStr.split(","); + List mediaQueries = new ArrayList<>(); + for (String mediaQueryStr : mediaQueryStrs) { + MediaQuery mediaQuery = parseMediaQuery(mediaQueryStr); + if (mediaQuery != null) { + mediaQueries.add(mediaQuery); + } + } + return mediaQueries; + } + + /** + * Parses a {@link String} into a {@link MediaQuery} value. + * + * @param mediaQueryStr the media query in the form of a {@link String} + * @return the resulting {@link MediaQuery} value + */ + static MediaQuery parseMediaQuery(String mediaQueryStr) { + mediaQueryStr = mediaQueryStr.trim().toLowerCase(); + boolean only = false; + boolean not = false; + if (mediaQueryStr.startsWith(MediaRuleConstants.ONLY)) { + only = true; + mediaQueryStr = mediaQueryStr.substring(MediaRuleConstants.ONLY.length()).trim(); + } else if (mediaQueryStr.startsWith(MediaRuleConstants.NOT)) { + not = true; + mediaQueryStr = mediaQueryStr.substring(MediaRuleConstants.NOT.length()).trim(); + } + + int indexOfSpace = mediaQueryStr.indexOf(' '); + String firstWord = indexOfSpace != -1 ? mediaQueryStr.substring(0, indexOfSpace) : mediaQueryStr; + + String mediaType = null; + List mediaExpressions = null; + + if (only || not || MediaType.isValidMediaType(firstWord)) { + mediaType = firstWord; + mediaExpressions = parseMediaExpressions(mediaQueryStr.substring(firstWord.length()), true); + } else { + mediaExpressions = parseMediaExpressions(mediaQueryStr, false); + } + + return new MediaQuery(mediaType, mediaExpressions, only, not); + } + + /** + * Parses a {@link String} into a list of {@link MediaExpression} values. + * + * @param mediaExpressionsStr the media expressions in the form of a {@link String} + * @param shallStartWithAnd indicates if the media expression shall start with "and" + * @return the resulting list of {@link MediaExpression} values + */ + private static List parseMediaExpressions(String mediaExpressionsStr, boolean shallStartWithAnd) { + mediaExpressionsStr = mediaExpressionsStr.trim(); + boolean startsWithEnd = mediaExpressionsStr.startsWith(MediaRuleConstants.AND); + + boolean firstExpression = true; + String[] mediaExpressionStrs = mediaExpressionsStr.split(MediaRuleConstants.AND); + List expressions = new ArrayList<>(); + for (String mediaExpressionStr : mediaExpressionStrs) { + MediaExpression expression = parseMediaExpression(mediaExpressionStr); + if (expression != null) { + if (firstExpression) { + if (shallStartWithAnd && !startsWithEnd) { + throw new IllegalStateException("Expected 'and' while parsing media expression"); + } + } + firstExpression = false; + expressions.add(expression); + } + } + return expressions; + } + + /** + * Parses a {@link String} into a {@link MediaExpression} value. + * + * @param mediaExpressionStr the media expression in the form of a {@link String} + * @return the resulting {@link MediaExpression} value + */ + private static MediaExpression parseMediaExpression(String mediaExpressionStr) { + mediaExpressionStr = mediaExpressionStr.trim(); + if (!mediaExpressionStr.startsWith("(") || !mediaExpressionStr.endsWith(")")) { + return null; + } + mediaExpressionStr = mediaExpressionStr.substring(1, mediaExpressionStr.length() - 1); + if (mediaExpressionStr.length() == 0) { + return null; + } + int colonPos = mediaExpressionStr.indexOf(':'); + String mediaFeature; + String value = null; + if (colonPos == -1) { + mediaFeature = mediaExpressionStr; + } else { + mediaFeature = mediaExpressionStr.substring(0, colonPos).trim(); + value = mediaExpressionStr.substring(colonPos + 1).trim(); + } + return new MediaExpression(mediaFeature, value); + } + +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/media/MediaRuleConstants.java b/src/main/java/com/itextpdf/styledxmlparser/css/media/MediaRuleConstants.java new file mode 100644 index 0000000000..e742336872 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/media/MediaRuleConstants.java @@ -0,0 +1,71 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.media; + +/** + * Class that bundles a series of media rule constants. + */ +public final class MediaRuleConstants { + + /** + * Creates a new {@link MediaRuleConstants} instance. + */ + private MediaRuleConstants() { + } + + /** The Constant AND. */ + public static final String AND = "and"; + + /** The Constant MIN. */ + public static final String MIN = "min"; + + /** The Constant MAX. */ + public static final String MAX = "max"; + + /** The Constant NOT. */ + public static final String NOT = "not"; + + /** The Constant ONLY. */ + public static final String ONLY = "only"; + +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/ShorthandResolverFactory.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/ShorthandResolverFactory.java index 09f734f5f4..245e57dad2 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/ShorthandResolverFactory.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/ShorthandResolverFactory.java @@ -46,6 +46,7 @@ This file is part of the iText (R) project. import com.itextpdf.styledxmlparser.css.CssConstants; import com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.BorderShorthandResolver; +import com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.FontShorthandResolver; import java.util.HashMap; import java.util.Map; @@ -60,6 +61,7 @@ public class ShorthandResolverFactory { static { shorthandResolvers = new HashMap<>(); shorthandResolvers.put(CssConstants.BORDER, new BorderShorthandResolver()); + shorthandResolvers.put( CssConstants.FONT,new FontShorthandResolver() ); // TODO text-decoration is a shorthand in CSS3, however it is not yet supported in any major browsers } diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/FontShorthandResolver.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/FontShorthandResolver.java new file mode 100644 index 0000000000..28fc6e8e2b --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/FontShorthandResolver.java @@ -0,0 +1,170 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.resolve.shorthand.impl; + +import com.itextpdf.styledxmlparser.css.CssConstants; +import com.itextpdf.styledxmlparser.css.CssDeclaration; +import com.itextpdf.styledxmlparser.css.resolve.shorthand.IShorthandResolver; +import com.itextpdf.styledxmlparser.css.util.CssUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.itextpdf.io.util.MessageFormatUtil; +import java.util.*; + +/** + * {@link IShorthandResolver} implementation for fonts. + */ +public class FontShorthandResolver implements IShorthandResolver { + + /** Unsupported shorthand values. */ + private static final Set UNSUPPORTED_VALUES_OF_FONT_SHORTHAND = new HashSet<>(Arrays.asList( + CssConstants.CAPTION, CssConstants.ICON, CssConstants.MENU, CssConstants.MESSAGE_BOX, + CssConstants.SMALL_CAPTION, CssConstants.STATUS_BAR + )); + + /** Font weight values. */ + private static final Set FONT_WEIGHT_NOT_DEFAULT_VALUES = new HashSet<>(Arrays.asList( + CssConstants.BOLD, CssConstants.BOLDER, CssConstants.LIGHTER, + "100", "200", "300", "400", "500", "600", "700", "800", "900" + )); + + /** Font size values. */ + private static final Set FONT_SIZE_VALUES = new HashSet<>(Arrays.asList( + CssConstants.MEDIUM, CssConstants.XX_SMALL, CssConstants.X_SMALL, CssConstants.SMALL, CssConstants.LARGE, + CssConstants.X_LARGE, CssConstants.XX_LARGE, CssConstants.SMALLER, CssConstants.LARGER + )); + + /* (non-Javadoc) + * @see com.itextpdf.html2pdf.css.resolve.shorthand.IShorthandResolver#resolveShorthand(java.lang.String) + */ + @Override + public List resolveShorthand(String shorthandExpression) { + if (UNSUPPORTED_VALUES_OF_FONT_SHORTHAND.contains(shorthandExpression)) { + Logger logger = LoggerFactory.getLogger(FontShorthandResolver.class); + logger.error(MessageFormatUtil.format("The \"{0}\" value of CSS shorthand property \"font\" is not supported", shorthandExpression)); + } + if (CssConstants.INITIAL.equals(shorthandExpression) || CssConstants.INHERIT.equals(shorthandExpression)) { + return Arrays.asList( + new CssDeclaration(CssConstants.FONT_STYLE, shorthandExpression), + new CssDeclaration(CssConstants.FONT_VARIANT, shorthandExpression), + new CssDeclaration(CssConstants.FONT_WEIGHT, shorthandExpression), + new CssDeclaration(CssConstants.FONT_SIZE, shorthandExpression), + new CssDeclaration(CssConstants.LINE_HEIGHT, shorthandExpression), + new CssDeclaration(CssConstants.FONT_FAMILY, shorthandExpression) + ); + } + + String fontStyleValue = null; + String fontVariantValue = null; + String fontWeightValue = null; + String fontSizeValue = null; + String lineHeightValue = null; + String fontFamilyValue = null; + + List properties = getFontProperties(shorthandExpression.replaceAll("\\s*,\\s*", ",")); + for (String value : properties) { + int slashSymbolIndex = value.indexOf('/'); + if (CssConstants.ITALIC.equals(value) || CssConstants.OBLIQUE.equals(value)) { + fontStyleValue = value; + } else if (CssConstants.SMALL_CAPS.equals(value)) { + fontVariantValue = value; + } else if (FONT_WEIGHT_NOT_DEFAULT_VALUES.contains(value)) { + fontWeightValue = value; + } else if (slashSymbolIndex > 0) { + fontSizeValue = value.substring(0, slashSymbolIndex); + lineHeightValue = value.substring(slashSymbolIndex + 1, value.length()); + } else if (FONT_SIZE_VALUES.contains(value) || CssUtils.isMetricValue(value) + || CssUtils.isNumericValue(value) || CssUtils.isRelativeValue(value)) { + fontSizeValue = value; + } else { + fontFamilyValue = value; + } + } + + List cssDeclarations = Arrays.asList( + new CssDeclaration(CssConstants.FONT_STYLE, fontStyleValue == null ? CssConstants.INITIAL : fontStyleValue), + new CssDeclaration(CssConstants.FONT_VARIANT, fontVariantValue == null ? CssConstants.INITIAL : fontVariantValue), + new CssDeclaration(CssConstants.FONT_WEIGHT, fontWeightValue == null ? CssConstants.INITIAL : fontWeightValue), + new CssDeclaration(CssConstants.FONT_SIZE, fontSizeValue == null ? CssConstants.INITIAL : fontSizeValue), + new CssDeclaration(CssConstants.LINE_HEIGHT, lineHeightValue == null ? CssConstants.INITIAL : lineHeightValue), + new CssDeclaration(CssConstants.FONT_FAMILY, fontFamilyValue == null ? CssConstants.INITIAL : fontFamilyValue) + ); + + return cssDeclarations; + } + + /** + * Gets the font properties. + * + * @param shorthandExpression the shorthand expression + * @return the font properties + */ + private List getFontProperties(String shorthandExpression) { + boolean doubleQuotesAreSpotted = false; + boolean singleQuoteIsSpotted = false; + List properties = new ArrayList<>(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < shorthandExpression.length(); i++) { + char currentChar = shorthandExpression.charAt(i); + if (currentChar == '\"') { + doubleQuotesAreSpotted = !doubleQuotesAreSpotted; + sb.append(currentChar); + } else if (currentChar == '\'' ) { + singleQuoteIsSpotted = !singleQuoteIsSpotted; + sb.append(currentChar); + } else if (!doubleQuotesAreSpotted && !singleQuoteIsSpotted && Character.isWhitespace(currentChar)) { + if (sb.length() > 0) { + properties.add(sb.toString()); + sb = new StringBuilder(); + } + } else { + sb.append(currentChar); + } + } + if (sb.length() > 0) { + properties.add(sb.toString()); + } + return properties; + } +} diff --git a/src/test/java/com/itextpdf/styledxmlparser/css/media/CssMediaRuleTest.java b/src/test/java/com/itextpdf/styledxmlparser/css/media/CssMediaRuleTest.java new file mode 100644 index 0000000000..0784678cde --- /dev/null +++ b/src/test/java/com/itextpdf/styledxmlparser/css/media/CssMediaRuleTest.java @@ -0,0 +1,33 @@ +package com.itextpdf.styledxmlparser.css.media; + +import com.itextpdf.styledxmlparser.css.CssRuleSet; +import com.itextpdf.styledxmlparser.node.IDocumentNode; +import com.itextpdf.styledxmlparser.node.impl.jsoup.JsoupHtmlParser; +import com.itextpdf.test.ExtendedITextTest; +import com.itextpdf.test.annotations.type.UnitTest; +import java.util.List; +import org.junit.Assert; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +@Category(UnitTest.class) + +public class CssMediaRuleTest extends ExtendedITextTest { + @Test + public void matchMediaDeviceTest() { + MediaDeviceDescription deviceDescription = new MediaDeviceDescription("all"); + deviceDescription.setHeight(450); + deviceDescription.setWidth(600); + CssMediaRule rule = new CssMediaRule("@media all and (min-width: 600px) and (min-height: 600px)"); + Assert.assertTrue(rule.matchMediaDevice(deviceDescription)); + } + + @Test + public void getCssRuleSetsTest() { + MediaDeviceDescription deviceDescription = new MediaDeviceDescription("all"); + String html = ""; + IDocumentNode node = new JsoupHtmlParser().parse(html); + List ruleSets = new CssMediaRule("only all and (min-width: 600px) and (min-height: 600px)").getCssRuleSets(node, deviceDescription); + Assert.assertNotNull(ruleSets); + } +} diff --git a/src/test/java/com/itextpdf/styledxmlparser/css/media/MediaExpressionTest.java b/src/test/java/com/itextpdf/styledxmlparser/css/media/MediaExpressionTest.java new file mode 100644 index 0000000000..aaff7c5404 --- /dev/null +++ b/src/test/java/com/itextpdf/styledxmlparser/css/media/MediaExpressionTest.java @@ -0,0 +1,143 @@ +package com.itextpdf.styledxmlparser.css.media; + +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 MediaExpressionTest extends ExtendedITextTest { + @Test + public void mediaExpressionTestTest01() { + MediaExpression minWidth = new MediaExpression("min-width", "600px"); + MediaExpression minHeight = new MediaExpression("min-height", "600px"); + + MediaDeviceDescription deviceDescription = new MediaDeviceDescription("all"); + deviceDescription.setWidth(600); + deviceDescription.setHeight(600); + + Assert.assertTrue(minHeight.matches(deviceDescription)); + Assert.assertTrue(minWidth.matches(deviceDescription)); + } + + @Test + public void mediaExpressionTestTest02() { + MediaExpression maxWidth = new MediaExpression("max-width", "600px"); + MediaExpression maxHeight = new MediaExpression("max-height", "600px"); + + MediaDeviceDescription deviceDescription = new MediaDeviceDescription("all"); + deviceDescription.setWidth(450); + deviceDescription.setHeight(450); + + Assert.assertTrue(maxHeight.matches(deviceDescription)); + Assert.assertTrue(maxWidth.matches(deviceDescription)); + } + + @Test + public void mediaExpressionTestTest03() { + MediaExpression orientation = new MediaExpression("orientation", "landscape"); + MediaExpression resolution = new MediaExpression("resolution", "150dpi"); + MediaExpression grid = new MediaExpression("grid", "0"); + MediaExpression colorIndex = new MediaExpression("max-color-index", "15000"); + MediaExpression monochrome = new MediaExpression("monochrome", "0"); + MediaExpression scan = new MediaExpression("scan", "interlace"); + MediaExpression color = new MediaExpression("color", "15000"); + MediaExpression minAspectRatio = new MediaExpression("max-aspect-ratio", "8/5"); + + MediaDeviceDescription deviceDescription = new MediaDeviceDescription("all"); + deviceDescription.setOrientation("landscape"); + deviceDescription.setResolution(150); + deviceDescription.setGrid(false); + deviceDescription.setColorIndex(15000); + deviceDescription.setMonochrome(0); + deviceDescription.setScan("interlace"); + deviceDescription.setBitsPerComponent(15000); + deviceDescription.setWidth(32); + deviceDescription.setHeight(20); + + Assert.assertTrue(resolution.matches(deviceDescription)); + Assert.assertTrue(orientation.matches(deviceDescription)); + Assert.assertTrue(grid.matches(deviceDescription)); + Assert.assertTrue(colorIndex.matches(deviceDescription)); + Assert.assertTrue(monochrome.matches(deviceDescription)); + Assert.assertTrue(scan.matches(deviceDescription)); + Assert.assertTrue(color.matches(deviceDescription)); + Assert.assertTrue(minAspectRatio.matches(deviceDescription)); + } + + @Test + public void mediaExpressionTestTest04() { + MediaExpression minColorIndex = new MediaExpression("min-color-index", "15000"); + MediaExpression minResolution = new MediaExpression("min-resolution", "150dpi"); + MediaExpression minColor = new MediaExpression("min-color", "8"); + MediaExpression minAspectRatio = new MediaExpression("min-aspect-ratio", "8/5"); + + MediaDeviceDescription deviceDescription = new MediaDeviceDescription("all"); + deviceDescription.setColorIndex(15000); + deviceDescription.setBitsPerComponent(8); + deviceDescription.setResolution(150); + deviceDescription.setWidth(32); + deviceDescription.setHeight(20); + + Assert.assertTrue(minAspectRatio.matches(deviceDescription)); + Assert.assertTrue(minColorIndex.matches(deviceDescription)); + Assert.assertTrue(minColor.matches(deviceDescription)); + Assert.assertTrue(minResolution.matches(deviceDescription)); + } + + @Test + public void mediaExpressionTestTest05() { + MediaExpression maxColorIndex = new MediaExpression("max-color-index", null); + MediaExpression maxColor = new MediaExpression("max-color", null); + MediaExpression maxWidth = new MediaExpression("width", "600ex"); + MediaExpression maxHeight = new MediaExpression("height", "600ex"); + MediaExpression maxMonochrome = new MediaExpression("max-monochrome", "0"); + MediaExpression maxResolution = new MediaExpression("max-resolution", "150dpi"); + + MediaDeviceDescription deviceDescription = new MediaDeviceDescription("all"); + deviceDescription.setHeight(450); + deviceDescription.setWidth(450); + deviceDescription.setColorIndex(15000); + deviceDescription.setBitsPerComponent(8); + deviceDescription.setMonochrome(0); + deviceDescription.setResolution(150); + + Assert.assertTrue(maxMonochrome.matches(deviceDescription)); + Assert.assertTrue(maxHeight.matches(deviceDescription)); + Assert.assertTrue(maxWidth.matches(deviceDescription)); + Assert.assertFalse(maxColorIndex.matches(deviceDescription)); + Assert.assertFalse(maxColor.matches(deviceDescription)); + Assert.assertTrue(maxResolution.matches(deviceDescription)); + } + + @Test + public void mediaExpressionTestTest06() { + + MediaExpression minColorIndex = new MediaExpression("min-color-index", null); + MediaExpression minColor = new MediaExpression("min-color", null); + MediaExpression colorIndex = new MediaExpression("color-index", "1500"); + MediaExpression minMonochrome = new MediaExpression("min-monochrome", "0"); + MediaExpression resolution = new MediaExpression("resolution", "150dpi"); + MediaExpression defaultExpression = new MediaExpression("none", "none"); + MediaExpression aspectRatio = new MediaExpression("aspect-ratio", "8/8"); + + MediaDeviceDescription deviceDescription = new MediaDeviceDescription("all"); + deviceDescription.setColorIndex(15000); + deviceDescription.setBitsPerComponent(8); + deviceDescription.setMonochrome(0); + deviceDescription.setWidth(1.99999999f); + deviceDescription.setHeight(2.00000000f); + deviceDescription.setColorIndex(15000); + + Assert.assertTrue(aspectRatio.matches(deviceDescription)); + Assert.assertTrue(minMonochrome.matches(deviceDescription)); + Assert.assertFalse(minColorIndex.matches(deviceDescription)); + Assert.assertFalse(minColor.matches(deviceDescription)); + Assert.assertFalse(resolution.matches(deviceDescription)); + Assert.assertFalse(defaultExpression.matches(deviceDescription)); + Assert.assertFalse(colorIndex.matches(deviceDescription)); + } +} + + diff --git a/src/test/java/com/itextpdf/styledxmlparser/css/media/MediaQueryTest.java b/src/test/java/com/itextpdf/styledxmlparser/css/media/MediaQueryTest.java new file mode 100644 index 0000000000..67af1eb857 --- /dev/null +++ b/src/test/java/com/itextpdf/styledxmlparser/css/media/MediaQueryTest.java @@ -0,0 +1,22 @@ +package com.itextpdf.styledxmlparser.css.media; + +import com.itextpdf.test.ExtendedITextTest; +import com.itextpdf.test.annotations.type.UnitTest; +import java.util.List; +import org.junit.Assert; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +@Category(UnitTest.class) + +public class MediaQueryTest extends ExtendedITextTest { + @Test + public void matchTest() { + MediaDeviceDescription deviceDescription = new MediaDeviceDescription("all"); + MediaQuery query = MediaQueryParser.parseMediaQuery("not all and (min-width: 600px)"); + List queries = MediaQueryParser.parseMediaQueries("not all and (min-width: 600px), not all and (min-width: 500px)"); + Assert.assertTrue(query.matches(deviceDescription)); + Assert.assertTrue(queries.get(0).matches(deviceDescription)); + Assert.assertTrue(queries.get(1).matches(deviceDescription)); + } +} diff --git a/src/test/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/CssShorthandResolverTest.java b/src/test/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/CssShorthandResolverTest.java new file mode 100644 index 0000000000..eecdb78249 --- /dev/null +++ b/src/test/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/CssShorthandResolverTest.java @@ -0,0 +1,259 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 iText Group NV + Authors: iText Software. + + 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.styledxmlparser.css.resolve.shorthand; + +import com.itextpdf.styledxmlparser.css.CssConstants; +import com.itextpdf.styledxmlparser.css.CssDeclaration; +import com.itextpdf.test.ExtendedITextTest; +import com.itextpdf.test.annotations.type.UnitTest; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.util.Set; +import java.util.HashSet; +import java.util.Arrays; +import java.util.List; +import java.util.TreeSet; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +@Category(UnitTest.class) +public class CssShorthandResolverTest extends ExtendedITextTest { + + + @Test + public void fontTest01() { + String shorthandExpression = "italic normal bold 12px/30px Georgia, serif"; + Set expectedResolvedProperties = new HashSet<>( Arrays.asList( + "font-style: italic", + "font-variant: initial", + "font-weight: bold", + "font-size: 12px", + "line-height: 30px", + "font-family: georgia,serif" + ) ); + + IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CssConstants.FONT ); + assertNotNull( resolver ); + List resolvedShorthandProps = resolver.resolveShorthand( shorthandExpression ); + compareResolvedProps( resolvedShorthandProps, expectedResolvedProperties ); + } + + @Test + public void fontTest02() { + String shorthandExpression = "bold Georgia, serif"; + Set expectedResolvedProperties = new HashSet<>( Arrays.asList( + "font-style: initial", + "font-variant: initial", + "font-weight: bold", + "font-size: initial", + "line-height: initial", + "font-family: georgia,serif" + ) ); + + IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CssConstants.FONT ); + assertNotNull( resolver ); + List resolvedShorthandProps = resolver.resolveShorthand( shorthandExpression ); + compareResolvedProps( resolvedShorthandProps, expectedResolvedProperties ); + } + + @Test + public void fontTest03() { + String shorthandExpression = "inherit"; + Set expectedResolvedProperties = new HashSet<>( Arrays.asList( + "font-style: inherit", + "font-variant: inherit", + "font-weight: inherit", + "font-size: inherit", + "line-height: inherit", + "font-family: inherit" + ) ); + + IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CssConstants.FONT ); + assertNotNull( resolver ); + List resolvedShorthandProps = resolver.resolveShorthand( shorthandExpression ); + compareResolvedProps( resolvedShorthandProps, expectedResolvedProperties ); + } + + @Test + public void fontTest04() { + String shorthandExpression = "bold Georgia, serif, \"Times New Roman\""; + Set expectedResolvedProperties = new HashSet<>( Arrays.asList( + "font-style: initial", + "font-variant: initial", + "font-weight: bold", + "font-size: initial", + "line-height: initial", + "font-family: georgia,serif,\"Times New Roman\"" + ) ); + + IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CssConstants.FONT ); + assertNotNull( resolver ); + List resolvedShorthandProps = resolver.resolveShorthand( shorthandExpression ); + compareResolvedProps( resolvedShorthandProps, expectedResolvedProperties ); + } + + @Test + public void fontTest05() { + String shorthandExpression = "italic normal bold 12px/30px Georgia, \"Times New Roman\", serif"; + Set expectedResolvedProperties = new HashSet<>( Arrays.asList( + "font-style: italic", + "font-variant: initial", + "font-weight: bold", + "font-size: 12px", + "line-height: 30px", + "font-family: georgia,\"Times New Roman\",serif" + ) ); + + IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CssConstants.FONT ); + assertNotNull( resolver ); + List resolvedShorthandProps = resolver.resolveShorthand( shorthandExpression ); + compareResolvedProps( resolvedShorthandProps, expectedResolvedProperties ); + } + + @Test + public void fontTest06() { + String shorthandExpression = "italic normal bold 12px/30px Georgia , \"Times New Roman\" , serif"; + Set expectedResolvedProperties = new HashSet<>( Arrays.asList( + "font-style: italic", + "font-variant: initial", + "font-weight: bold", + "font-size: 12px", + "line-height: 30px", + "font-family: georgia,\"Times New Roman\",serif" + ) ); + + IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CssConstants.FONT ); + assertNotNull( resolver ); + List resolvedShorthandProps = resolver.resolveShorthand( shorthandExpression ); + compareResolvedProps( resolvedShorthandProps, expectedResolvedProperties ); + } + + @Test + public void fontTest07() { + String shorthandExpression = "italic normal bold 12px/30px Georgia , \"Times New Roman\" "; + Set expectedResolvedProperties = new HashSet<>( Arrays.asList( + "font-style: italic", + "font-variant: initial", + "font-weight: bold", + "font-size: 12px", + "line-height: 30px", + "font-family: georgia,\"Times New Roman\"" + ) ); + + IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CssConstants.FONT ); + assertNotNull( resolver ); + List resolvedShorthandProps = resolver.resolveShorthand( shorthandExpression ); + compareResolvedProps( resolvedShorthandProps, expectedResolvedProperties ); + } + + @Test + public void fontTest08() { + String shorthandExpression = "Georgia,'Times New Roman'"; + Set expectedResolvedProperties = new HashSet<>( Arrays.asList( + "font-style: initial", + "font-variant: initial", + "font-weight: initial", + "font-size: initial", + "line-height: initial", + "font-family: georgia,'Times New Roman'" + ) ); + + IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CssConstants.FONT ); + assertNotNull( resolver ); + List resolvedShorthandProps = resolver.resolveShorthand( shorthandExpression ); + compareResolvedProps( resolvedShorthandProps, expectedResolvedProperties ); + } + + @Test + public void fontTest09() { + String shorthandExpression = "Georgia , 'Times New Roman', serif"; + Set expectedResolvedProperties = new HashSet<>( Arrays.asList( + "font-style: initial", + "font-variant: initial", + "font-weight: initial", + "font-size: initial", + "line-height: initial", + "font-family: georgia,'Times New Roman',serif" + ) ); + + IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CssConstants.FONT ); + assertNotNull( resolver ); + List resolvedShorthandProps = resolver.resolveShorthand( shorthandExpression ); + compareResolvedProps( resolvedShorthandProps, expectedResolvedProperties ); + } + + private void compareResolvedProps(List actual, Set expected) { + Set actualSet = new HashSet<>(); + for (CssDeclaration cssDecl : actual) { + actualSet.add( cssDecl.toString() ); + } + + boolean areDifferent = false; + + StringBuilder sb = new StringBuilder( "Resolved styles are different from expected!" ); + Set expCopy = new TreeSet<>( expected ); + Set actCopy = new TreeSet<>( actualSet ); + expCopy.removeAll( actualSet ); + actCopy.removeAll( expected ); + if (!expCopy.isEmpty()) { + areDifferent = true; + sb.append( "\nExpected but not found properties:\n" ); + for (String expProp : expCopy) { + sb.append( expProp ).append( '\n' ); + } + } + if (!actCopy.isEmpty()) { + areDifferent = true; + sb.append( "\nNot expected but found properties:\n" ); + for (String actProp : actCopy) { + sb.append( actProp ).append( '\n' ); + } + } + + if (areDifferent) { + fail( sb.toString() ); + } + } +} From 815b59d96edb962a0421d8ebaded74dde73ecc23 Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 9 May 2018 10:37:51 +0200 Subject: [PATCH 11/23] RND-864 add extra tests to improve coverage results RND-864 add UriResolverTest RND-864 make test runnable on linux RND-864 remove additional spaces inside method parameters RND-864 remove additional spaces inside method parameters RND-864 remove Remove UriResolverTest and test UriResolver calling getBaseUri inside ResourceResolverTest RND-864 change ResourceResolverTest category to UnitTest RND-864 Create separated test classes for UriResolver and ResourceResovler respectively RND-864 add documentation and extra tests RND-864 remove broken code from HtmlParserTest RND-864 fix method comments RND-864 add 07x and 12.x tests to UriResolverTest RND-864 fixe deprecated method in HtmlParserTest --- .../resolver/resource/UriResolver.java | 4 + .../resource/ResourceResolverTest.java | 113 ++++++++++ .../resolver/resource/UriResolverTest.java | 196 ++++++++++++++++-- .../resourceResolverTest.png | Bin 0 -> 4313 bytes .../retrieveStyleSheetTest.css | 8 + .../simpleImageCacheTest.png | Bin 0 -> 4313 bytes 6 files changed, 302 insertions(+), 19 deletions(-) create mode 100644 src/test/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolverTest.java create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/resolver/retrieveStreamTest/resourceResolverTest.png create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/resolver/retrieveStreamTest/retrieveStyleSheetTest.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/resolver/simpleImageCacheTest/simpleImageCacheTest.png diff --git a/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolver.java b/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolver.java index d60ddf8451..4a6fb29764 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolver.java +++ b/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolver.java @@ -135,6 +135,10 @@ public boolean isLocalBaseUri() { * @param base the base URI */ private void resolveBaseUrlOrPath(String base) { + //TODO RND-1019 + // this method produces + // a behavior that is not consistant in java vs .Net + //when resolving some characters ex. scaped backwards lash base = base.trim(); baseUrl = baseUriAsUrl(UriEncodeUtil.encode(base)); if (baseUrl == null) { diff --git a/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolverTest.java b/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolverTest.java new file mode 100644 index 0000000000..8e7f3a52e4 --- /dev/null +++ b/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolverTest.java @@ -0,0 +1,113 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 iText Group NV + Authors: iText Software. + + 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.styledxmlparser.resolver.resource; + +import com.itextpdf.kernel.pdf.xobject.PdfImageXObject; +import com.itextpdf.styledxmlparser.LogMessageConstant; +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.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.ExpectedException; + +@Category(UnitTest.class) +public class ResourceResolverTest extends ExtendedITextTest { + private final String baseUri = "./src/test/resources/com/itextpdf/styledxmlparser/resolver/retrieveStreamTest/"; + @Rule + public ExpectedException junitExpectedException = ExpectedException.none(); + + @Test + @LogMessages(messages = @LogMessage(messageTemplate = LogMessageConstant.UNABLE_TO_RETRIEVE_STREAM_WITH_GIVEN_BASE_URI, count = 1)) + public void malformedResourceNameTest() { + String fileName = "resourceResolverTest .png"; + ResourceResolver resourceResolver = new ResourceResolver(baseUri); + resourceResolver.retrieveStream(fileName); + } + + @Test + public void malformedResourceNameTest01() throws IOException { + junitExpectedException.expect(IOException.class); + String fileName = "retrieveStyl eSheetTest.css"; + ResourceResolver resourceResolver = new ResourceResolver(baseUri); + resourceResolver.retrieveStyleSheet(fileName); + } + + @Test + public void retrieveStreamTest() throws IOException { + String fileName = "resourceResolverTest.png"; + byte[] expected = Files.readAllBytes(new File(baseUri + fileName).toPath()); + ResourceResolver resourceResolver = new ResourceResolver(baseUri); + byte[] stream = resourceResolver.retrieveStream(fileName); + Assert.assertNotNull(resourceResolver.retrieveStream(fileName)); + Assert.assertEquals(expected.length, stream.length); + } + + @Test + public void retrieveStyleSheetTest() throws IOException { + String fileName = "retrieveStyleSheetTest.css"; + InputStream expected = new FileInputStream(baseUri + fileName); + ResourceResolver resourceResolver = new ResourceResolver(baseUri); + InputStream stream = resourceResolver.retrieveStyleSheet(fileName); + Assert.assertNotNull(stream); + Assert.assertEquals(expected.read(), stream.read()); + } + + + @Test + public void retrieveImageTest() { + String fileName = "resourceResolverTest.png"; + ResourceResolver resourceResolver = new ResourceResolver(baseUri); + PdfImageXObject image = resourceResolver.retrieveImage(fileName); + Assert.assertNotNull(image); + Assert.assertTrue(image.identifyImageFileExtension().equalsIgnoreCase("png")); + } +} diff --git a/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolverTest.java b/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolverTest.java index da4cf8d442..0be29b86cf 100644 --- a/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolverTest.java +++ b/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolverTest.java @@ -44,15 +44,14 @@ This file is part of the iText (R) project. import com.itextpdf.test.ExtendedITextTest; import com.itextpdf.test.annotations.type.UnitTest; +import java.net.MalformedURLException; +import java.nio.file.Paths; import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.rules.ExpectedException; -import java.net.MalformedURLException; -import java.nio.file.Paths; - @Category(UnitTest.class) public class UriResolverTest extends ExtendedITextTest { @@ -61,7 +60,7 @@ public class UriResolverTest extends ExtendedITextTest { @Test public void uriResolverTest01() throws MalformedURLException { - String absolutePathRoot = Paths.get("").toAbsolutePath().getRoot().toUri().toURL().toExternalForm().replace('\\', '/').replaceFirst("^/", ""); + String absolutePathRoot = Paths.get("").toAbsolutePath().getRoot().toUri().toURL().toExternalForm(); String absoluteBaseUri = absolutePathRoot + "test/folder/index.html"; UriResolver resolver = new UriResolver(absoluteBaseUri); Assert.assertEquals(absolutePathRoot + "test/folder/index.html", resolver.getBaseUri()); @@ -73,7 +72,7 @@ public void uriResolverTest01() throws MalformedURLException { @Test public void uriResolverTest01A() throws MalformedURLException { - String absolutePathRoot = Paths.get("").toAbsolutePath().toUri().toURL().toExternalForm().replace('\\', '/').replaceFirst("^/", ""); + String absolutePathRoot = Paths.get("").toAbsolutePath().toUri().toURL().toExternalForm(); String absoluteBaseUri = absolutePathRoot + "test/folder/index.html"; UriResolver resolver = new UriResolver(absoluteBaseUri); Assert.assertEquals(absolutePathRoot + "test/folder/index.html", resolver.getBaseUri()); @@ -145,6 +144,28 @@ public void uriResolverTest07() throws MalformedURLException { Assert.assertEquals("http://itextpdf.com/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); Assert.assertEquals("http://folder2.com/innerTest2", resolver.resolveAgainstBaseUri("//folder2.com/innerTest2").toExternalForm()); } + @Test + public void uriResolverTest07A() throws MalformedURLException { + String absolutePathRoot = Paths.get("").toAbsolutePath().getRoot().toUri().toURL().toString(); + UriResolver resolver = new UriResolver(absolutePathRoot + "%23r%e%2525s@o%25urces/test/folder/index.html"); + String malformedPath = absolutePathRoot + "%23r%25e%2525s@o%25urces/"; + Assert.assertEquals(malformedPath + "test/folder/index.html", resolver.getBaseUri()); + Assert.assertEquals(malformedPath + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); + } + + @Test + public void uriResolverTest07B() throws MalformedURLException { + String absolutePathRoot = Paths.get("").toAbsolutePath().getRoot().toUri().toURL().toString(); + UriResolver resolver = new UriResolver(absolutePathRoot + "#r%e%25s@o%urces/folder/index.html"); + String malformedPath = absolutePathRoot; + Assert.assertEquals(malformedPath + "#r%25e%25s@o%25urces/folder/index.html", resolver.getBaseUri()); + Assert.assertEquals(malformedPath + "test/folder/innerTest", resolver.resolveAgainstBaseUri("test/folder/innerTest").toExternalForm()); + Assert.assertEquals(malformedPath + "folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertEquals(malformedPath + "folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder/folder2/innerTest2").toExternalForm()); + } @Test public void uriResolverTest08() throws MalformedURLException { @@ -157,10 +178,8 @@ public void uriResolverTest08() throws MalformedURLException { @Test public void uriResolverTest09() throws MalformedURLException { - String absolutePathRoot = Paths.get("").toAbsolutePath().getRoot().toString().replace('\\', '/'); - String absoluteBaseUri = absolutePathRoot + "test/folder/index.html"; - UriResolver resolver = new UriResolver(absoluteBaseUri); - + String absolutePathRoot = Paths.get("").toAbsolutePath().getRoot().toUri().toString(); + UriResolver resolver = new UriResolver(absolutePathRoot + "test/folder/index.html"); String uriRoot = Paths.get("").toAbsolutePath().getRoot().toUri().toURL().toExternalForm(); Assert.assertEquals(uriRoot + "test/folder/index.html", resolver.getBaseUri()); Assert.assertEquals(uriRoot + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); @@ -169,6 +188,78 @@ public void uriResolverTest09() throws MalformedURLException { Assert.assertEquals(uriRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); } + @Test + public void uriResolverTest10A() throws MalformedURLException { + String absolutePathRoot = Paths.get("").toAbsolutePath().getRoot().toUri().toURL().toString(); + UriResolver resolver = new UriResolver(absolutePathRoot + "path%with%spaces/test/folder/index.html"); + String malformedPath = absolutePathRoot + "path%25with%25spaces/"; + Assert.assertEquals(malformedPath + "test/folder/index.html", resolver.getBaseUri()); + Assert.assertEquals(malformedPath + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); + } + + @Test + public void uriResolverTest10B() throws MalformedURLException { + String absolutePathRoot = Paths.get("").toAbsolutePath().getRoot().toUri().toURL().toString(); + UriResolver resolver = new UriResolver(absolutePathRoot + "path%25with%25spaces/test/folder/index.html"); + String malformedPath = absolutePathRoot + "path%25with%25spaces/"; + Assert.assertEquals(malformedPath + "test/folder/index.html", resolver.getBaseUri()); + Assert.assertEquals(malformedPath + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); + } + + @Test + public void uriResolverTest10C() throws MalformedURLException { + String absolutePathRoot = Paths.get("").toAbsolutePath().getRoot().toUri().toURL().toString(); + UriResolver resolver = new UriResolver(absolutePathRoot + "path%2525with%2525spaces/test/folder/index.html"); + String malformedPath = absolutePathRoot + "path%2525with%2525spaces/"; + Assert.assertEquals(malformedPath + "test/folder/index.html", resolver.getBaseUri()); + Assert.assertEquals(malformedPath + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); + } + + @Test + public void uriResolverTest10D() throws MalformedURLException { + String absolutePathRoot = Paths.get("").toAbsolutePath().getRoot().toUri().toURL().toString(); + UriResolver resolver = new UriResolver(absolutePathRoot + "path with spaces/test/folder/index.html"); + String malformedPath = absolutePathRoot + "path%20with%20spaces/"; + Assert.assertEquals(malformedPath + "test/folder/index.html", resolver.getBaseUri()); + Assert.assertEquals(malformedPath + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); + } + + @Test + public void uriResolverTest10E() throws MalformedURLException { + String absolutePathRoot = Paths.get("").toAbsolutePath().getRoot().toUri().toURL().toString(); + UriResolver resolver = new UriResolver(absolutePathRoot + "path%20with%20spaces/test/folder/index.html"); + String malformedPath = absolutePathRoot + "path%20with%20spaces/"; + Assert.assertEquals(malformedPath + "test/folder/index.html", resolver.getBaseUri()); + Assert.assertEquals(malformedPath + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); + } + + @Test + public void uriResolverTest10F() throws MalformedURLException { + String absolutePathRoot = Paths.get("").toAbsolutePath().getRoot().toUri().toURL().toString(); + UriResolver resolver = new UriResolver(absolutePathRoot + "path%2520with%2520spaces/test/folder/index.html"); + String malformedPath = absolutePathRoot + "path%2520with%2520spaces/"; + Assert.assertEquals(malformedPath + "test/folder/index.html", resolver.getBaseUri()); + Assert.assertEquals(malformedPath + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); + } + @Test public void uriResolverTest13() throws MalformedURLException { UriResolver resolver = new UriResolver(""); @@ -197,7 +288,7 @@ public void uriResolverTest14() throws MalformedURLException { @Test public void uriResolverTest15() throws MalformedURLException { - String absolutePathRoot = "file:/" + Paths.get("").toAbsolutePath().getRoot().toString().replace('\\', '/').replaceFirst("^/", ""); + String absolutePathRoot = Paths.get("").toAbsolutePath().getRoot().toUri().toURL().toExternalForm(); String absoluteBaseUri = absolutePathRoot + "test/folder/index.html"; UriResolver resolver = new UriResolver(absoluteBaseUri); Assert.assertEquals(absolutePathRoot + "test/folder/index.html", resolver.getBaseUri()); @@ -209,21 +300,88 @@ public void uriResolverTest15() throws MalformedURLException { @Test public void uriResolverTest16() throws MalformedURLException { - String absolutePathRoot = "file:///" + Paths.get("").toAbsolutePath().getRoot().toString().replace('\\', '/').replaceFirst("^/", ""); + String absolutePathRoot = Paths.get("").toAbsolutePath().getRoot().toUri().toURL().toString(); String absoluteBaseUri = absolutePathRoot + "test/folder/index.html"; UriResolver resolver = new UriResolver(absoluteBaseUri); - String singleSlashRootPath = absolutePathRoot.replace("///", "/"); - Assert.assertEquals(singleSlashRootPath + "test/folder/index.html", resolver.getBaseUri()); - Assert.assertEquals(singleSlashRootPath + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); - Assert.assertEquals(singleSlashRootPath + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); - Assert.assertEquals(singleSlashRootPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); - Assert.assertEquals(singleSlashRootPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); + Assert.assertEquals(absolutePathRoot + "test/folder/index.html", resolver.getBaseUri()); + Assert.assertEquals(absolutePathRoot + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); + Assert.assertEquals(absolutePathRoot + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); + Assert.assertEquals(absolutePathRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertEquals(absolutePathRoot + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); + } + + @Test + public void uriResolverTest16A() throws MalformedURLException { + String absolutePathRoot = Paths.get("").toAbsolutePath().getRoot().toUri().toURL().toString(); + String absoluteBaseUri = absolutePathRoot + "path/with/spaces/test/folder/index.html"; + UriResolver resolver = new UriResolver(absoluteBaseUri); + String malformedPath = absolutePathRoot + "path/with/spaces/"; + Assert.assertEquals(malformedPath + "test/folder/index.html", resolver.getBaseUri()); + Assert.assertEquals(malformedPath + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); + } + + @Test + //TODO RND-1019 this test should fail in .Net version when RND-1019 is resolved this method produces a behavior that is not consistant in java vs .Net + // the whitespace characters are + public void uriResolverTest16B() throws MalformedURLException { + String absolutePathRoot = Paths.get("").toAbsolutePath().getRoot().toUri().toURL().toString(); + + String absoluteBaseUri = absolutePathRoot + "path%2Fwith%2Fspaces/test/folder/index.html"; + UriResolver resolver = new UriResolver(absoluteBaseUri); + String malformedPath = absolutePathRoot + "path%2Fwith%2Fspaces/"; + Assert.assertEquals(malformedPath + "test/folder/index.html", resolver.getBaseUri()); + Assert.assertEquals(malformedPath + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); + } + + @Test + public void uriResolverTest16C() throws MalformedURLException { + String absolutePathRoot = Paths.get("").toAbsolutePath().getRoot().toUri().toURL().toString(); + String absoluteBaseUri = absolutePathRoot + "path%252Fwith%252Fspaces/test/folder/index.html"; + UriResolver resolver = new UriResolver(absoluteBaseUri); + String malformedPath = absolutePathRoot + "path%252Fwith%252Fspaces/"; + Assert.assertEquals(malformedPath + "test/folder/index.html", resolver.getBaseUri()); + Assert.assertEquals(malformedPath + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); + } + + @Test + public void uriResolverTest16D() throws MalformedURLException { + String absolutePathRoot = Paths.get("").toAbsolutePath().getRoot().toUri().toURL().toString(); + String absoluteBaseUri = absolutePathRoot + "path%25252Fwith%25252Fspaces/test/folder/index.html"; + UriResolver resolver = new UriResolver(absoluteBaseUri); + String malformedPath = absolutePathRoot + "path%25252Fwith%25252Fspaces/"; + Assert.assertEquals(malformedPath + "test/folder/index.html", resolver.getBaseUri()); + Assert.assertEquals(malformedPath + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertEquals(malformedPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); } @Test public void uriResolverTest17() throws MalformedURLException { - String absolutePathRoot = "file:///" + Paths.get("").toAbsolutePath().getRoot().toString().replace('\\', '/').replaceFirst("^/", ""); - String absoluteBaseUri = absolutePathRoot + "test/fol ders/wi@th/diffe#rent/$characters/index.html\t\t\t\t\t\t"; + String absolutePathRoot = Paths.get("").toAbsolutePath().getRoot().toUri().toURL().toString(); + String absoluteBaseUri = absolutePathRoot + "test/fol ders/wi@th/diffe#rent/$characters/test/folder/index.html\t\t\t\t\t\t"; + UriResolver resolver = new UriResolver(absoluteBaseUri); + String malformedPath = absolutePathRoot + "test/fol%20ders/wi@th/diffe#rent/$characters/"; + Assert.assertNotNull(malformedPath + "test/folder/innerTest", resolver.resolveAgainstBaseUri("innerTest").toExternalForm()); + Assert.assertNotNull(malformedPath + "test/folder2/innerTest2", resolver.resolveAgainstBaseUri("../folder2/innerTest2").toExternalForm()); + Assert.assertNotNull(malformedPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("/folder2/innerTest2").toExternalForm()); + Assert.assertNotNull(malformedPath + "test/folder/folder2/innerTest2", resolver.resolveAgainstBaseUri("//folder2/innerTest2").toExternalForm()); + } + + @Test + public void uriResolverTest18() { + String absolutePathRoot ="http://"; + String absoluteBaseUri = absolutePathRoot + "test/folders/index.html"; UriResolver resolver = new UriResolver(absoluteBaseUri); + Assert.assertFalse(resolver.isLocalBaseUri()); } } diff --git a/src/test/resources/com/itextpdf/styledxmlparser/resolver/retrieveStreamTest/resourceResolverTest.png b/src/test/resources/com/itextpdf/styledxmlparser/resolver/retrieveStreamTest/resourceResolverTest.png new file mode 100644 index 0000000000000000000000000000000000000000..7dbc85a25b3a8ca794111be24d7c059326aa87fc GIT binary patch literal 4313 zcmeAS@N?(olHy`uVBq!ia0y~yU}<1rVCvvt0*bVIibVk_#^NA%Cx&(BWL^R}Ea{HE zjtmSN`?>!lvI6;>1s;*b3=BdgAk26#O}>JGK_Ji5#WAEJ?(JRsBH?g`1BqVKH8qP{ zrc9XvAzx}(GO4-9 z-2=LH0M0uDRQmMtUxwR!s%#7lcQ)*<mD!qJ5a|vBR8s?-ducjc>d!^ z_os*BUwh42XCq^GbocYeug&?7Uj|0WOpXofcRohvoO?B@6K|Fg#N}kay2@bGrIt%juhHie9zP zxgHy=c94PL0SCv1OOevmJf@|Zmw#E+@a0-@0t4*Kk?S94>d3$Edhvm+`uFX3v9E2- z#2$Zi&biM4k=&_sjdg49qV;Asj*G9p&R_OCe%n5_+uwm1!1!ZnjoWhRH%)I1ubuz& zYtPg_2I~Uio8R7^?tfgFfx*GM;cRxshW7cJU(Erk*q)#J`t_4nKTUissuh_S4#=?F zxU=kb@|=wVg&S`>7FK-xc(mdNS6k8TxD#<5z+h)*EMr*~t^Cfn;O#dXo1e>m-Lep^ z7E@wkaPV!AZGL$+VX}I&uef|%xc=Lu_g?)9z#Oozk-=K1`+V${zw$Hn>}m|;cC*FD z0lm@jL#)o^+pdi7C)U4?sIl0(_d+9oA<*yZIvK2`c3*AtSKD59_rTex+uV_@K;^oO zWhT@5%P($~eeGTsyZvPu&^Zn#!aqDN{I&DU;T^Y_r}J;j-0*bq$MryQrv}-nNAqeQ zoV^N+AOm5>vJ^9J!R!29Vet$MANC3+0F$U7BhW5^QRZkkj3$E7%rIIKjFyO_)xl`B tINBx{Z5xd?3`bkVG;I}6h*!lvI6;>1s;*b3=BdgAk26#O}>JGK_Ji5#WAEJ?(JRsBH?g`1BqVKH8qP{ zrc9XvAzx}(GO4-9 z-2=LH0M0uDRQmMtUxwR!s%#7lcQ)*<mD!qJ5a|vBR8s?-ducjc>d!^ z_os*BUwh42XCq^GbocYeug&?7Uj|0WOpXofcRohvoO?B@6K|Fg#N}kay2@bGrIt%juhHie9zP zxgHy=c94PL0SCv1OOevmJf@|Zmw#E+@a0-@0t4*Kk?S94>d3$Edhvm+`uFX3v9E2- z#2$Zi&biM4k=&_sjdg49qV;Asj*G9p&R_OCe%n5_+uwm1!1!ZnjoWhRH%)I1ubuz& zYtPg_2I~Uio8R7^?tfgFfx*GM;cRxshW7cJU(Erk*q)#J`t_4nKTUissuh_S4#=?F zxU=kb@|=wVg&S`>7FK-xc(mdNS6k8TxD#<5z+h)*EMr*~t^Cfn;O#dXo1e>m-Lep^ z7E@wkaPV!AZGL$+VX}I&uef|%xc=Lu_g?)9z#Oozk-=K1`+V${zw$Hn>}m|;cC*FD z0lm@jL#)o^+pdi7C)U4?sIl0(_d+9oA<*yZIvK2`c3*AtSKD59_rTex+uV_@K;^oO zWhT@5%P($~eeGTsyZvPu&^Zn#!aqDN{I&DU;T^Y_r}J;j-0*bq$MryQrv}-nNAqeQ zoV^N+AOm5>vJ^9J!R!29Vet$MANC3+0F$U7BhW5^QRZkkj3$E7%rIIKjFyO_)xl`B tINBx{Z5xd?3`bkVG;I}6h* Date: Thu, 21 Jun 2018 08:36:39 +0200 Subject: [PATCH 12/23] RND-864 fix sonarqube discovered bugs --- .../styledxmlparser/css/CssFontFaceRule.java | 5 +++-- .../css/media/MediaExpression.java | 7 +------ .../styledxmlparser/css/media/MediaQuery.java | 3 ++- .../styledxmlparser/css/util/CssUtils.java | 19 ++++++++++++++----- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/CssFontFaceRule.java b/src/main/java/com/itextpdf/styledxmlparser/css/CssFontFaceRule.java index 9189c13660..1225a0b76b 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/CssFontFaceRule.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/CssFontFaceRule.java @@ -44,6 +44,7 @@ This file is part of the iText (R) project. import com.itextpdf.io.util.MessageFormatUtil; +import java.util.ArrayList; import java.util.List; /** @@ -71,7 +72,7 @@ public CssFontFaceRule(String ruleParameters) { * @return the properties */ public List getProperties() { - return properties; + return new ArrayList<>(properties) ; } /* (non-Javadoc) @@ -79,7 +80,7 @@ public List getProperties() { */ @Override public void addBodyCssDeclarations(List cssDeclarations) { - properties = cssDeclarations; + properties = new ArrayList<>(cssDeclarations); } /* (non-Javadoc) diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/media/MediaExpression.java b/src/main/java/com/itextpdf/styledxmlparser/css/media/MediaExpression.java index cecfbb664d..f8926a900a 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/media/MediaExpression.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/media/MediaExpression.java @@ -134,7 +134,7 @@ public boolean matches(MediaDeviceDescription deviceDescription) { } else if (maxPrefix) { return aspectRatio != null && aspectRatio[0] * deviceDescription.getHeight() <= aspectRatio[1] * deviceDescription.getWidth(); } else { - return aspectRatio != null && equals(aspectRatio[0] * deviceDescription.getHeight(), aspectRatio[1] * deviceDescription.getWidth(), 0.000001); + return aspectRatio != null && CssUtils.compareFloats(aspectRatio[0] * deviceDescription.getHeight(), aspectRatio[1] * deviceDescription.getWidth()); } } case MediaFeature.GRID: { @@ -206,9 +206,4 @@ private static float parseAbsoluteLength(String value) { return CssUtils.parseAbsoluteLength(value); } } - - private static boolean equals(double a, double b, double epsilon) { - return a == b ? true : Math.abs(a - b) < epsilon; - } - } diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/media/MediaQuery.java b/src/main/java/com/itextpdf/styledxmlparser/css/media/MediaQuery.java index dd858102e6..3f94893a25 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/media/MediaQuery.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/media/MediaQuery.java @@ -42,6 +42,7 @@ This file is part of the iText (R) project. */ package com.itextpdf.styledxmlparser.css.media; +import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -80,7 +81,7 @@ public class MediaQuery { */ MediaQuery(String type, List expressions, boolean only, boolean not) { this.type = type; - this.expressions = expressions; + this.expressions = new ArrayList<>(expressions); this.only = only; this.not = not; } diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/util/CssUtils.java b/src/main/java/com/itextpdf/styledxmlparser/css/util/CssUtils.java index 44fab77d2c..105d4728cf 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/util/CssUtils.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/util/CssUtils.java @@ -55,8 +55,9 @@ This file is part of the iText (R) project. */ public class CssUtils { - private static final String[] METRIC_MEASUREMENTS = new String[] {CssConstants.PX, CssConstants.IN, CssConstants.CM, CssConstants.MM, CssConstants.PC, CssConstants.PT}; - private static final String[] RELATIVE_MEASUREMENTS = new String[] {CssConstants.PERCENTAGE, CssConstants.EM, CssConstants.EX, CssConstants.REM}; + private static final String[] METRIC_MEASUREMENTS = new String[]{CssConstants.PX, CssConstants.IN, CssConstants.CM, CssConstants.MM, CssConstants.PC, CssConstants.PT}; + private static final String[] RELATIVE_MEASUREMENTS = new String[]{CssConstants.PERCENTAGE, CssConstants.EM, CssConstants.EX, CssConstants.REM}; + private static final float EPSILON = 0.000000000000001f; /** * Creates a new {@link CssUtils} instance. @@ -234,7 +235,7 @@ public static float parseRelativeValue(final String relativeValue, final float b } else if (unit.startsWith(CssConstants.EX)) { f = baseValue * f / 2; } - return (float)f; + return (float) f; } /** @@ -284,8 +285,7 @@ private static int determinePositionBetweenValueAndUnit(String string) { } /** - - /** + * /** * Checks whether a string contains an allowed metric unit in HTML/CSS; px, in, cm, mm, pc or pt. * * @param value the string that needs to be checked. @@ -410,4 +410,13 @@ public static boolean isColorProperty(String value) { return value.contains("rgb(") || value.contains("rgba(") || value.contains("#") || CssConstants.TRANSPARENT.equals(value); } + + /** + * Helper method for comparing floating point numbers + * @return true if both floating point numbers are close enough to be considered equal + */ + public static boolean compareFloats(double f1, double f2) { + return (Math.abs(f1 - f2) < EPSILON); + } + } From 7659f4c112d1b0b54a704c5bcfdb571beb6f48f2 Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 22 Jun 2018 14:13:31 +0200 Subject: [PATCH 13/23] RND-864 add tests to improve coverage --- .../css/CssNestedAtRuleFactory.java | 4 +- .../css/media/package-info.java | 1 + .../html2pdf/css/CssMatchingTest.java | 161 ++++ .../html2pdf/css/CssStyleSheetParserTest.java | 168 +++++ .../css/media/CssMediaRuleTest.java | 143 ++++ .../css/CssMatchingTest/css01.css | 3 + .../css/CssMatchingTest/css02.css | 6 + .../css/CssMatchingTest/css03.css | 16 + .../css/CssMatchingTest/css04.css | 3 + .../css/CssMatchingTest/css05.css | 7 + .../css/CssMatchingTest/css06.css | 7 + .../css/CssMatchingTest/html01.html | 5 + .../css/CssMatchingTest/html02.html | 5 + .../css/CssMatchingTest/html03.html | 5 + .../css/CssMatchingTest/html04.html | 5 + .../css/CssMatchingTest/html05.html | 5 + .../css/CssMatchingTest/html06.html | 5 + .../css/CssStyleSheetParserTest/cmp_css02.css | 3 + .../css/CssStyleSheetParserTest/cmp_css03.css | 12 + .../css/CssStyleSheetParserTest/cmp_css05.css | 10 + .../css/CssStyleSheetParserTest/cmp_css06.css | 12 + .../css/CssStyleSheetParserTest/cmp_css08.css | 24 + .../css/CssStyleSheetParserTest/cmp_css10.css | 6 + .../css/CssStyleSheetParserTest/cmp_css11.css | 35 + .../css/CssStyleSheetParserTest/cmp_css12.css | 4 + .../CssStyleSheetParserTest/cmp_default.css | 701 ++++++++++++++++++ .../css/CssStyleSheetParserTest/css01.css | 4 + .../css/CssStyleSheetParserTest/css02.css | 4 + .../css/CssStyleSheetParserTest/css03.css | 16 + .../css/CssStyleSheetParserTest/css04.css | 2 + .../css/CssStyleSheetParserTest/css05.css | 8 + .../css/CssStyleSheetParserTest/css06.css | 4 + .../css/CssStyleSheetParserTest/css07.css | 9 + .../css/CssStyleSheetParserTest/css08.css | 23 + .../css/CssStyleSheetParserTest/css09.css | 3 + .../css/CssStyleSheetParserTest/css10.css | 13 + .../css/CssStyleSheetParserTest/css11.css | 54 ++ .../css/CssStyleSheetParserTest/css12.css | 5 + .../css/CssStyleSheetParserTest/html01.html | 84 +++ .../css/media/MediaRuleTest/css01.css | 15 + .../css/media/MediaRuleTest/css02.css | 6 + .../css/media/MediaRuleTest/css03.css | 5 + .../css/media/MediaRuleTest/css04.css | 11 + .../css/media/MediaRuleTest/css05.css | 5 + .../css/media/MediaRuleTest/css06.css | 5 + .../css/media/MediaRuleTest/css07.css | 3 + .../css/media/MediaRuleTest/html01.html | 5 + .../css/media/MediaRuleTest/html02.html | 5 + .../css/media/MediaRuleTest/html03.html | 5 + .../css/media/MediaRuleTest/html04.html | 5 + .../css/media/MediaRuleTest/html05.html | 5 + .../css/media/MediaRuleTest/html06.html | 5 + .../css/media/MediaRuleTest/html07.html | 8 + 53 files changed, 1672 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/media/package-info.java create mode 100644 src/test/java/com/itextpdf/html2pdf/css/CssMatchingTest.java create mode 100644 src/test/java/com/itextpdf/html2pdf/css/CssStyleSheetParserTest.java create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/css01.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/css02.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/css03.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/css04.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/css05.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/css06.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/html01.html create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/html02.html create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/html03.html create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/html04.html create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/html05.html create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/html06.html create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css02.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css03.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css05.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css06.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css08.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css10.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css11.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css12.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_default.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css01.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css02.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css03.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css04.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css05.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css06.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css07.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css08.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css09.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css10.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css11.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css12.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/html01.html create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css01.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css02.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css03.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css04.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css05.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css06.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css07.css create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html01.html create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html02.html create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html03.html create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html04.html create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html05.html create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html06.html create mode 100644 src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html07.html diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/CssNestedAtRuleFactory.java b/src/main/java/com/itextpdf/styledxmlparser/css/CssNestedAtRuleFactory.java index 7779b36766..a9d20c4811 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/CssNestedAtRuleFactory.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/CssNestedAtRuleFactory.java @@ -43,6 +43,8 @@ This file is part of the iText (R) project. package com.itextpdf.styledxmlparser.css; +import com.itextpdf.styledxmlparser.css.media.CssMediaRule; + /** * A factory for creating {@link CssNestedAtRule} objects. */ @@ -67,7 +69,7 @@ public static CssNestedAtRule createNestedRule(String ruleDeclaration) { //TODO (RND-863) consider media rules in SVG switch (ruleName) { case CssRuleName.MEDIA: - //return new CssMediaRule(ruleParameters); + return new CssMediaRule(ruleParameters); case CssRuleName.PAGE: //return new CssPageRule(ruleParameters); case CssRuleName.TOP_LEFT_CORNER: diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/media/package-info.java b/src/main/java/com/itextpdf/styledxmlparser/css/media/package-info.java new file mode 100644 index 0000000000..46bc74ca33 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/media/package-info.java @@ -0,0 +1 @@ +package com.itextpdf.styledxmlparser.css.media; \ No newline at end of file diff --git a/src/test/java/com/itextpdf/html2pdf/css/CssMatchingTest.java b/src/test/java/com/itextpdf/html2pdf/css/CssMatchingTest.java new file mode 100644 index 0000000000..cbe562ed5f --- /dev/null +++ b/src/test/java/com/itextpdf/html2pdf/css/CssMatchingTest.java @@ -0,0 +1,161 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 iText Group NV + Authors: iText Software. + + 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.html2pdf.css; + + +import com.itextpdf.styledxmlparser.IHtmlParser; +import com.itextpdf.styledxmlparser.css.CssDeclaration; +import com.itextpdf.styledxmlparser.css.CssStyleSheet; +import com.itextpdf.styledxmlparser.css.media.MediaDeviceDescription; +import com.itextpdf.styledxmlparser.css.parse.CssStyleSheetParser; +import com.itextpdf.styledxmlparser.node.IDocumentNode; +import com.itextpdf.styledxmlparser.node.IElementNode; +import com.itextpdf.styledxmlparser.node.impl.jsoup.JsoupXmlParser; +import com.itextpdf.styledxmlparser.node.impl.jsoup.node.JsoupDocumentNode; +import com.itextpdf.styledxmlparser.node.impl.jsoup.node.JsoupElementNode; +import com.itextpdf.test.ExtendedITextTest; +import com.itextpdf.test.annotations.type.UnitTest; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.List; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +@Category(UnitTest.class) +public class CssMatchingTest extends ExtendedITextTest { + + private static final String sourceFolder = "./src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/"; + + @BeforeClass + public static void beforeClass() { + } + + @Test + public void test01() throws IOException { + String htmlFileName = sourceFolder + "html01.html"; + String cssFileName = sourceFolder + "css01.css"; + IHtmlParser htmlParser = new JsoupXmlParser(); + IDocumentNode document = htmlParser.parse(new FileInputStream(htmlFileName), "UTF-8"); + CssStyleSheet css = CssStyleSheetParser.parse(new FileInputStream(cssFileName)); + MediaDeviceDescription deviceDescription = new MediaDeviceDescription("all"); + IElementNode element = new JsoupElementNode(((JsoupDocumentNode)document).getDocument().getElementsByTag("p").first()); + List declarations = css.getCssDeclarations(element, deviceDescription); + Assert.assertEquals(1, declarations.size()); + Assert.assertEquals("font-weight: bold", declarations.get(0).toString()); + } + + @Test + public void test02() throws IOException { + String htmlFileName = sourceFolder + "html02.html"; + String cssFileName = sourceFolder + "css02.css"; + IHtmlParser htmlParser = new JsoupXmlParser(); + IDocumentNode document = htmlParser.parse(new FileInputStream(htmlFileName), "UTF-8"); + CssStyleSheet css = CssStyleSheetParser.parse(new FileInputStream(cssFileName)); + MediaDeviceDescription deviceDescription = new MediaDeviceDescription("all"); + IElementNode element = new JsoupElementNode(((JsoupDocumentNode)document).getDocument().getElementsByTag("p").first()); + List declarations = css.getCssDeclarations(element, deviceDescription); + Assert.assertEquals(2, declarations.size()); + Assert.assertEquals("font-weight: bold", declarations.get(1).toString()); + Assert.assertEquals("color: red", declarations.get(0).toString()); + } + + @Test + public void test03() throws IOException { + String htmlFileName = sourceFolder + "html03.html"; + String cssFileName = sourceFolder + "css03.css"; + IHtmlParser htmlParser = new JsoupXmlParser(); + IDocumentNode document = htmlParser.parse(new FileInputStream(htmlFileName), "UTF-8"); + CssStyleSheet css = CssStyleSheetParser.parse(new FileInputStream(cssFileName)); + MediaDeviceDescription deviceDescription = new MediaDeviceDescription("all"); + IElementNode element = new JsoupElementNode(((JsoupDocumentNode)document).getDocument().getElementsByTag("p").first()); + List declarations = css.getCssDeclarations(element, deviceDescription); + Assert.assertEquals(2, declarations.size()); + Assert.assertEquals("font-weight: bold", declarations.get(0).toString()); + Assert.assertEquals("color: black", declarations.get(1).toString()); + } + + @Test + public void test04() throws IOException { + String htmlFileName = sourceFolder + "html04.html"; + String cssFileName = sourceFolder + "css04.css"; + IHtmlParser htmlParser = new JsoupXmlParser(); + IDocumentNode document = htmlParser.parse(new FileInputStream(htmlFileName), "UTF-8"); + CssStyleSheet css = CssStyleSheetParser.parse(new FileInputStream(cssFileName)); + MediaDeviceDescription deviceDescription = new MediaDeviceDescription("all"); + IElementNode element = new JsoupElementNode(((JsoupDocumentNode)document).getDocument().getElementsByTag("p").first()); + List declarations = css.getCssDeclarations(element, deviceDescription); + Assert.assertEquals(1, declarations.size()); + Assert.assertEquals("font-size: 100px", declarations.get(0).toString()); + } + + @Test + public void test05() throws IOException { + String htmlFileName = sourceFolder + "html05.html"; + String cssFileName = sourceFolder + "css05.css"; + IHtmlParser htmlParser = new JsoupXmlParser(); + IDocumentNode document = htmlParser.parse(new FileInputStream(htmlFileName), "UTF-8"); + CssStyleSheet css = CssStyleSheetParser.parse(new FileInputStream(cssFileName)); + MediaDeviceDescription deviceDescription = new MediaDeviceDescription("all"); + IElementNode element = new JsoupElementNode(((JsoupDocumentNode)document).getDocument().getElementsByTag("p").first()); + List declarations = css.getCssDeclarations(element, deviceDescription); + Assert.assertEquals(1, declarations.size()); + Assert.assertEquals("color: red", declarations.get(0).toString()); + } + + @Test + public void test06() throws IOException { + String htmlFileName = sourceFolder + "html06.html"; + String cssFileName = sourceFolder + "css06.css"; + IHtmlParser htmlParser = new JsoupXmlParser(); + IDocumentNode document = htmlParser.parse(new FileInputStream(htmlFileName), "UTF-8"); + CssStyleSheet css = CssStyleSheetParser.parse(new FileInputStream(cssFileName)); + MediaDeviceDescription deviceDescription = new MediaDeviceDescription("all"); + IElementNode element = new JsoupElementNode(((JsoupDocumentNode)document).getDocument().getElementsByTag("p").first()); + List declarations = css.getCssDeclarations(element, deviceDescription); + Assert.assertEquals(1, declarations.size()); + Assert.assertEquals("color: blue", declarations.get(0).toString()); + } + +} diff --git a/src/test/java/com/itextpdf/html2pdf/css/CssStyleSheetParserTest.java b/src/test/java/com/itextpdf/html2pdf/css/CssStyleSheetParserTest.java new file mode 100644 index 0000000000..7b2f7e0283 --- /dev/null +++ b/src/test/java/com/itextpdf/html2pdf/css/CssStyleSheetParserTest.java @@ -0,0 +1,168 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 iText Group NV + Authors: iText Software. + + 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.html2pdf.css; + +import com.itextpdf.io.util.StreamUtil; +import com.itextpdf.styledxmlparser.css.CssStyleSheet; +import com.itextpdf.styledxmlparser.css.parse.CssStyleSheetParser; +import com.itextpdf.test.ExtendedITextTest; +import com.itextpdf.test.annotations.type.UnitTest; +import java.io.FileInputStream; +import java.io.IOException; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +@Category(UnitTest.class) +public class CssStyleSheetParserTest extends ExtendedITextTest { + + private static final String sourceFolder = "./src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/"; + + @BeforeClass + public static void beforeClass() { + } + + @Test + public void test01() throws IOException { + String cssFile = sourceFolder + "css01.css"; + CssStyleSheet styleSheet = CssStyleSheetParser.parse(new FileInputStream(cssFile)); + Assert.assertEquals(getCssFileContents(cssFile), styleSheet.toString()); + } + + @Test + public void test02() throws IOException { + String cssFile = sourceFolder + "css02.css"; + String cmpFile = sourceFolder + "cmp_css02.css"; + CssStyleSheet styleSheet = CssStyleSheetParser.parse(new FileInputStream(cssFile)); + Assert.assertEquals(getCssFileContents(cmpFile), styleSheet.toString()); + } + + @Test + public void test03() throws IOException { + String cssFile = sourceFolder + "css03.css"; + String cmpFile = sourceFolder + "cmp_css03.css"; + CssStyleSheet styleSheet = CssStyleSheetParser.parse(new FileInputStream(cssFile)); + Assert.assertEquals(getCssFileContents(cmpFile), styleSheet.toString()); + } + + @Test + public void test04() throws IOException { + String cssFile = sourceFolder + "css04.css"; + CssStyleSheet styleSheet = CssStyleSheetParser.parse(new FileInputStream(cssFile)); + Assert.assertEquals("", styleSheet.toString()); + } + + @Test + public void test05() throws IOException { + String cssFile = sourceFolder + "css05.css"; + String cmpFile = sourceFolder + "cmp_css05.css"; + CssStyleSheet styleSheet = CssStyleSheetParser.parse(new FileInputStream(cssFile)); + Assert.assertEquals(getCssFileContents(cmpFile), styleSheet.toString()); + } + + @Test + public void test06() throws IOException { + String cssFile = sourceFolder + "css06.css"; + String cmpFile = sourceFolder + "cmp_css06.css"; + CssStyleSheet styleSheet = CssStyleSheetParser.parse(new FileInputStream(cssFile)); + Assert.assertEquals(getCssFileContents(cmpFile), styleSheet.toString()); + } + + @Test + public void test07() throws IOException { + String cssFile = sourceFolder + "css07.css"; + CssStyleSheet styleSheet = CssStyleSheetParser.parse(new FileInputStream(cssFile)); + Assert.assertEquals(getCssFileContents(cssFile), styleSheet.toString()); + } + + @Test + public void test08() throws IOException { + String cssFile = sourceFolder + "css08.css"; + String cmpFile = sourceFolder + "cmp_css08.css"; + CssStyleSheet styleSheet = CssStyleSheetParser.parse(new FileInputStream(cssFile)); + Assert.assertEquals(getCssFileContents(cmpFile), styleSheet.toString()); + } + + @Test + public void test09() throws IOException { + String cssFile = sourceFolder + "css09.css"; + CssStyleSheet styleSheet = CssStyleSheetParser.parse(new FileInputStream(cssFile)); + Assert.assertEquals(getCssFileContents(cssFile), styleSheet.toString()); + } + + @Test + public void test10() throws IOException { + String cssFile = sourceFolder + "css10.css"; + String cmpFile = sourceFolder + "cmp_css10.css"; + CssStyleSheet styleSheet = CssStyleSheetParser.parse(new FileInputStream(cssFile)); + Assert.assertEquals(getCssFileContents(cmpFile), styleSheet.toString()); + } + + @Test + public void test11() throws IOException { + // TODO in this test declarations of the page at-rule with compound selector are duplicated. + // See CssPageRule#addBodyCssDeclarations() method for the reason and possible solution if this becomes important. + + String cssFile = sourceFolder + "css11.css"; + String cmpFile = sourceFolder + "cmp_css11.css"; + CssStyleSheet styleSheet = CssStyleSheetParser.parse(new FileInputStream(cssFile)); + Assert.assertEquals(getCssFileContents(cmpFile), styleSheet.toString()); + } + + @Test + public void test12() throws IOException { + String cssFile = sourceFolder + "css12.css"; + String cmpFile = sourceFolder + "cmp_css12.css"; + CssStyleSheet styleSheet = CssStyleSheetParser.parse(new FileInputStream(cssFile)); + Assert.assertEquals(getCssFileContents(cmpFile), styleSheet.toString()); + } + + private String getCssFileContents(String filePath) throws IOException { + byte[] bytes = StreamUtil.inputStreamToArray(new FileInputStream(filePath)); + String content = new String(bytes); + content = content.trim(); + content = content.replace("\r\n", "\n"); + return content; + } +} diff --git a/src/test/java/com/itextpdf/styledxmlparser/css/media/CssMediaRuleTest.java b/src/test/java/com/itextpdf/styledxmlparser/css/media/CssMediaRuleTest.java index 0784678cde..06cd9c1b89 100644 --- a/src/test/java/com/itextpdf/styledxmlparser/css/media/CssMediaRuleTest.java +++ b/src/test/java/com/itextpdf/styledxmlparser/css/media/CssMediaRuleTest.java @@ -1,18 +1,161 @@ package com.itextpdf.styledxmlparser.css.media; +import com.itextpdf.styledxmlparser.IHtmlParser; +import com.itextpdf.styledxmlparser.css.CssDeclaration; import com.itextpdf.styledxmlparser.css.CssRuleSet; +import com.itextpdf.styledxmlparser.css.CssStyleSheet; +import com.itextpdf.styledxmlparser.css.parse.CssStyleSheetParser; import com.itextpdf.styledxmlparser.node.IDocumentNode; +import com.itextpdf.styledxmlparser.node.IElementNode; import com.itextpdf.styledxmlparser.node.impl.jsoup.JsoupHtmlParser; +import com.itextpdf.styledxmlparser.node.impl.jsoup.node.JsoupDocumentNode; +import com.itextpdf.styledxmlparser.node.impl.jsoup.node.JsoupElementNode; import com.itextpdf.test.ExtendedITextTest; import com.itextpdf.test.annotations.type.UnitTest; +import java.io.FileInputStream; +import java.io.IOException; import java.util.List; import org.junit.Assert; +import org.junit.BeforeClass; import org.junit.Test; import org.junit.experimental.categories.Category; @Category(UnitTest.class) public class CssMediaRuleTest extends ExtendedITextTest { + private static final String sourceFolder = "./src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/"; + + @BeforeClass + public static void beforeClass() { + } + + + @Test + public void test01() throws IOException { + String htmlFileName = sourceFolder + "html01.html"; + String cssFileName = sourceFolder + "css01.css"; + IHtmlParser htmlParser = new JsoupHtmlParser(); + IDocumentNode document = htmlParser.parse(new FileInputStream(htmlFileName), "UTF-8"); + CssStyleSheet css = CssStyleSheetParser.parse(new FileInputStream(cssFileName)); + MediaDeviceDescription deviceDescription = new MediaDeviceDescription(MediaType.PRINT); + IElementNode element = new JsoupElementNode(((JsoupDocumentNode) document).getDocument().getElementsByTag("p").first()); + List declarations = css.getCssDeclarations(element, deviceDescription); + Assert.assertEquals(3, declarations.size()); + Assert.assertEquals("font-weight: bold", declarations.get(0).toString()); + Assert.assertEquals("color: red", declarations.get(1).toString()); + Assert.assertEquals("font-size: 20pt", declarations.get(2).toString()); + } + + @Test + public void test02() throws IOException { + String htmlFileName = sourceFolder + "html02.html"; + String cssFileName = sourceFolder + "css02.css"; + IHtmlParser htmlParser = new JsoupHtmlParser(); + IDocumentNode document = htmlParser.parse(new FileInputStream(htmlFileName), "UTF-8"); + CssStyleSheet css = CssStyleSheetParser.parse(new FileInputStream(cssFileName)); + IElementNode element = new JsoupElementNode(((JsoupDocumentNode) document).getDocument().getElementsByTag("p").first()); + + MediaDeviceDescription deviceDescription1 = new MediaDeviceDescription(MediaType.PRINT); + deviceDescription1.setWidth(525); + + MediaDeviceDescription deviceDescription2 = new MediaDeviceDescription(MediaType.HANDHELD); + deviceDescription2.setOrientation("landscape"); + + List declarations1 = css.getCssDeclarations(element, deviceDescription1); + List declarations2 = css.getCssDeclarations(element, deviceDescription2); + + Assert.assertTrue(declarations1.equals(declarations2)); + + Assert.assertEquals(1, declarations1.size()); + Assert.assertEquals("font-weight: bold", declarations1.get(0).toString()); + } + + @Test + public void test03() throws IOException { + String htmlFileName = sourceFolder + "html03.html"; + String cssFileName = sourceFolder + "css03.css"; + IHtmlParser htmlParser = new JsoupHtmlParser(); + IDocumentNode document = htmlParser.parse(new FileInputStream(htmlFileName), "UTF-8"); + CssStyleSheet css = CssStyleSheetParser.parse(new FileInputStream(cssFileName)); + MediaDeviceDescription deviceDescription = new MediaDeviceDescription(MediaType.PRINT); + deviceDescription.setResolution(300); + IElementNode element = new JsoupElementNode(((JsoupDocumentNode) document).getDocument().getElementsByTag("p").first()); + List declarations = css.getCssDeclarations(element, deviceDescription); + Assert.assertEquals(1, declarations.size()); + Assert.assertEquals("color: black", declarations.get(0).toString()); + } + + @Test + public void test04() throws IOException { + String htmlFileName = sourceFolder + "html04.html"; + String cssFileName = sourceFolder + "css04.css"; + IHtmlParser htmlParser = new JsoupHtmlParser(); + IDocumentNode document = htmlParser.parse(new FileInputStream(htmlFileName), "UTF-8"); + CssStyleSheet css = CssStyleSheetParser.parse(new FileInputStream(cssFileName)); + + MediaDeviceDescription deviceDescription = new MediaDeviceDescription(MediaType.PRINT).setColorIndex(256); + + IElementNode element = new JsoupElementNode(((JsoupDocumentNode) document).getDocument().getElementsByTag("p").first()); + List declarations = css.getCssDeclarations(element, deviceDescription); + Assert.assertEquals(2, declarations.size()); + Assert.assertEquals("color: red", declarations.get(0).toString()); + Assert.assertEquals("font-size: 20em", declarations.get(1).toString()); + } + + @Test + public void test05() throws IOException { + String htmlFileName = sourceFolder + "html05.html"; + String cssFileName = sourceFolder + "css05.css"; + IHtmlParser htmlParser = new JsoupHtmlParser(); + IDocumentNode document = htmlParser.parse(new FileInputStream(htmlFileName), "UTF-8"); + CssStyleSheet css = CssStyleSheetParser.parse(new FileInputStream(cssFileName)); + IElementNode element = new JsoupElementNode(((JsoupDocumentNode) document).getDocument().getElementsByTag("p").first()); + + MediaDeviceDescription deviceDescription1 = new MediaDeviceDescription(MediaType.PRINT). + setWidth(300).setHeight(301); + + MediaDeviceDescription deviceDescription2 = new MediaDeviceDescription(MediaType.SCREEN). + setWidth(400).setHeight(400); + + List declarations1 = css.getCssDeclarations(element, deviceDescription1); + List declarations2 = css.getCssDeclarations(element, deviceDescription2); + + Assert.assertEquals(0, declarations1.size()); + + Assert.assertEquals(1, declarations2.size()); + Assert.assertEquals("color: red", declarations2.get(0).toString()); + } + + @Test + public void test06() throws IOException { + String htmlFileName = sourceFolder + "html06.html"; + String cssFileName = sourceFolder + "css06.css"; + IHtmlParser htmlParser = new JsoupHtmlParser(); + IDocumentNode document = htmlParser.parse(new FileInputStream(htmlFileName), "UTF-8"); + CssStyleSheet css = CssStyleSheetParser.parse(new FileInputStream(cssFileName)); + IElementNode element = new JsoupElementNode(((JsoupDocumentNode) document).getDocument().getElementsByTag("p").first()); + + MediaDeviceDescription deviceDescription1 = new MediaDeviceDescription(MediaType.PRINT). + setBitsPerComponent(2); + + MediaDeviceDescription deviceDescription2 = new MediaDeviceDescription(MediaType.HANDHELD). + setBitsPerComponent(2); + + MediaDeviceDescription deviceDescription3 = new MediaDeviceDescription(MediaType.SCREEN). + setBitsPerComponent(1); + + List declarations1 = css.getCssDeclarations(element, deviceDescription1); + List declarations2 = css.getCssDeclarations(element, deviceDescription2); + List declarations3 = css.getCssDeclarations(element, deviceDescription3); + + Assert.assertTrue(declarations1.equals(declarations2)); + Assert.assertEquals(0, declarations3.size()); + + Assert.assertEquals(1, declarations1.size()); + Assert.assertEquals("color: red", declarations1.get(0).toString()); + } + + @Test public void matchMediaDeviceTest() { MediaDeviceDescription deviceDescription = new MediaDeviceDescription("all"); diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/css01.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/css01.css new file mode 100644 index 0000000000..a221fb806b --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/css01.css @@ -0,0 +1,3 @@ +p { +font-weight: bold +} \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/css02.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/css02.css new file mode 100644 index 0000000000..f7cfbfd464 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/css02.css @@ -0,0 +1,6 @@ +p { +font-weight: bold +} +* { +color: red; +} \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/css03.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/css03.css new file mode 100644 index 0000000000..e47e585978 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/css03.css @@ -0,0 +1,16 @@ +#id777 { + color: blue; + +} +p { +font-weight: bold; +color: red; +} +* { +font-weight: normal; +color: pink +} + +p#id777 { + color: black; +} \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/css04.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/css04.css new file mode 100644 index 0000000000..31f70afaa7 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/css04.css @@ -0,0 +1,3 @@ +p[custom] { + font-size: 100px; +} \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/css05.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/css05.css new file mode 100644 index 0000000000..0821f51efa --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/css05.css @@ -0,0 +1,7 @@ +#id777 { + color: red !important; +} + +.cls { + color: blue !important; +} \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/css06.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/css06.css new file mode 100644 index 0000000000..64a122ce24 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/css06.css @@ -0,0 +1,7 @@ +#id777 { + color: red; +} + +.cls { + color: blue !important; +} \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/html01.html b/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/html01.html new file mode 100644 index 0000000000..0f432bc0c2 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/html01.html @@ -0,0 +1,5 @@ + + +

Hello world!

+ + \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/html02.html b/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/html02.html new file mode 100644 index 0000000000..0f432bc0c2 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/html02.html @@ -0,0 +1,5 @@ + + +

Hello world!

+ + \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/html03.html b/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/html03.html new file mode 100644 index 0000000000..0e506a11fe --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/html03.html @@ -0,0 +1,5 @@ + + +

Hello world!

+ + \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/html04.html b/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/html04.html new file mode 100644 index 0000000000..cc10024431 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/html04.html @@ -0,0 +1,5 @@ + + +

Hello world!

+ + \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/html05.html b/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/html05.html new file mode 100644 index 0000000000..3648e7e524 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/html05.html @@ -0,0 +1,5 @@ + + +

Hello world!

+ + \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/html06.html b/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/html06.html new file mode 100644 index 0000000000..3648e7e524 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssMatchingTest/html06.html @@ -0,0 +1,5 @@ + + +

Hello world!

+ + \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css02.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css02.css new file mode 100644 index 0000000000..5879116c1f --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css02.css @@ -0,0 +1,3 @@ +div { + font-size: 2em +} diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css03.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css03.css new file mode 100644 index 0000000000..68211cd6de --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css03.css @@ -0,0 +1,12 @@ +p { + color: green; + font-size: 10pt +} +@media screen { + p { + color: red + } +} +.blue { + color: blue +} \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css05.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css05.css new file mode 100644 index 0000000000..2b9bc1f0bb --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css05.css @@ -0,0 +1,10 @@ +@media print { + #navigation { + display: none + } + @media (max-width: 12cm) { + .note { + float: none + } + } +} \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css06.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css06.css new file mode 100644 index 0000000000..14d75c4023 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css06.css @@ -0,0 +1,12 @@ +div { + font-size: 10pt; + color: red +} +p { + font-size: 10pt; + color: red +} +#navbar { + font-size: 10pt; + color: red +} \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css08.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css08.css new file mode 100644 index 0000000000..3612001af4 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css08.css @@ -0,0 +1,24 @@ +a[rel="nofollow"] { + +} +a[rel="nofollow"] { + +} +a[rel="nofollow"] { + +} +object[type^="image/"] { + +} +a[href$=".html"] { + +} +p[title*="hello"] { + +} +e[foo~="bar"] { + +} +e[foo|="en"] { + +} \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css10.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css10.css new file mode 100644 index 0000000000..0a54ac090e --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css10.css @@ -0,0 +1,6 @@ +blockquote { + margin: 1em 40px +} +blockquote { + padding: 1em 40px +} \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css11.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css11.css new file mode 100644 index 0000000000..8c957cd2fe --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css11.css @@ -0,0 +1,35 @@ +@font-face { + size: a4 +} +@font-face { + size: landscape + margin: 3in +} +@font-face { + size: a5 + border: solid 1px +} +@font-face { + margin: 1in +} +@font-face { + size: a5 landscape + margin: 0.5in 1in 0.5in 0.5in +} +@font-face { + margin-left: 1in +} +@media print { + @font-face { + margin-left: 1in + } +} +@font-face { + margin: 0.5in +} +@font-face { + background-color: #ccc +} +@font-face { + background-color: #ccf +} \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css12.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css12.css new file mode 100644 index 0000000000..ac57fc95d3 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_css12.css @@ -0,0 +1,4 @@ +@font-face { + font-family: "Font" + src: url(http://some-font.eot) format("embedded-opentype"),url(data:application/font-woff;base64,2CBPCRXmgywtV1t4oWwjBju0kqkvfhPs0cYdMgFtDSY5uL7MIGT5wiGs078HrvBHekp0Yf=) format("truetype") +} \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_default.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_default.css new file mode 100644 index 0000000000..ee87689479 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/cmp_default.css @@ -0,0 +1,701 @@ +html { + font-family: times-roman +} +pre { + font-family: monospace; + font-size: 9pt; + line-height: 12pt +} +tt { + font-family: monospace; + font-size: 9pt; + line-height: 12pt +} +code { + font-family: monospace; + font-size: 9pt; + line-height: 12pt +} +kbd { + font-family: monospace; + font-size: 9pt; + line-height: 12pt +} +samp { + font-family: monospace; + font-size: 9pt; + line-height: 12pt +} +dt { + margin: 0 +} +big { + font-size: larger +} +small { + font-size: smaller +} +b { + font-weight: bold +} +i { + font-style: italic +} +html { + font-size: 12pt; + display: block +} +body { + font-size: 12pt; + display: block +} +p { + margin: 1em 0 +} +dl { + margin: 1em 0 +} +multicol { + margin: 1em 0 +} +dd { + margin-left: 40px; + margin-bottom: 0; + margin-right: 0; + margin-top: 0 +} +blockquote { + margin: 1em 40px +} +figure { + margin: 1em 40px +} +center { + display: block; + text-align: center +} +blockquote[type="cite"] { + border: 3px solid; + padding-left: 1em; + border-color: blue; + border-width: thin; + margin: 1em 0 +} +h1 { + font-size: 2em; + font-weight: bold; + margin: 0.67em 0 +} +h2 { + font-size: 1.5em; + font-weight: bold; + margin: 0.83em 0 +} +h3 { + font-size: 1.17em; + font-weight: bold; + margin: 1em 0 +} +h4 { + font-size: 1em; + font-weight: bold; + margin: 1.33em 0 +} +h5 { + font-size: 0.83em; + font-weight: bold; + margin: 1.67em 0 +} +h6 { + font-size: 0.67em; + font-weight: bold; + margin: 2.33em 0 +} +listing { + font-size: medium; + margin: 1em 0; + white-space: pre +} +xmp { + margin: 1em 0; + white-space: pre +} +pre { + margin: 1em 0; + white-space: pre +} +plaintext { + margin: 1em 0; + white-space: pre +} +table { + margin-bottom: 0; + margin-top: 0; + margin-left: 0; + margin-right: 0; + text-indent: 0; + border-spacing: 2px +} +caption { + text-align: center; + display: table-caption +} +tr { + vertical-align: inherit +} +tbody { + vertical-align: middle +} +thead { + vertical-align: middle +} +tfoot { + vertical-align: middle +} +table > tr { + vertical-align: middle +} +td { + padding: 1px; + text-align: inherit; + vertical-align: inherit; + background-color: inherit +} +th { + display: table-cell; + font-weight: bold; + padding: 1px; + vertical-align: inherit; + text-align: center; + background-color: inherit +} +sub { + font-size: smaller; + vertical-align: sub +} +sup { + font-size: smaller; + vertical-align: super +} +nobr { + white-space: nowrap +} +mark { + background: none repeat scroll 0 0 yellow; + color: black +} +abbr[title] { + border-bottom: 1px dotted +} +acronym[title] { + border-bottom: 1px dotted +} +ul { + list-style-type: disc; + margin: 1em 0; + padding-left: 40px +} +menu { + list-style-type: disc; + margin: 1em 0; + padding-left: 40px +} +dir { + list-style-type: disc; + margin: 1em 0; + padding-left: 40px +} +ul li ul { + list-style-type: circle +} +ol ul { + margin-top: 0; + margin-bottom: 0 +} +ul ol { + margin-top: 0; + margin-bottom: 0 +} +ul ul { + margin-top: 0; + margin-bottom: 0 +} +ol ol { + margin-top: 0; + margin-bottom: 0 +} +ol { + list-style-type: decimal; + margin: 1em 0; + padding-left: 40px +} +dl { + display: block; + margin: 1em 0 +} +hr { + display: block; + margin-top: 0.5em; + margin-bottom: 0.5em; + margin-left: auto; + margin-right: auto; + border-style: inset; + border-width: 1px +} +pre { + display: block; + white-space: pre; + margin: 1em 0 +} +em { + font-style: italic +} +u { + text-decoration: underline +} +strike { + text-decoration: line-through +} +strong { + font-weight: bold +} +a[href] { + text-decoration: underline; + color: blue +} +q { + display: inline +} +q::before { + content: open-quote +} +q::after { + content: close-quote +} +aside { + display: block +} +article { + display: block +} +main { + display: block +} +nav { + display: block +} +footer { + display: block +} +header { + display: block +} +section { + display: block +} +cite { + font-style: italic +} +code { + font-family: monospace +} +address { + display: block; + font-style: italic +} +center { + text-align: center +} +del { + text-decoration: line-through +} +dfn { + font-style: italic +} +fieldset { + display: block; + margin-left: 2px; + margin-right: 2px; + padding-top: 0.35em; + padding-bottom: 0.625em; + padding-left: 0.75em; + padding-right: 0.75em; + border: 2px groove +} +figcaption { + display: block +} +figure { + display: block; + margin-top: 1em; + margin-bottom: 1em; + margin-left: 40px; + margin-right: 40px +} +ins { + text-decoration: underline +} +kbd { + font-family: monospace +} +mark { + background-color: yellow; + color: black +} +s { + text-decoration: line-through +} +samp { + font-family: monospace +} +var { + font-style: italic +} +img[align="left"] { + margin-right: 3px +} +img { + display: inline-block +} +input { + color: initial; + letter-spacing: normal; + word-spacing: normal; + text-transform: none; + text-indent: 0px; + text-shadow: none; + display: inline-block; + text-align: start; + margin: 0em 0em 0em 0em; + font: 13.3333px arial +} +textarea { + color: initial; + letter-spacing: normal; + word-spacing: normal; + text-transform: none; + text-indent: 0px; + text-shadow: none; + display: inline-block; + text-align: start; + margin: 0em 0em 0em 0em; + font: 13.3333px arial +} +select { + color: initial; + letter-spacing: normal; + word-spacing: normal; + text-transform: none; + text-indent: 0px; + text-shadow: none; + display: inline-block; + text-align: start; + margin: 0em 0em 0em 0em; + font: 13.3333px arial +} +button { + color: initial; + letter-spacing: normal; + word-spacing: normal; + text-transform: none; + text-indent: 0px; + text-shadow: none; + display: inline-block; + text-align: start; + margin: 0em 0em 0em 0em; + font: 13.3333px arial +} +input { + background-color: white; + padding: 1px; + border: 2px inset black; + border-image: initial +} +input:not([type]) { + padding: 1px 0px +} +input[type="email"] { + padding: 1px 0px +} +input[type="number"] { + padding: 1px 0px +} +input[type="password"] { + padding: 1px 0px +} +input[type="tel"] { + padding: 1px 0px +} +input[type="url"] { + padding: 1px 0px +} +input[type="text"] { + padding: 1px 0px +} +input[type="radio"] { + margin: 3px 3px 0px 5px; + padding: 0px; + border: initial +} +input[type="button"] { + background-color: lightgrey; + border: 2px outset black; + border-image: initial; + box-sizing: border-box; + text-align: center; + padding: 1px 6px +} +input[type="submit"] { + background-color: lightgrey; + border: 2px outset black; + border-image: initial; + box-sizing: border-box; + text-align: center; + padding: 1px 6px +} +button { + background-color: lightgrey; + border: 2px outset black; + border-image: initial; + box-sizing: border-box; + text-align: center; + padding: 1px 6px +} +input[type="radio"] { + margin: 3px 0.5ex; + padding: initial; + border: initial +} +input[type="checkbox"] { + margin: 3px 0.5ex; + padding: initial; + border: initial +} +input[type="checkbox"] { + margin: 3px 3px 3px 4px; + box-sizing: border-box +} +select { + box-sizing: border-box; + white-space: pre; + color: black; + background-color: white; + overflow: hidden; + border: 1px solid rgb(169,169,169) +} +optgroup { + line-height: initial; + font-weight: bold; + display: block +} +option { + font-weight: normal; + display: block; + white-space: pre; + min-height: 1.2em; + padding: 0px 2px 1px +} +optgroup option::before { + content: " " +} +textarea { + font-family: courier; + background-color: white; + white-space: pre-wrap; + word-wrap: break-word; + border-image: initial; + border: 1px solid rgb(169,169,169); + padding: 2px +} +legend { + display: block; + padding-left: 2px; + padding-right: 2px; + border: none +} +address { + display: block +} +blockquote { + display: block +} +body { + display: block +} +dd { + display: block +} +div { + display: block +} +dl { + display: block +} +dt { + display: block +} +fieldset { + display: block +} +form { + display: block +} +frame { + display: block +} +frameset { + display: block +} +h1 { + display: block +} +h2 { + display: block +} +h3 { + display: block +} +h4 { + display: block +} +h5 { + display: block +} +h6 { + display: block +} +iframe { + display: block +} +noframes { + display: block +} +object { + display: block +} +ol { + display: block +} +p { + display: block +} +ul { + display: block +} +applet { + display: block +} +center { + display: block +} +dir { + display: block +} +hr { + display: block +} +menu { + display: block +} +pre { + display: block +} +li { + display: list-item +} +table { + display: table +} +tr { + display: table-row +} +thead { + display: table-header-group +} +tbody { + display: table-row-group +} +tfoot { + display: table-footer-group +} +col { + display: table-column +} +colgroup { + display: table-column-group +} +td { + display: table-cell +} +th { + display: table-cell +} +caption { + display: table-caption +} +@page { + @top-left-corner { + text-align: right; + vertical-align: middle + } + @top-left { + text-align: left; + vertical-align: middle + } + @top-center { + text-align: center; + vertical-align: middle + } + @top-right { + text-align: right; + vertical-align: middle + } + @top-right-corner { + text-align: left; + vertical-align: middle + } + @left-top { + text-align: center; + vertical-align: top + } + @left-middle { + text-align: center; + vertical-align: middle + } + @left-bottom { + text-align: center; + vertical-align: bottom + } + @right-top { + text-align: center; + vertical-align: top + } + @right-middle { + text-align: center; + vertical-align: middle + } + @right-bottom { + text-align: center; + vertical-align: bottom + } + @bottom-left-corner { + text-align: right; + vertical-align: middle + } + @bottom-left { + text-align: left; + vertical-align: middle + } + @bottom-center { + text-align: center; + vertical-align: middle + } + @bottom-right { + text-align: right; + vertical-align: middle + } + @bottom-right-corner { + text-align: left; + vertical-align: middle + } +} \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css01.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css01.css new file mode 100644 index 0000000000..1d5714d050 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css01.css @@ -0,0 +1,4 @@ +div { + font-size: 2em +} + diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css02.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css02.css new file mode 100644 index 0000000000..cfb7a04ddd --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css02.css @@ -0,0 +1,4 @@ +div { + /*123*/ font-size: 2em +} + diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css03.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css03.css new file mode 100644 index 0000000000..f62a5ac394 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css03.css @@ -0,0 +1,16 @@ + + + p { + color: green; + font-size: 10pt; + } + +@media screen { + p { + color: red; + } +} + + .blue { + color: blue; + } \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css04.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css04.css new file mode 100644 index 0000000000..c44db7146b --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css04.css @@ -0,0 +1,2 @@ +font-size: 2em + diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css05.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css05.css new file mode 100644 index 0000000000..15aafb63cf --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css05.css @@ -0,0 +1,8 @@ +@media print { + /* hide navigation controls when printing */ + #navigation { display: none } + @media (max-width: 12cm) { + /* keep notes in flow when printing to narrow pages */ + .note { float: none } + } +} \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css06.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css06.css new file mode 100644 index 0000000000..9328be92f9 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css06.css @@ -0,0 +1,4 @@ +div, p, #navbar { + font-size: 10pt; +color:red; +} \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css07.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css07.css new file mode 100644 index 0000000000..efd3c087a6 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css07.css @@ -0,0 +1,9 @@ +@import url("fineprint.css") print; +@import url("bluish.css") projection, tv; +@import 'custom.css'; +@import url("chrome://communicator/skin/"); +@import "common.css" screen, projection; +@import url('landscape.css') screen and (orientation:landscape); +.myclass { + font-size: 10pt +} \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css08.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css08.css new file mode 100644 index 0000000000..c96cbdda6e --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css08.css @@ -0,0 +1,23 @@ +a[rel=nofollow] { +} + +a[rel='nofollow'] { +} + +a[rel="nofollow"] { +} + +object[type^="image/"] { +} + +a[href$=".html"] { +} + +p[title*="hello"] { +} + +e[foo~="bar"] { +} + +e[foo|="en"] { +} \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css09.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css09.css new file mode 100644 index 0000000000..be93b4c216 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css09.css @@ -0,0 +1,3 @@ +blockquote { + margin: 1em 40px +} \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css10.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css10.css new file mode 100644 index 0000000000..5f4c1f76b6 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css10.css @@ -0,0 +1,13 @@ +/* +some random comment +*/ + +blockquote { + margin: 1em 40px +} + +/****** Multistars comment ******/ + +blockquote { + padding: 1em 40px +} \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css11.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css11.css new file mode 100644 index 0000000000..7067783efa --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css11.css @@ -0,0 +1,54 @@ +@page { + size: a4; +} +@page:first { + size: landscape; + margin: 3in; +} +@page { + size: a5; + border: solid 1px; +} +@page:left { + margin: 1in; +} +@page asdjf, auTo, customPageName:right:right,:left { + size: a5 landscape; + margin: 0.5in 1in 0.5in 0.5in; + @left-bottom { + color: red; + content: "Left content."; + } +} +@page :left:left:first { + margin-left: + + + 1in; +} +@media print { + @page + + :right:right + + { + + @top-left { + content: "Some header text " counter(chapter); + } + + margin-left: + + + 1in; + } +} +@page :right { + margin: 0.5in; +} +@page :right { + background-color: #ccc; +} +@page :left { + background-color: #ccf; +} \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css12.css b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css12.css new file mode 100644 index 0000000000..de22e29da9 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/css12.css @@ -0,0 +1,5 @@ +@font-face { + font-family: "Font"; + src: url(http://some-font.eot) format("embedded-opentype"), + url(data:application/font-woff;base64,2CBPCRXmgywtV1t4oWwjBju0kqkvfhPs0cYdMgFtDSY5uL7MIGT5wiGs078HrvBHekp0Yf=) format("truetype"); +} diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/html01.html b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/html01.html new file mode 100644 index 0000000000..20e776fe63 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/html01.html @@ -0,0 +1,84 @@ + + + + + +

Hello world

+ + \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css01.css b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css01.css new file mode 100644 index 0000000000..be2bb3df7a --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css01.css @@ -0,0 +1,15 @@ +@media print { + p { + font-weight: bold + } +} + +@media all { + p { + color: red; + } +} + +p { + font-size: 20pt; +} \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css02.css b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css02.css new file mode 100644 index 0000000000..e4e7c00918 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css02.css @@ -0,0 +1,6 @@ +@media (min-width: 700px), handheld and (orientation: landscape) { + p { + font-weight: bold + } +} + diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css03.css b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css03.css new file mode 100644 index 0000000000..5e691b28d7 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css03.css @@ -0,0 +1,5 @@ +@media print and (min-resolution: 300dpi) { + p { + color: black; + } +} \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css04.css b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css04.css new file mode 100644 index 0000000000..557ca51c76 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css04.css @@ -0,0 +1,11 @@ +@media all and (color-index) { + p { + color: red; + } +} + +@media all and (min-color-index: 256) { + P { + font-size: 20em; + } +} \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css05.css b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css05.css new file mode 100644 index 0000000000..320203325d --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css05.css @@ -0,0 +1,5 @@ +@media screen and (min-aspect-ratio: 1/1) { + p { + color: red; + } +} \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css06.css b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css06.css new file mode 100644 index 0000000000..13ac6c26a3 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css06.css @@ -0,0 +1,5 @@ +@media not screen and (color), print and (color) { + p { + color: red; + } +} \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css07.css b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css07.css new file mode 100644 index 0000000000..0bd13cd09c --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/css07.css @@ -0,0 +1,3 @@ + p { + font-size: 20pt; + } \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html01.html b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html01.html new file mode 100644 index 0000000000..0f432bc0c2 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html01.html @@ -0,0 +1,5 @@ + + +

Hello world!

+ + \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html02.html b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html02.html new file mode 100644 index 0000000000..0f432bc0c2 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html02.html @@ -0,0 +1,5 @@ + + +

Hello world!

+ + \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html03.html b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html03.html new file mode 100644 index 0000000000..0e506a11fe --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html03.html @@ -0,0 +1,5 @@ + + +

Hello world!

+ + \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html04.html b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html04.html new file mode 100644 index 0000000000..cc10024431 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html04.html @@ -0,0 +1,5 @@ + + +

Hello world!

+ + \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html05.html b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html05.html new file mode 100644 index 0000000000..3648e7e524 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html05.html @@ -0,0 +1,5 @@ + + +

Hello world!

+ + \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html06.html b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html06.html new file mode 100644 index 0000000000..3648e7e524 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html06.html @@ -0,0 +1,5 @@ + + +

Hello world!

+ + \ No newline at end of file diff --git a/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html07.html b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html07.html new file mode 100644 index 0000000000..db4cbb88f5 --- /dev/null +++ b/src/test/resources/com/itextpdf/styledxmlparser/css/media/MediaRuleTest/html07.html @@ -0,0 +1,8 @@ + + + + + +

Hello world!

+ + From bf7669d7cab2d76577955a6fdba748e40fc121ae Mon Sep 17 00:00:00 2001 From: Samuel Huylebroeck Date: Fri, 1 Jun 2018 14:59:57 +0200 Subject: [PATCH 14/23] Move classes and tests from html2pdf to SXP DEVSIX-1955 --- .../styledxmlparser/AttributeConstants.java | 257 -------------- .../CommonAttributeConstants.java | 14 + .../{IHtmlParser.java => IXmlParser.java} | 26 +- .../styledxmlparser/LogMessageConstant.java | 8 +- .../styledxmlparser/TagConstants.java | 313 ------------------ ...Constants.java => CommonCssConstants.java} | 235 +------------ .../styledxmlparser/css/CssContextNode.java | 117 +++++++ .../styledxmlparser/css/CssFontFaceRule.java | 4 +- .../styledxmlparser/css/CssNestedAtRule.java | 2 +- .../css/CssNestedAtRuleFactory.java | 6 +- .../styledxmlparser/css/CssRuleSet.java | 2 +- .../css/CssRuleSetComparator.java | 64 ++++ .../styledxmlparser/css/ICssResolver.java | 6 +- .../css/media/CssMediaRule.java | 2 +- .../css/page/CssMarginRule.java | 89 +++++ .../css/page/CssNonStandardRuleSet.java | 88 +++++ .../styledxmlparser/css/page/CssPageRule.java | 125 +++++++ .../PageContextConstants.java} | 34 +- .../css/page/PageContextNode.java | 119 +++++++ .../css/page/PageMarginBoxContextNode.java | 119 +++++++ .../css/page/package-info.java | 1 + .../css/parse/CssPageSelectorParser.java | 85 +++++ .../css/parse/CssSelectorParser.java | 62 +++- .../css/parse/syntax/AtRuleBlockState.java | 2 +- .../css/parse/syntax/CommentEndState.java | 2 +- .../css/parse/syntax/CommentInnerState.java | 2 +- .../css/parse/syntax/CommentStartState.java | 2 +- .../ConditionalGroupAtRuleBlockState.java | 2 +- .../css/parse/syntax/PropertiesState.java | 2 +- .../css/parse/syntax/RuleState.java | 2 +- .../css/parse/syntax/UnknownState.java | 2 +- .../css/pseudo/CssPseudoElementNode.java | 177 ++++++++++ .../css/pseudo/CssPseudoElementUtil.java | 80 +++++ .../css/pseudo/package-info.java | 1 + .../css/resolve/AbstractCssContext.java | 75 +++++ .../css/resolve/CssDefaults.java | 162 +++++++++ .../css/resolve/CssInheritance.java | 142 ++++++++ .../css/resolve/CssPropertyMerger.java | 106 ++++++ .../css/resolve/CssQuotes.java | 195 +++++++++++ .../shorthand/ShorthandResolverFactory.java | 34 +- .../impl/AbstractBorderShorthandResolver.java | 28 +- .../impl/AbstractBoxShorthandResolver.java | 6 +- .../AbstractCornersShorthandResolver.java | 143 ++++++++ .../impl/BackgroundShorthandResolver.java | 235 +++++++++++++ .../impl/BorderBottomShorthandResolver.java | 59 ++++ .../impl/BorderColorShorthandResolver.java | 67 ++++ .../impl/BorderLeftShorthandResolver.java | 59 ++++ .../impl/BorderRadiusShorthandResolver.java | 67 ++++ .../impl/BorderRightShorthandResolver.java | 59 ++++ .../impl/BorderShorthandResolver.java | 8 +- .../impl/BorderStyleShorthandResolver.java} | 33 +- .../impl/BorderTopShorthandResolver.java | 59 ++++ .../impl/BorderWidthShorthandResolver.java | 67 ++++ .../shorthand/impl/FontShorthandResolver.java | 44 +-- .../impl/ListStyleShorthandResolver.java | 103 ++++++ .../impl/MarginShorthandResolver.java | 67 ++++ .../impl/OutlineShorthandResolver.java | 59 ++++ .../impl/PaddingShorthandResolver.java | 67 ++++ .../css/selector/AbstractCssSelector.java | 4 +- .../selector/CssPageMarginBoxSelector.java | 93 ++++++ .../css/selector/CssPageSelector.java | 80 +++++ .../css/selector/CssSelector.java | 8 +- .../item/CssAttributeSelectorItem.java | 4 +- .../selector/item/CssClassSelectorItem.java | 8 +- .../css/selector/item/CssIdSelectorItem.java | 8 +- .../item/CssPagePseudoClassSelectorItem.java | 88 +++++ .../item/CssPageTypeSelectorItem.java | 84 +++++ .../item/CssPseudoClassChildSelectorItem.java | 63 ++++ .../item/CssPseudoClassEmptySelectorItem.java | 36 ++ .../CssPseudoClassFirstChildSelectorItem.java | 29 ++ ...CssPseudoClassFirstOfTypeSelectorItem.java | 29 ++ .../CssPseudoClassLastChildSelectorItem.java | 29 ++ .../CssPseudoClassLastOfTypeSelectorItem.java | 29 ++ .../item/CssPseudoClassNotSelectorItem.java | 32 ++ .../CssPseudoClassNthChildSelectorItem.java | 10 + .../CssPseudoClassNthOfTypeSelectorItem.java | 24 ++ .../item/CssPseudoClassNthSelectorItem.java | 90 +++++ .../item/CssPseudoClassRootSelectorItem.java | 28 ++ .../item/CssPseudoClassSelectorItem.java | 196 +++++++++++ .../item/CssPseudoElementSelectorItem.java | 89 +++++ .../item/CssSeparatorSelectorItem.java | 4 +- .../css/selector/item/CssTagSelectorItem.java | 4 +- .../css/selector/item/package-info.java | 1 + .../css/selector/package-info.java | 1 + .../styledxmlparser/css/util/CssUtils.java | 103 ++++-- .../CssDeclarationValidationMaster.java | 36 +- .../impl/datatype/CssColorValidator.java | 7 +- .../impl/datatype/CssEnumValidator.java | 2 +- .../impl/datatype/CssIdentifierValidator.java | 2 +- .../impl/datatype/CssQuotesValidator.java | 7 +- .../impl/datatype/CssTransformValidator.java | 40 +-- .../MultiTypeDeclarationValidator.java | 2 +- .../SingleTypeDeclarationValidator.java | 2 +- .../jsoup/helper/DataUtil.java | 9 +- .../styledxmlparser/jsoup/nodes/Element.java | 19 +- .../node/impl/jsoup/JsoupHtmlParser.java | 8 +- .../node/impl/jsoup/JsoupXmlParser.java | 8 +- .../node/impl/jsoup/node/JsoupAttribute.java | 4 +- .../node/impl/jsoup/node/JsoupAttributes.java | 6 +- .../node/impl/jsoup/node/JsoupDataNode.java | 2 +- .../impl/jsoup/node/JsoupElementNode.java | 20 +- .../node/impl/jsoup/node/JsoupNode.java | 6 +- .../node/impl/jsoup/node/JsoupTextNode.java | 2 +- ...ntProvider.java => BasicFontProvider.java} | 58 +--- .../resolver/resource/ResourceResolver.java | 73 +++- .../resolver/resource/UriResolver.java | 2 +- .../html2pdf/css/CssStyleSheetParserTest.java | 168 ---------- .../css/CssMatchingTest.java | 23 +- .../css/media/CssMediaRuleTest.java | 14 +- .../shorthand/CssShorthandResolverTest.java | 20 +- .../item/SpecificityCalculationTest.java | 209 ++++++++++++ .../styledxmlparser/css/util/CssUtilTest.java | 109 ++++++ .../css/util/CssUtilsTest.java | 10 +- .../resource/ResourceResolverTest.java | 2 +- 114 files changed, 4734 insertions(+), 1306 deletions(-) delete mode 100644 src/main/java/com/itextpdf/styledxmlparser/AttributeConstants.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/CommonAttributeConstants.java rename src/main/java/com/itextpdf/styledxmlparser/{IHtmlParser.java => IXmlParser.java} (77%) delete mode 100644 src/main/java/com/itextpdf/styledxmlparser/TagConstants.java rename src/main/java/com/itextpdf/styledxmlparser/css/{CssConstants.java => CommonCssConstants.java} (79%) create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/CssContextNode.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/CssRuleSetComparator.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/page/CssMarginRule.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/page/CssNonStandardRuleSet.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/page/CssPageRule.java rename src/main/java/com/itextpdf/styledxmlparser/css/{ICssContext.java => page/PageContextConstants.java} (77%) create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/page/PageContextNode.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/page/PageMarginBoxContextNode.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/page/package-info.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/parse/CssPageSelectorParser.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/pseudo/CssPseudoElementNode.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/pseudo/CssPseudoElementUtil.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/pseudo/package-info.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/resolve/AbstractCssContext.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssDefaults.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssInheritance.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssPropertyMerger.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssQuotes.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/AbstractCornersShorthandResolver.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BackgroundShorthandResolver.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderBottomShorthandResolver.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderColorShorthandResolver.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderLeftShorthandResolver.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderRadiusShorthandResolver.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderRightShorthandResolver.java rename src/main/java/com/itextpdf/styledxmlparser/{HtmlUtils.java => css/resolve/shorthand/impl/BorderStyleShorthandResolver.java} (74%) create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderTopShorthandResolver.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderWidthShorthandResolver.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/ListStyleShorthandResolver.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/MarginShorthandResolver.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/OutlineShorthandResolver.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/PaddingShorthandResolver.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/selector/CssPageMarginBoxSelector.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/selector/CssPageSelector.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPagePseudoClassSelectorItem.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPageTypeSelectorItem.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassChildSelectorItem.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassEmptySelectorItem.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassFirstChildSelectorItem.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassFirstOfTypeSelectorItem.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassLastChildSelectorItem.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassLastOfTypeSelectorItem.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassNotSelectorItem.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassNthChildSelectorItem.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassNthOfTypeSelectorItem.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassNthSelectorItem.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassRootSelectorItem.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassSelectorItem.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoElementSelectorItem.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/selector/item/package-info.java create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/selector/package-info.java rename src/main/java/com/itextpdf/styledxmlparser/resolver/font/{DefaultFontProvider.java => BasicFontProvider.java} (58%) delete mode 100644 src/test/java/com/itextpdf/html2pdf/css/CssStyleSheetParserTest.java rename src/test/java/com/itextpdf/{html2pdf => styledxmlparser}/css/CssMatchingTest.java (93%) create mode 100644 src/test/java/com/itextpdf/styledxmlparser/css/selector/item/SpecificityCalculationTest.java create mode 100644 src/test/java/com/itextpdf/styledxmlparser/css/util/CssUtilTest.java diff --git a/src/main/java/com/itextpdf/styledxmlparser/AttributeConstants.java b/src/main/java/com/itextpdf/styledxmlparser/AttributeConstants.java deleted file mode 100644 index b3d9b68e61..0000000000 --- a/src/main/java/com/itextpdf/styledxmlparser/AttributeConstants.java +++ /dev/null @@ -1,257 +0,0 @@ -/* - This file is part of the iText (R) project. - Copyright (c) 1998-2018 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.styledxmlparser; - -/** - * Class that bundles a series of attribute constants. - */ -public final class AttributeConstants { - /** - * Creates a new {@link AttributeConstants} instance. - */ - private AttributeConstants() { - } - - /** The Constant ALIGN. */ - public static final String ALIGN = "align"; - - /** The Constant ALT. */ - public static final String ALT = "alt"; - - /** The Constant APPLICATION_NAME. */ - public static final String APPLICATION_NAME = "application-name"; - - /** The Constant AUTHOR. */ - public static final String AUTHOR = "author"; - - /** The Constant BGCOLOR. */ - public static final String BGCOLOR = "bgcolor"; - - /** The Constant BORDER. */ - public static final String BORDER = "border"; - - /** The Constant CLASS. */ - public static final String CLASS = "class"; - - /** The Constant CLASS. */ - public static final String CELLPADDING = "cellpadding"; - - /** The Constant CLASS. */ - public static final String CELLSPACING = "cellspacing"; - - /** The Constant COLOR. */ - public static final String COLOR = "color"; - - /** The Constant COLS. */ - public static final String COLS = "cols"; - - /** The Constant COLSPAN. */ - public static final String COLSPAN = "colspan"; - - /** The Constant CONTENT. */ - public static final String CONTENT = "content"; - - /** The Constant DATA */ - public static final String DATA = "data"; - - /** The Constant DESCRIPTION. */ - public static final String DESCRIPTION = "description"; - - /** The Constant DIR. */ - public static final String DIR = "dir"; - - /** The Constant FACE. */ - public static final String FACE = "face"; - - /** The Constant HEIGHT. */ - public static final String HEIGHT = "height"; - - /** The Constant HREF. */ - public static final String HREF = "href"; - - /** The Constant HSPACE. */ - public static final String HSPACE = "hspace"; - - /** The Constant ID. */ - public static final String ID = "id"; - - /** The Constant KEYWORDS. */ - public static final String KEYWORDS = "keywords"; - - /** The Constant LANG. */ - public static final String LANG = "lang"; - - /** The Constant MEDIA. */ - public static final String MEDIA = "media"; - - /** The Constant NAME. */ - public static final String NAME = "name"; - - /** The Constant NOSHADE. */ - public static final String NOSHADE = "noshade"; - - /** The Constant NUMBER. */ - public static final String NUMBER = "number"; - - /** The Constant REL. */ - public static final String REL = "rel"; - - /** The Constant ROWS. */ - public static final String ROWS = "rows"; - - /** The Constant ROWSPAN. */ - public static final String ROWSPAN = "rowspan"; - - /** The Constant SIZE. */ - public static final String SIZE = "size"; - - /** The Constant SPAN. */ - public static final String SPAN = "span"; - - /** The Constant SRC. */ - public static final String SRC = "src"; - - /** The Constant STYLE. */ - public static final String STYLE = "style"; - - /** The Constant TYPE. */ - public static final String TYPE = "type"; - - /** The Constant VALIGN. */ - public static final String VALIGN = "valign"; - - /** The Constant VALUE. */ - public static final String VALUE = "value"; - - /** The Constant VSPACE. */ - public static final String VSPACE = "vspace"; - - /** The Constant WIDTH. */ - public static final String WIDTH = "width"; - - /** The Constant TITLE. */ - public static final String TITLE = "title"; - - // attribute values - - /** The Constant _1. */ - public static final String _1 = "1"; - - /** The Constant A. */ - public static final String A = "A"; - - /** The Constant a. */ - public static final String a = "a"; - - /** The Constant BOTTOM. */ - public static final String BOTTOM = "bottom"; - - /** The Constant BUTTON. */ - public static final String BUTTON = "button"; - - /** The Constant CENTER. */ - public static final String CENTER = "center"; - - /** The Constant CHECKBOX. */ - public static final String CHECKBOX = "checkbox"; - - /** The Constant CHECKED. */ - public static final String CHECKED = "checked"; - - /** The Constant EMAIL. */ - public static final String EMAIL = "email"; - - /** The Constant I. */ - public static final String I = "I"; - - /** The Constant i. */ - public static final String i = "i"; - - /** The Constant LEFT. */ - public static final String LEFT = "left"; - - /** The Constant LTR. */ - public static final String LTR = "ltr"; - - /** The Constant MIDDLE. */ - public static final String MIDDLE = "middle"; - - /** The Constant PASSWORD. */ - public static final String PASSWORD = "password"; - - /** The Constant RADIO. */ - public static final String RADIO = "radio"; - - /** The Constant RIGHT. */ - public static final String RIGHT = "right"; - - /** The Constant RTL. */ - public static final String RTL = "rtl"; - - /** The Constant STYLESHEET. */ - public static final String STYLESHEET = "stylesheet"; - - /** The Constant SUBMIT. */ - public static final String SUBMIT = "submit"; - - /** The Constant TEXT. */ - public static final String TEXT = "text"; - - /** The Constant TOP. */ - public static final String TOP = "top"; - - /**The Constant start*/ - public static final String START = "start"; - - public static final String PLACEHOLDER = "placeholder"; - - // iText custom attributes - - /** The Constant PARENT_TABLE_BORDER. */ - public static final String PARENT_TABLE_BORDER = "parenttableborder"; - - public final class ObjectTypes{ - public static final String SVGIMAGE = "image/svg+xml"; - } - -} diff --git a/src/main/java/com/itextpdf/styledxmlparser/CommonAttributeConstants.java b/src/main/java/com/itextpdf/styledxmlparser/CommonAttributeConstants.java new file mode 100644 index 0000000000..1f3d81e565 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/CommonAttributeConstants.java @@ -0,0 +1,14 @@ +package com.itextpdf.styledxmlparser; + +public class CommonAttributeConstants { + /** The Constant ID. */ + public static final String ID = "id"; + /** The Constant CLASS. */ + public static final String CLASS = "class"; + /** The Constant LANG. */ + public static final String LANG = "lang"; + /** The Constant LANG. */ + public static final String STYLESHEET = "stylesheet"; + /** The Constant LANG. */ + public static final String REL = "rel"; +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/IHtmlParser.java b/src/main/java/com/itextpdf/styledxmlparser/IXmlParser.java similarity index 77% rename from src/main/java/com/itextpdf/styledxmlparser/IHtmlParser.java rename to src/main/java/com/itextpdf/styledxmlparser/IXmlParser.java index 195b9a65f9..8b62f5e62c 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/IHtmlParser.java +++ b/src/main/java/com/itextpdf/styledxmlparser/IXmlParser.java @@ -1,25 +1,25 @@ /* This file is part of the iText (R) project. - Copyright (c) 1998-2018 iText Group NV + CopyrigX (c) 1998-2018 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 + FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGX IS OWNED BY ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT - OF THIRD PARTY RIGHTS + OF THIRD PARTY RIGXS 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 + along with this program; if not, see Xtp://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/ + Xtp://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 @@ -49,26 +49,26 @@ This file is part of the iText (R) project. import java.io.InputStream; /** - * Interface for the HTML parsing operations that accept HTML and return a document node. + * Interface for the XML parsing operations that accept XML and return a document node. */ -public interface IHtmlParser { +public interface IXmlParser { /** - * Parses HTML provided as an {@code InputStream} and an encoding. + * Parses XML provided as an {@code InputStream} and an encoding. * - * @param htmlStream the html stream + * @param XmlStream the Xml stream * @param charset the character set. If {@code null} then parser should detect encoding from stream. * @return a document node * @throws IOException Signals that an I/O exception has occurred. */ - IDocumentNode parse(InputStream htmlStream, String charset) throws IOException; + IDocumentNode parse(InputStream XmlStream, String charset) throws IOException; /** - * Parses HTML provided as a {@code String}. + * Parses XML provided as a {@code String}. * - * @param html the html string + * @param Xml the Xml string * @return a document node */ - IDocumentNode parse(String html); + IDocumentNode parse(String Xml); } diff --git a/src/main/java/com/itextpdf/styledxmlparser/LogMessageConstant.java b/src/main/java/com/itextpdf/styledxmlparser/LogMessageConstant.java index 3d7ad946dc..c7ab1a6196 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/LogMessageConstant.java +++ b/src/main/java/com/itextpdf/styledxmlparser/LogMessageConstant.java @@ -47,6 +47,8 @@ This file is part of the iText (R) project. */ public final class LogMessageConstant { + /** The Constant DEFAULT_VALUE_OF_CSS_PROPERTY_UNKNOWN. */ + public static final String DEFAULT_VALUE_OF_CSS_PROPERTY_UNKNOWN = "Default value of the css property \"{0}\" is unknown."; /** The Constant ERROR_PARSING_COULD_NOT_MAP_NODE */ public static final String ERROR_PARSING_COULD_NOT_MAP_NODE = "Could not map node type: {0}"; /** The Constant ERROR_PARSING_CSS_SELECTOR. */ @@ -55,6 +57,8 @@ public final class LogMessageConstant { public static final String UNKNOWN_ABSOLUTE_METRIC_LENGTH_PARSED = "Unknown absolute metric length parsed \"{0}\"."; public static final String URL_IS_EMPTY_IN_CSS_EXPRESSION = "url function is empty in expression:{0}"; public static final String URL_IS_NOT_CLOSED_IN_CSS_EXPRESSION = "url function is not properly closed in expression:{0}"; + /** The Constant QUOTES_PROPERTY_INVALID. */ + public static final String QUOTES_PROPERTY_INVALID = "Quote property \"{0}\" is invalid. It should contain even number of values."; /** The Constant QUOTE_IS_NOT_CLOSED_IN_CSS_EXPRESSION. */ public static final String QUOTE_IS_NOT_CLOSED_IN_CSS_EXPRESSION = "The quote is not closed in css expression: {0}"; /** The Constant INVALID_CSS_PROPERTY_DECLARATION. */ @@ -68,7 +72,9 @@ public final class LogMessageConstant { public static final String UNABLE_TO_RETRIEVE_STREAM_WITH_GIVEN_BASE_URI = "Unable to retrieve stream with given base URI ({0}) and source path ({1})"; public static final String UNABLE_TO_PROCESS_EXTERNAL_CSS_FILE = "Unable to process external css file" ; public static final String UNABLE_TO_RETRIEVE_FONT = "Unable to retrieve font:\n {0}"; - + public static final String UNSUPPORTED_PSEUDO_CSS_SELECTOR = "Unsupported pseudo css selector: {0}"; + /** The Constant WAS_NOT_ABLE_TO_DEFINE_BACKGROUND_CSS_SHORTHAND_PROPERTIES. */ + public static final String WAS_NOT_ABLE_TO_DEFINE_BACKGROUND_CSS_SHORTHAND_PROPERTIES = "Was not able to define one of the background CSS shorthand properties: {0}"; /** * Instantiates a new log message constant. */ diff --git a/src/main/java/com/itextpdf/styledxmlparser/TagConstants.java b/src/main/java/com/itextpdf/styledxmlparser/TagConstants.java deleted file mode 100644 index 3b9200b1a0..0000000000 --- a/src/main/java/com/itextpdf/styledxmlparser/TagConstants.java +++ /dev/null @@ -1,313 +0,0 @@ -/* - This file is part of the iText (R) project. - Copyright (c) 1998-2018 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.styledxmlparser; - -/** - * Class that bundles a series of tag constants. - */ -public final class TagConstants { - - /** - * Creates a new {@link TagConstants} instance. - */ - private TagConstants() { - } - - /** The Constant A. */ - public static final String A = "a"; - - /** The Constant ABBR. */ - public static final String ABBR = "abbr"; - - /** The Constant ADDRESS. */ - public static final String ADDRESS="address"; - - /** The Constant ARTICLE. */ - public static final String ARTICLE = "article"; - - /** The Constant ASIDE. */ - public static final String ASIDE = "aside"; - - /** The Constant B. */ - public static final String B = "b"; - - /** The Constant BDI. */ - public static final String BDI = "bdi"; - - /** The Constant BDO. */ - public static final String BDO = "bdo"; - - /** The Constant BIG. */ - public static final String BIG = "big"; - - /** The Constant BLOCKQUOTE. */ - public static final String BLOCKQUOTE = "blockquote"; - - /** The Constant BODY. */ - public static final String BODY = "body"; - - /** The Constant BR. */ - public static final String BR = "br"; - - /** The Constant BUTTON. */ - public static final String BUTTON = "button"; - - /** The Constant CAPTION. */ - public static final String CAPTION = "caption"; - - /** The Constant CENTER. */ - public static final String CENTER = "center"; - - /** The Constant CITE. */ - public static final String CITE = "cite"; - - /** The Constant CODE. */ - public static final String CODE = "code"; - - /** The Constant COL. */ - public static final String COL = "col"; - - /** The Constant COLGROUP. */ - public static final String COLGROUP = "colgroup"; - - /** The Constant DD. */ - public static final String DD = "dd"; - - /** The Constant DEL. */ - public static final String DEL = "del"; - - /** The Constant DFN. */ - public static final String DFN = "dfn"; - - /** The Constant DL. */ - public static final String DL = "dl"; - - /** The Constant DT. */ - public static final String DT = "dt"; - - /** The Constant DIV. */ - public static final String DIV = "div"; - - /** The Constant EM. */ - public static final String EM = "em"; - - /** The Constant FIELDSET. */ - public static final String FIELDSET = "fieldset"; - - /** The Constant FIGCAPTION. */ - public static final String FIGCAPTION = "figcaption"; - - /** The Constant FIGURE. */ - public static final String FIGURE = "figure"; - - /** The Constant FONT. */ - public static final String FONT = "font"; - - /** The Constant FOOTER. */ - public static final String FOOTER = "footer"; - - /** The Constant FORM. */ - public static final String FORM = "form"; - - /** The Constant H1. */ - public static final String H1 = "h1"; - - /** The Constant H2. */ - public static final String H2 = "h2"; - - /** The Constant H3. */ - public static final String H3 = "h3"; - - /** The Constant H4. */ - public static final String H4 = "h4"; - - /** The Constant H5. */ - public static final String H5 = "h5"; - - /** The Constant H6. */ - public static final String H6 = "h6"; - - /** The Constant HR. */ - public static final String HR = "hr"; - - /** The Constant HEAD. */ - public static final String HEAD = "head"; - - /** The Constant HEADER. */ - public static final String HEADER = "header"; - - /** The Constant HTML. */ - public static final String HTML = "html"; - - /** The Constant I. */ - public static final String I = "i"; - - /** The Constant IMG. */ - public static final String IMG = "img"; - - /** The Constant INPUT. */ - public static final String INPUT = "input"; - - /** The Constant INS. */ - public static final String INS = "ins"; - - /** The Constant KBD. */ - public static final String KBD = "kbd"; - - /** The Constant LABEL. */ - public static final String LABEL = "label"; - - /** The Constant LEGEND. */ - public static final String LEGEND = "legend"; - - /** The Constant LI. */ - public static final String LI = "li"; - - /** The Constant LINK. */ - public static final String LINK = "link"; - - /** The Constant MAIN. */ - public static final String MAIN = "main"; - - /** The Constant MARK. */ - public static final String MARK = "mark"; - - /** The Constant MARQUEE. */ - public static final String MARQUEE = "marquee"; - - /** The Constant META. */ - public static final String META = "meta"; - - /** The Constant NAV. */ - public static final String NAV = "nav"; - - /** The Constant OL. */ - public static final String OL = "ol"; - - /** The Constant P. */ - public static final String P = "p"; - - /** The Constant PRE. */ - public static final String PRE = "pre"; - - /** The Constant Q. */ - public static final String Q = "q"; - - /** The Constant S. */ - public static final String S = "s"; - - /** The Constant SAMP. */ - public static final String SAMP = "samp"; - - /** The Constant SCRIPT. */ - public static final String SCRIPT = "script"; - - /** The Constant SECTION. */ - public static final String SECTION = "section"; - - /** The Constant SELECT. */ - public static final String SELECT = "select"; - - /** The Constant SMALL. */ - public static final String SMALL = "small"; - - /** The Constant SPAN. */ - public static final String SPAN = "span"; - - /** The Constant STRIKE. */ - public static final String STRIKE = "strike"; - - /** The Constant STRONG. */ - public static final String STRONG = "strong"; - - /** The Constant STYLE. */ - public static final String STYLE = "style"; - - /** The Constant SUB. */ - public static final String SUB = "sub"; - - /** The Constant SUP. */ - public static final String SUP = "sup"; - - /** The Constant TABLE. */ - public static final String TABLE = "table"; - - /** The Constant TBODY. */ - public static final String TBODY = "tbody"; - - /** The Constant TEXTAREA. */ - public static final String TEXTAREA = "textarea"; - - /** The Constant TD. */ - public static final String TD = "td"; - - /** The Constant TFOOT. */ - public static final String TFOOT = "tfoot"; - - /** The Constant TH. */ - public static final String TH = "th"; - - /** The Constant THEAD. */ - public static final String THEAD = "thead"; - - /** The Constant TIME. */ - public static final String TIME = "time"; - - /** The Constant TITLE. */ - public static final String TITLE = "title"; - - /** The Constant TR. */ - public static final String TR = "tr"; - - /** The Constant TT. */ - public static final String TT = "tt"; - - /** The Constant U. */ - public static final String U = "u"; - - /** The Constant UL. */ - public static final String UL = "ul"; - - /** The Constant VAR. */ - public static final String VAR = "var"; -} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/CssConstants.java b/src/main/java/com/itextpdf/styledxmlparser/css/CommonCssConstants.java similarity index 79% rename from src/main/java/com/itextpdf/styledxmlparser/css/CssConstants.java rename to src/main/java/com/itextpdf/styledxmlparser/css/CommonCssConstants.java index a08dde5128..dc730ce3f7 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/CssConstants.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/CommonCssConstants.java @@ -51,7 +51,7 @@ This file is part of the iText (R) project. * Class containing possible CSS property keys and values, pseudo element keys, * units of measurement, and so on. */ -public class CssConstants { +public class CommonCssConstants { // properties @@ -85,9 +85,6 @@ public class CssConstants { /** The Constant BACKGROUND_SIZE. */ public static final String BACKGROUND_SIZE = "background-size"; - /** The Constant BLEED. */ - public static final String BLEED = "bleed"; - /** The Constant BORDER. */ public static final String BORDER = "border"; @@ -172,39 +169,18 @@ public class CssConstants { /** The Constant BORDER_WIDTH. */ public static final String BORDER_WIDTH = "border-width"; - /** The Constant BOTH. */ - public static final String BOTH = "both"; - /** The Constant BOX_SHADOW. */ public static final String BOX_SHADOW = "box-shadow"; - /** The Constant BOX_SIZING. */ - public static final String BOX_SIZING = "box-sizing"; - /** The Constant CAPTION_SIDE. */ public static final String CAPTION_SIDE = "caption-side"; - /** The Constant CLEAR. */ - public static final String CLEAR = "clear"; - /** The Constant COLOR. */ public static final String COLOR = "color"; - /** The Constant CONTENT. */ - public static final String CONTENT = "content"; - - /** The Constant COUNTER_INCREMENT. */ - public static final String COUNTER_INCREMENT = "counter-increment"; - - /** The Constant COUNTER_RESET. */ - public static final String COUNTER_RESET = "counter-reset"; - /** The Constant DIRECTION. */ public static final String DIRECTION = "direction"; - /** The Constant DISPLAY. */ - public static final String DISPLAY = "display"; - /** The Constant EMPTY_CELLS. */ public static final String EMPTY_CELLS = "empty-cells"; @@ -268,9 +244,6 @@ public class CssConstants { /** The Constant HANGING_PUNCTUATION. */ public static final String HANGING_PUNCTUATION = "hanging-punctuation"; - /** The Constant HEIGHT. */ - public static final String HEIGHT = "height"; - /** The Constant HYPHENS. */ public static final String HYPHENS = "hyphens"; @@ -292,9 +265,6 @@ public class CssConstants { /** The Constant LIST_STYLE_TYPE. */ public static final String LIST_STYLE_TYPE = "list-style-type"; - /** The Constant MARKS. */ - public static final String MARKS = "marks"; - /** The Constant MARGIN. */ public static final String MARGIN = "margin"; @@ -310,9 +280,6 @@ public class CssConstants { /** The Constant MARGIN_TOP. */ public static final String MARGIN_TOP = "margin-top"; - /** The Constant MAX_HEIGHT. */ - public static final String MAX_HEIGHT = "max-height"; - /** The Constant MIN_HEIGHT. */ public static final String MIN_HEIGHT = "min-height"; @@ -325,27 +292,15 @@ public class CssConstants { /** The Constant OUTLINE_COLOR. */ public static final String OUTLINE_COLOR = "outline-color"; - /** The Constant OUTLINE_OFFSET. */ - public static final String OUTLINE_OFFSET = "outline-offset"; - /** The Constant OUTLINE_STYLE. */ public static final String OUTLINE_STYLE = "outline-style"; /** The Constant OUTLINE_WIDTH. */ public static final String OUTLINE_WIDTH = "outline-width"; - /** The Constant OVERFLOW. */ - public static final String OVERFLOW = "overflow"; - /** The Constant OVERFLOW_WRAP. */ public static final String OVERFLOW_WRAP = "overflow-wrap"; - /** The Constant OVERFLOW_X. */ - public static final String OVERFLOW_X = "overflow-x"; - - /** The Constant OVERFLOW_Y. */ - public static final String OVERFLOW_Y = "overflow-y"; - /** The Constant PADDING. */ public static final String PADDING = "padding"; @@ -376,18 +331,9 @@ public class CssConstants { /** The Constant QUOTES. */ public static final String QUOTES = "quotes"; - /** The Constant SIZE. */ - public static final String SIZE = "size"; - - /** The Constant STYLE. */ - public static final String STYLE = "style"; - /** The Constant TAB_SIZE. */ public static final String TAB_SIZE = "tab-size"; - /** The Constant TABLE_LAYOUT. */ - public static final String TABLE_LAYOUT = "table-layout"; - /** The Constant TEXT_ALIGN. */ public static final String TEXT_ALIGN = "text-align"; @@ -424,11 +370,6 @@ public class CssConstants { /** The Constant UNICODE_BIDI. */ public static final String UNICODE_BIDI = "unicode-bidi"; - /** The Constant VERTICAL_ALIGN. */ - public static final String VERTICAL_ALIGN = "vertical-align"; - /** The Constant VISIBILITY. */ - public static final String VISIBLE = "visible"; - /** The Constant VISIBILITY. */ public static final String VISIBILITY = "visibility"; @@ -438,12 +379,6 @@ public class CssConstants { /** The Constant WIDTH. */ public static final String WIDTH = "width"; - /** The Constant MAX_WIDTH. */ - public static final String MAX_WIDTH = "max-width"; - - /** The Constant MIN_WIDTH. */ - public static final String MIN_WIDTH = "min-width"; - /** The Constant WORDWRAP. */ public static final String WORDWRAP = "word-wrap"; @@ -458,9 +393,6 @@ public class CssConstants { // property values - /** The Constant ABSOLUTE. */ - public static final String ABSOLUTE = "absolute"; - /** The Constant ALWAYS. */ public static final String ALWAYS = "always"; @@ -473,12 +405,6 @@ public class CssConstants { /** The Constant AUTO. */ public static final String AUTO = "auto"; - /** The Constant BLINK. */ - public static final String BLINK = "blink"; - - /** The Constant BLOCK. */ - public static final String BLOCK = "block"; - /** The Constant BOLD. */ public static final String BOLD = "bold"; @@ -491,12 +417,6 @@ public class CssConstants { /** The Constant BOTTOM. */ public static final String BOTTOM = "bottom"; - /** The Constant BREAK_WORD. */ - public static final String BREAK_WORD = "break-word"; - - /** The Constant CAPITALIZE. */ - public static final String CAPITALIZE = "capitalize"; - /** The Constant CAPTION. */ public static final String CAPTION = "caption"; @@ -512,9 +432,6 @@ public class CssConstants { /** The Constant CLOSE_QUOTE. */ public static final String CLOSE_QUOTE = "close-quote"; - /** The Constant COLLAPSE. */ - public static final String COLLAPSE = "collapse"; - /** The Constant CONTAIN. */ public static final String CONTAIN = "contain"; @@ -524,12 +441,6 @@ public class CssConstants { /** The Constant COVER. */ public static final String COVER = "cover"; - /** The Constant CROP. */ - public static final String CROP = "crop"; - - /** The Constant CROSS. */ - public static final String CROSS = "cross"; - /** The Constant CURRENTCOLOR. */ public static final String CURRENTCOLOR = "currentcolor"; @@ -551,12 +462,6 @@ public class CssConstants { /** The Constant DOUBLE. */ public static final String DOUBLE = "double"; - /** The Constant FIRST. */ - public static final String FIRST = "first"; - - /** The Constant FIRST_EXCEPT. */ - public static final String FIRST_EXCEPT = "first-except"; - /** The Constant FIXED. */ public static final String FIXED = "fixed"; @@ -587,51 +492,27 @@ public class CssConstants { /** The Constant INITIAL. */ public static final String INITIAL = "initial"; - /** The Constant INLINE. */ - public static final String INLINE = "inline"; - - /** The Constant INLINE_BLOCK. */ - public static final String INLINE_BLOCK = "inline-block"; - - /** The Constant INLINE_TABLE. */ - public static final String INLINE_TABLE = "inline-table"; - /** The Constant INSET. */ public static final String INSET = "inset"; /** The Constant INSIDE. */ public static final String INSIDE = "inside"; - /** The Constant INVERT. */ - public static final String INVERT = "invert"; - /** The Constant ITALIC. */ public static final String ITALIC = "italic"; - /** The Constant JUSTIFY. */ - public static final String JUSTIFY = "justify"; - - /** The Constant LANDSCAPE. */ - public static final String LANDSCAPE = "landscape"; - /** The Constant LARGE. */ public static final String LARGE = "large"; /** The Constant LARGER. */ public static final String LARGER = "larger"; - /** The Constant LAST. */ - public static final String LAST = "last"; - /** The Constant LEFT. */ public static final String LEFT = "left"; /** The Constant LIGHTER. */ public static final String LIGHTER = "lighter"; - /** The Constant LINE_THROUGH. */ - public static final String LINE_THROUGH = "line-through"; - /** The Constant LOCAL. */ public static final String LOCAL = "local"; @@ -647,12 +528,6 @@ public class CssConstants { /** The Constant LOWER_ROMAN. */ public static final String LOWER_ROMAN = "lower-roman"; - /** The Constant LOWERCASE. */ - public static final String LOWERCASE = "lowercase"; - - /** The Constant LTR. */ - public static final String LTR = "ltr"; - /** The Constant MANUAL. */ public static final String MANUAL = "manual"; @@ -668,9 +543,6 @@ public class CssConstants { /** The Constant MESSAGE_BOX. */ public static final String MESSAGE_BOX = "message-box"; - /** The Constant MIDDLE. */ - public static final String MIDDLE = "middle"; - /** The Constant NO_OPEN_QUOTE. */ public static final String NO_OPEN_QUOTE = "no-open-quote"; @@ -686,9 +558,6 @@ public class CssConstants { /** The Constant NORMAL. */ public static final String NORMAL = "normal"; - /** The Constant NOWRAP. */ - public static final String NOWRAP = "nowrap"; - /** The Constant OBLIQUE. */ public static final String OBLIQUE = "oblique"; @@ -701,33 +570,9 @@ public class CssConstants { /** The Constant OUTSET. */ public static final String OUTSET = "outset"; - /** The Constant OVERLINE. */ - public static final String OVERLINE = "overline"; - /** The Constant PADDING_BOX. */ public static final String PADDING_BOX = "padding-box"; - /** The Constant PAGE. */ - public static final String PAGE = "page"; - - /** The Constant PAGES. */ - public static final String PAGES = "pages"; - - /** The Constant PORTRAIT. */ - public static final String PORTRAIT = "portrait"; - - /** The Constant PRE. */ - public static final String PRE = "pre"; - - /** The Constant PRE_LINE. */ - public static final String PRE_LINE = "pre-line"; - - /** The Constant PRE_WRAP. */ - public static final String PRE_WRAP = "pre-wrap"; - - /** The Constant RELATIVE. */ - public static final String RELATIVE = "relative"; - /** The Constant REPEAT. */ public static final String REPEAT = "repeat"; @@ -746,9 +591,6 @@ public class CssConstants { /** The Constant ROTATE. */ public static final String ROTATE = "rotate"; - /** The Constant RTL. */ - public static final String RTL = "rtl"; - /** The Constant SCALE. */ public static final String SCALE = "scale"; @@ -761,9 +603,6 @@ public class CssConstants { /** The Constant SCROLL. */ public static final String SCROLL = "scroll"; - /** The Constant SEPARATE. */ - public static final String SEPARATE = "separate"; - /** The Constant SKEW. */ public static final String SKEW = "skew"; @@ -800,27 +639,6 @@ public class CssConstants { /** The Constant STATUS_BAR. */ public static final String STATUS_BAR = "status-bar"; - /** The Constant SUB. */ - public static final String SUB = "sub"; - - /** The Constant SUPER. */ - public static final String SUPER = "super"; - - /** The Constant TABLE. */ - public static final String TABLE = "table"; - - /** The Constant TABLE_CELL. */ - public static final String TABLE_CELL = "table-cell"; - - /** The Constant TABLE_ROW. */ - public static final String TABLE_ROW = "table-row"; - - /** The Constant TEXT_BOTTOM. */ - public static final String TEXT_BOTTOM = "text-bottom"; - - /** The Constant TEXT_TOP. */ - public static final String TEXT_TOP = "text-top"; - /** The Constant THICK. */ public static final String THICK = "thick"; @@ -842,9 +660,6 @@ public class CssConstants { /** The Constant TRANSPARENT. */ public static final String TRANSPARENT = "transparent"; - /** The Constant UNDERLINE. */ - public static final String UNDERLINE = "underline"; - /** The Constant UPPER_ALPHA. */ public static final String UPPER_ALPHA = "upper-alpha"; @@ -854,9 +669,6 @@ public class CssConstants { /** The Constant UPPER_ROMAN. */ public static final String UPPER_ROMAN = "upper-roman"; - /** The Constant UPPERCASE. */ - public static final String UPPERCASE = "uppercase"; - /** The Constant X_LARGE. */ public static final String X_LARGE = "x-large"; @@ -899,34 +711,6 @@ public class CssConstants { public static final Set BORDER_STYLE_VALUES = Collections.unmodifiableSet(new HashSet<>( Arrays.asList(new String[] {NONE, HIDDEN, DOTTED, DASHED, SOLID, DOUBLE, GROOVE, RIDGE, INSET, OUTSET}))); - /** The Constant FONT_ABSOLUTE_SIZE_KEYWORDS. */ - public static final Set FONT_ABSOLUTE_SIZE_KEYWORDS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( - CssConstants.MEDIUM, CssConstants.XX_SMALL, CssConstants.X_SMALL, CssConstants.SMALL, CssConstants.LARGE, - CssConstants.X_LARGE, CssConstants.XX_LARGE - ))); - - /** The Constant OVERFLOW_VALUES. */ - public static final Set OVERFLOW_VALUES = new HashSet<>( - Arrays.asList(new String[] {VISIBLE, HIDDEN})); - - - // pseudo-elements - - /** The Constant AFTER. */ - public static final String AFTER = "after"; - - /** The Constant BEFORE. */ - public static final String BEFORE = "before"; - - /** The Constant FIRST_LETTER. */ - public static final String FIRST_LETTER = "first-letter"; - - /** The Constant FIRST_LINE. */ - public static final String FIRST_LINE = "first-line"; - - /** The Constant SELECTION. */ - public static final String SELECTION = "selection"; - // pseudo-classes /** The Constant ACTIVE. */ @@ -1022,20 +806,6 @@ public class CssConstants { /** The Constant VISITED. */ public static final String VISITED = "visited"; - // Functions - - /** The Constant COUNTER. */ - public static final String COUNTER = "counter"; - - /** The Constant COUNTERS. */ - public static final String COUNTERS = "counters"; - - /** The Constant RUNNING. */ - public static final String ELEMENT = "element"; - - /** The Constant RUNNING. */ - public static final String RUNNING = "running"; - // units of measurement /** The Constant CM. */ @@ -1073,9 +843,6 @@ public class CssConstants { // units of resolution - /** The Constant DPI. */ - public static final String DPI = "dpi"; - /** The Constant DPCM. */ public static final String DPCM = "dpcm"; diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/CssContextNode.java b/src/main/java/com/itextpdf/styledxmlparser/css/CssContextNode.java new file mode 100644 index 0000000000..f00b7bbaa4 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/CssContextNode.java @@ -0,0 +1,117 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css; + + +import com.itextpdf.styledxmlparser.node.INode; +import com.itextpdf.styledxmlparser.node.IStylesContainer; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * The CSS context node. + */ +public abstract class CssContextNode implements INode, IStylesContainer { + + /** The child nodes. */ + private List childNodes = new ArrayList<>(); + + /** The parent node. */ + private INode parentNode; + + /** The styles. */ + private Map styles; + + /** + * Creates a new {@link CssContextNode} instance. + * + * @param parentNode the parent node + */ + public CssContextNode(INode parentNode) { + this.parentNode = parentNode; + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.html.node.INode#childNodes() + */ + @Override + public List childNodes() { + return Collections.unmodifiableList(childNodes); + } + + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.html.node.INode#addChild(com.itextpdf.styledxmlparser.html.node.INode) + */ + @Override + public void addChild(INode node) { + childNodes.add(node); + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.html.node.INode#parentNode() + */ + @Override + public INode parentNode() { + return parentNode; + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.html.node.IStylesContainer#setStyles(java.util.Map) + */ + @Override + public void setStyles(Map stringStringMap) { + this.styles = stringStringMap; + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.html.node.IStylesContainer#getStyles() + */ + @Override + public Map getStyles() { + return this.styles; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/CssFontFaceRule.java b/src/main/java/com/itextpdf/styledxmlparser/css/CssFontFaceRule.java index 1225a0b76b..7ba44954d7 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/CssFontFaceRule.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/CssFontFaceRule.java @@ -76,7 +76,7 @@ public List getProperties() { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.CssNestedAtRule#addBodyCssDeclarations(java.util.List) + * @see com.itextpdf.styledxmlparser.css.CssNestedAtRule#addBodyCssDeclarations(java.util.List) */ @Override public void addBodyCssDeclarations(List cssDeclarations) { @@ -84,7 +84,7 @@ public void addBodyCssDeclarations(List cssDeclarations) { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.CssNestedAtRule#toString() + * @see com.itextpdf.styledxmlparser.css.CssNestedAtRule#toString() */ @Override public String toString() { diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/CssNestedAtRule.java b/src/main/java/com/itextpdf/styledxmlparser/css/CssNestedAtRule.java index cb27b21ad7..91739af205 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/CssNestedAtRule.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/CssNestedAtRule.java @@ -103,7 +103,7 @@ public void addBodyCssDeclarations(List cssDeclarations) { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.CssStatement#getCssRuleSets(com.itextpdf.html2pdf.html.node.INode, com.itextpdf.html2pdf.css.media.MediaDeviceDescription) + * @see com.itextpdf.styledxmlparser.css.CssStatement#getCssRuleSets(com.itextpdf.styledxmlparser.html.node.INode, com.itextpdf.styledxmlparser.css.media.MediaDeviceDescription) */ @Override public List getCssRuleSets(INode node, MediaDeviceDescription deviceDescription) { diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/CssNestedAtRuleFactory.java b/src/main/java/com/itextpdf/styledxmlparser/css/CssNestedAtRuleFactory.java index a9d20c4811..7cb83a1fa5 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/CssNestedAtRuleFactory.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/CssNestedAtRuleFactory.java @@ -44,6 +44,8 @@ This file is part of the iText (R) project. import com.itextpdf.styledxmlparser.css.media.CssMediaRule; +import com.itextpdf.styledxmlparser.css.page.CssMarginRule; +import com.itextpdf.styledxmlparser.css.page.CssPageRule; /** * A factory for creating {@link CssNestedAtRule} objects. @@ -71,7 +73,7 @@ public static CssNestedAtRule createNestedRule(String ruleDeclaration) { case CssRuleName.MEDIA: return new CssMediaRule(ruleParameters); case CssRuleName.PAGE: - //return new CssPageRule(ruleParameters); + return new CssPageRule(ruleParameters); case CssRuleName.TOP_LEFT_CORNER: case CssRuleName.TOP_LEFT: case CssRuleName.TOP_CENTER: @@ -88,7 +90,7 @@ public static CssNestedAtRule createNestedRule(String ruleDeclaration) { case CssRuleName.BOTTOM_CENTER: case CssRuleName.BOTTOM_RIGHT: case CssRuleName.BOTTOM_RIGHT_CORNER: - //return new CssMarginRule(ruleName, ruleParameters); + return new CssMarginRule(ruleName, ruleParameters); case CssRuleName.FONT_FACE: return new CssFontFaceRule(ruleParameters); default: diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/CssRuleSet.java b/src/main/java/com/itextpdf/styledxmlparser/css/CssRuleSet.java index cfdfdfdc88..c49325dc99 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/CssRuleSet.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/CssRuleSet.java @@ -91,7 +91,7 @@ public CssRuleSet(ICssSelector selector, List normalDeclarations } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.CssStatement#getCssRuleSets(com.itextpdf.html2pdf.html.node.INode, com.itextpdf.html2pdf.css.media.MediaDeviceDescription) + * @see com.itextpdf.styledxmlparser.css.CssStatement#getCssRuleSets(com.itextpdf.styledxmlparser.html.node.INode, com.itextpdf.styledxmlparser.css.media.MediaDeviceDescription) */ @Override public List getCssRuleSets(INode element, MediaDeviceDescription deviceDescription) { diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/CssRuleSetComparator.java b/src/main/java/com/itextpdf/styledxmlparser/css/CssRuleSetComparator.java new file mode 100644 index 0000000000..cc734987e0 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/CssRuleSetComparator.java @@ -0,0 +1,64 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css; + +import com.itextpdf.styledxmlparser.css.selector.CssSelectorComparator; + +import java.util.Comparator; + +/** + * Comparator class used to sort CSS rule set objects. + */ +public class CssRuleSetComparator implements Comparator { + + /** The selector comparator. */ + private CssSelectorComparator selectorComparator = new CssSelectorComparator(); + + /* (non-Javadoc) + * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) + */ + @Override + public int compare(CssRuleSet o1, CssRuleSet o2) { + return selectorComparator.compare(o1.getSelector(), o2.getSelector()); + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/ICssResolver.java b/src/main/java/com/itextpdf/styledxmlparser/css/ICssResolver.java index 32e235c24c..d9f204fd96 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/ICssResolver.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/ICssResolver.java @@ -43,6 +43,7 @@ This file is part of the iText (R) project. package com.itextpdf.styledxmlparser.css; +import com.itextpdf.styledxmlparser.css.resolve.AbstractCssContext; import com.itextpdf.styledxmlparser.node.INode; import com.itextpdf.styledxmlparser.resolver.resource.ResourceResolver; @@ -58,8 +59,9 @@ public interface ICssResolver { * * @param rootNode tree from which to collect CSS * @param resourceResolver ResourceResolver used to resolve resources + * @param context the CSS context (RootFontSize, etc.) */ - void collectCssDeclarations(INode rootNode, ResourceResolver resourceResolver); + void collectCssDeclarations(INode rootNode, ResourceResolver resourceResolver, AbstractCssContext context); /** * Resolves the styles of a node given the passed context. @@ -68,6 +70,6 @@ public interface ICssResolver { * @param context the CSS context (RootFontSize, etc.) * @return the map containing the resolved styles */ - Map resolveStyles(INode node, ICssContext context); + Map resolveStyles(INode node, AbstractCssContext context); } diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/media/CssMediaRule.java b/src/main/java/com/itextpdf/styledxmlparser/css/media/CssMediaRule.java index ac5fbfd09e..1732895ec2 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/media/CssMediaRule.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/media/CssMediaRule.java @@ -70,7 +70,7 @@ public CssMediaRule(String ruleParameters) { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.CssNestedAtRule#getCssRuleSets(com.itextpdf.html2pdf.html.node.INode, com.itextpdf.html2pdf.css.media.MediaDeviceDescription) + * @see com.itextpdf.styledxmlparser.css.CssNestedAtRule#getCssRuleSets(com.itextpdf.styledxmlparser.html.node.INode, com.itextpdf.styledxmlparser.css.media.MediaDeviceDescription) */ @Override public List getCssRuleSets(INode element, MediaDeviceDescription deviceDescription) { diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/page/CssMarginRule.java b/src/main/java/com/itextpdf/styledxmlparser/css/page/CssMarginRule.java new file mode 100644 index 0000000000..223bee62fd --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/page/CssMarginRule.java @@ -0,0 +1,89 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.page; + +import com.itextpdf.styledxmlparser.css.CssDeclaration; +import com.itextpdf.styledxmlparser.css.CssNestedAtRule; +import com.itextpdf.styledxmlparser.css.selector.CssPageMarginBoxSelector; +import com.itextpdf.styledxmlparser.css.selector.ICssSelector; + +import java.util.List; + +/** + * {@link CssNestedAtRule} implementation for margins. + */ +public class CssMarginRule extends CssNestedAtRule { + + /** The page selectors. */ + private List pageSelectors; + + /** + * Creates a new {@link CssMarginRule} instance. + * + * @param ruleName the rule name + * @param ruleParameters the rule parameters + */ + public CssMarginRule(String ruleName, String ruleParameters) { + super(ruleName, ruleParameters); + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.CssNestedAtRule#addBodyCssDeclarations(java.util.List) + */ + @Override + public void addBodyCssDeclarations(List cssDeclarations) { + for (ICssSelector pageSelector : pageSelectors) { + this.body.add(new CssNonStandardRuleSet(new CssPageMarginBoxSelector(getRuleName(), pageSelector), cssDeclarations)); + } + } + + /** + * Sets the page selectors. + * + * @param pageSelectors the new page selectors + */ + void setPageSelectors(List pageSelectors) { + this.pageSelectors = pageSelectors; + } + +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/page/CssNonStandardRuleSet.java b/src/main/java/com/itextpdf/styledxmlparser/css/page/CssNonStandardRuleSet.java new file mode 100644 index 0000000000..2d5f9295c2 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/page/CssNonStandardRuleSet.java @@ -0,0 +1,88 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.page; + +import com.itextpdf.styledxmlparser.css.CssDeclaration; +import com.itextpdf.styledxmlparser.css.CssRuleSet; +import com.itextpdf.styledxmlparser.css.selector.ICssSelector; + +import java.util.List; + +/** + * Class for a non standard {@link CssRuleSet}. + */ +class CssNonStandardRuleSet extends CssRuleSet { + + /** + * Creates a new {@link CssNonStandardRuleSet} instance. + * + * @param selector the selector + * @param declarations the declarations + */ + public CssNonStandardRuleSet(ICssSelector selector, List declarations) { + super(selector, declarations); + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.CssRuleSet#toString() + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < getNormalDeclarations().size(); i++) { + if (i > 0) { + sb.append(";").append("\n"); + } + CssDeclaration declaration = getNormalDeclarations().get(i); + sb.append(declaration.toString()); + } + for (int i = 0; i < getImportantDeclarations().size(); i++) { + if (i > 0 || getNormalDeclarations().size() > 0) { + sb.append(";").append("\n"); + } + CssDeclaration declaration = getImportantDeclarations().get(i); + sb.append(declaration.toString()).append(" !important"); + } + return sb.toString(); + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/page/CssPageRule.java b/src/main/java/com/itextpdf/styledxmlparser/css/page/CssPageRule.java new file mode 100644 index 0000000000..bd10784a35 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/page/CssPageRule.java @@ -0,0 +1,125 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.page; + +import com.itextpdf.styledxmlparser.css.CssDeclaration; +import com.itextpdf.styledxmlparser.css.CssNestedAtRule; +import com.itextpdf.styledxmlparser.css.CssRuleName; +import com.itextpdf.styledxmlparser.css.CssStatement; +import com.itextpdf.styledxmlparser.css.selector.CssPageSelector; +import com.itextpdf.styledxmlparser.css.selector.ICssSelector; +import com.itextpdf.styledxmlparser.css.util.CssUtils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * {@link CssNestedAtRule} implementation for page rules. + */ +public class CssPageRule extends CssNestedAtRule { + + /** The page selectors. */ + private List pageSelectors; + + /** + * Creates a new {@link CssPageRule} instance. + * + * @param ruleParameters the rule parameters + */ + public CssPageRule(String ruleParameters) { + super(CssRuleName.PAGE, ruleParameters); + pageSelectors = new ArrayList<>(); + + String[] selectors = ruleParameters.split(","); + for (int i = 0; i < selectors.length; i++) { + selectors[i] = CssUtils.removeDoubleSpacesAndTrim(selectors[i]); + } + for (String currentSelectorStr : selectors) { + pageSelectors.add(new CssPageSelector(currentSelectorStr)); + } + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.CssNestedAtRule#addBodyCssDeclarations(java.util.List) + */ + @Override + public void addBodyCssDeclarations(List cssDeclarations) { + // TODO Due to this for-loop, on toString method call for the CssPageRule instance + // all the body declarations will be duplicated for each pageSelector part. + // This potentially could lead to a nasty behaviour when declarations will double + // for each read-write iteration of the same css-file (however, this use case seems + // to be unlikely to happen). + // Possible solution would be to split single page rule with compound selector into + // several page rules with simple selectors on addition of the page rule to it's parent. + // + // Also, the same concerns this method implementation in CssMarginRule class. + // + // See CssStyleSheetParserTest#test11 test. + for (ICssSelector pageSelector : pageSelectors) { + this.body.add(new CssNonStandardRuleSet(pageSelector, cssDeclarations)); + } + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.CssNestedAtRule#addStatementToBody(com.itextpdf.styledxmlparser.css.CssStatement) + */ + @Override + public void addStatementToBody(CssStatement statement) { + if (statement instanceof CssMarginRule) { + ((CssMarginRule) statement).setPageSelectors(pageSelectors); + } + this.body.add(statement); + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.CssNestedAtRule#addStatementsToBody(java.util.Collection) + */ + @Override + public void addStatementsToBody(Collection statements) { + for (CssStatement statement : statements) { + addStatementToBody(statement); + } + } + +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/ICssContext.java b/src/main/java/com/itextpdf/styledxmlparser/css/page/PageContextConstants.java similarity index 77% rename from src/main/java/com/itextpdf/styledxmlparser/css/ICssContext.java rename to src/main/java/com/itextpdf/styledxmlparser/css/page/PageContextConstants.java index 7cf980e5a8..9a4c92edc6 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/ICssContext.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/page/PageContextConstants.java @@ -1,8 +1,8 @@ /* This file is part of the iText (R) project. - Copyright (c) 1998-2018 iText Group NV - Authors: iText Software. - + Copyright (c) 1998-2017 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 @@ -10,7 +10,7 @@ This file is part of the iText (R) project. 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. @@ -20,15 +20,15 @@ This file is part of the iText (R) project. 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 @@ -36,14 +36,26 @@ This file is part of the iText (R) project. 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.styledxmlparser.css; +package com.itextpdf.styledxmlparser.css.page; /** - * Interface for the CSS context used by a {@link ICssResolver} + * Class that bundles a series of page context constants. */ -public interface ICssContext { +public class PageContextConstants { + + /** The Constant BLANK. */ + public static final String BLANK = "blank"; + + /** The Constant FIRST. */ + public static final String FIRST = "first"; + + /** The Constant LEFT. */ + public static final String LEFT = "left"; + + /** The Constant RIGHT. */ + public static final String RIGHT = "right"; } diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/page/PageContextNode.java b/src/main/java/com/itextpdf/styledxmlparser/css/page/PageContextNode.java new file mode 100644 index 0000000000..bca56f1eaa --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/page/PageContextNode.java @@ -0,0 +1,119 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.page; + +import com.itextpdf.styledxmlparser.css.CssContextNode; +import com.itextpdf.styledxmlparser.node.INode; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * {@link CssContextNode} implementation for page contexts. + */ +public class PageContextNode extends CssContextNode { + + /** The page type name. */ + private String pageTypeName; + + /** The page classes. */ + private List pageClasses; + + /** + * Creates a new {@link PageContextNode} instance. + */ + public PageContextNode() { + this(null); + } + + /** + * Creates a new {@link PageContextNode} instance. + * + * @param parentNode the parent node + */ + public PageContextNode(INode parentNode) { + super(parentNode); + this.pageClasses = new ArrayList<>(); + } + + /** + * Adds a page class. + * + * @param pageClass the page class + * @return the page context node + */ + public PageContextNode addPageClass(String pageClass) { + this.pageClasses.add(pageClass.toLowerCase()); + return this; + } + + /** + * Gets the page type name. + * + * @return the page type name + */ + public String getPageTypeName() { + return this.pageTypeName; + } + + /** + * Sets the page type name. + * + * @param pageTypeName the page type name + * @return the page context node + */ + public PageContextNode setPageTypeName(String pageTypeName) { + this.pageTypeName = pageTypeName; + return this; + } + + /** + * Gets the list of page classes. + * + * @return the page classes + */ + public List getPageClasses() { + return Collections.unmodifiableList(pageClasses); + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/page/PageMarginBoxContextNode.java b/src/main/java/com/itextpdf/styledxmlparser/css/page/PageMarginBoxContextNode.java new file mode 100644 index 0000000000..b460da8009 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/page/PageMarginBoxContextNode.java @@ -0,0 +1,119 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.page; + +import com.itextpdf.kernel.geom.Rectangle; +import com.itextpdf.styledxmlparser.css.CssContextNode; +import com.itextpdf.styledxmlparser.node.INode; + +/** + * {@link CssContextNode} implementation for page margin box contexts. + */ +public class PageMarginBoxContextNode extends CssContextNode { + + /** The Constant PAGE_MARGIN_BOX_TAG. */ + public static final String PAGE_MARGIN_BOX_TAG = "_064ef03_page-margin-box"; + + /** The margin box name. */ + private String marginBoxName; + + private Rectangle pageMarginBoxRectangle; + private Rectangle containingBlockForMarginBox; + + /** + * Creates a new {@link PageMarginBoxContextNode} instance. + * + * @param parentNode the parent node + * @param marginBoxName the margin box name + */ + public PageMarginBoxContextNode(INode parentNode, String marginBoxName) { + super(parentNode); + this.marginBoxName = marginBoxName; + if (!(parentNode instanceof PageContextNode)) { + throw new IllegalArgumentException("Page-margin-box context node shall have a page context node as parent."); + } + } + + /** + * Gets the margin box name. + * + * @return the margin box name + */ + public String getMarginBoxName() { + return marginBoxName; + } + + /** + * Sets the rectangle in which page margin box contents are shown. + * @param pageMarginBoxRectangle the {@link Rectangle} defining position and dimensions of the margin box content area + */ + public void setPageMarginBoxRectangle(Rectangle pageMarginBoxRectangle) { + this.pageMarginBoxRectangle = pageMarginBoxRectangle; + } + + /** + * Gets the rectangle in which page margin box contents should be shown. + * @return the {@link Rectangle} defining position and dimensions of the margin box content area + */ + public Rectangle getPageMarginBoxRectangle() { + return pageMarginBoxRectangle; + } + + /** + * Sets the containing block rectangle for the margin box, which is used for calculating + * some of the margin box properties relative values. + * @param containingBlockForMarginBox the {@link Rectangle} which is used as a reference for some + * margin box relative properties calculations. + */ + public void setContainingBlockForMarginBox(Rectangle containingBlockForMarginBox) { + this.containingBlockForMarginBox = containingBlockForMarginBox; + } + + /** + * @return the {@link Rectangle} which is used as a reference for some + * margin box relative properties calculations. + */ + public Rectangle getContainingBlockForMarginBox() { + return containingBlockForMarginBox; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/page/package-info.java b/src/main/java/com/itextpdf/styledxmlparser/css/page/package-info.java new file mode 100644 index 0000000000..df9f9a947b --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/page/package-info.java @@ -0,0 +1 @@ +package com.itextpdf.styledxmlparser.css.page; \ No newline at end of file diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/parse/CssPageSelectorParser.java b/src/main/java/com/itextpdf/styledxmlparser/css/parse/CssPageSelectorParser.java new file mode 100644 index 0000000000..4e5d347a58 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/parse/CssPageSelectorParser.java @@ -0,0 +1,85 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.parse; + +import com.itextpdf.styledxmlparser.css.selector.item.CssPagePseudoClassSelectorItem; +import com.itextpdf.styledxmlparser.css.selector.item.CssPageTypeSelectorItem; +import com.itextpdf.styledxmlparser.css.selector.item.ICssSelectorItem; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Utilities class to parse CSS page selectors. + */ +public final class CssPageSelectorParser { + + /** The pattern string for page selectors. */ + private static final String PAGE_SELECTOR_PATTERN_STR = + "(^-?[_a-zA-Z][\\w-]*)|(:(?i)(left|right|first|blank))"; + + /** The pattern for page selectors. */ + private static final Pattern selectorPattern = Pattern.compile(PAGE_SELECTOR_PATTERN_STR); + + /** + * Parses the selector items into a list of {@link ICssSelectorItem} instances. + * + * @param selectorItemsStr the selector items in the form of a {@link String} + * @return the resulting list of {@link ICssSelectorItem} instances + */ + public static List parseSelectorItems(String selectorItemsStr) { + List selectorItems = new ArrayList<>(); + Matcher itemMatcher = selectorPattern.matcher(selectorItemsStr); + while (itemMatcher.find()) { + String selectorItem = itemMatcher.group(0); + if (selectorItem.charAt(0) == ':') { + selectorItems.add(new CssPagePseudoClassSelectorItem(selectorItem.substring(1).toLowerCase())); + } else { + selectorItems.add(new CssPageTypeSelectorItem(selectorItem)); + } + } + return selectorItems; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/parse/CssSelectorParser.java b/src/main/java/com/itextpdf/styledxmlparser/css/parse/CssSelectorParser.java index a16de357d2..943fa28853 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/parse/CssSelectorParser.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/parse/CssSelectorParser.java @@ -1,6 +1,6 @@ /* This file is part of the iText (R) project. - Copyright (c) 1998-2018 iText Group NV + Copyright (c) 1998-2017 iText Group NV Authors: Bruno Lowagie, Paulo Soares, et al. This program is free software; you can redistribute it and/or modify @@ -43,9 +43,12 @@ This file is part of the iText (R) project. package com.itextpdf.styledxmlparser.css.parse; import com.itextpdf.io.util.MessageFormatUtil; +import com.itextpdf.styledxmlparser.LogMessageConstant; import com.itextpdf.styledxmlparser.css.selector.item.CssAttributeSelectorItem; import com.itextpdf.styledxmlparser.css.selector.item.CssClassSelectorItem; import com.itextpdf.styledxmlparser.css.selector.item.CssIdSelectorItem; +import com.itextpdf.styledxmlparser.css.selector.item.CssPseudoElementSelectorItem; +import com.itextpdf.styledxmlparser.css.selector.item.CssPseudoClassSelectorItem; import com.itextpdf.styledxmlparser.css.selector.item.CssSeparatorSelectorItem; import com.itextpdf.styledxmlparser.css.selector.item.CssTagSelectorItem; import com.itextpdf.styledxmlparser.css.selector.item.ICssSelectorItem; @@ -66,7 +69,6 @@ public final class CssSelectorParser { * Set of legacy pseudo elements (first-line, first-letter, before, after). */ private static final Set legacyPseudoElements = new HashSet<>(); - static { legacyPseudoElements.add("first-line"); legacyPseudoElements.add("first-letter"); @@ -118,8 +120,7 @@ public static List parseSelectorItems(String selector) { selectorItems.add(new CssAttributeSelectorItem(selectorItem)); break; case ':': - //TODO (RND-866): Consider pseudo-elements in SVG - //appendPseudoSelector(selectorItems, selectorItem, match); + appendPseudoSelector(selectorItems, selectorItem, match); break; case ' ': case '+': @@ -161,4 +162,57 @@ public static List parseSelectorItems(String selector) { return selectorItems; } + + /** + * Resolves a pseudo selector, appends it to list and updates {@link CssSelectorParserMatch} in process. + * + * @param selectorItems list of items to which new selector will be added to + * @param pseudoSelector the pseudo selector + * @param match the corresponding {@link CssSelectorParserMatch} that will be updated. + */ + private static void appendPseudoSelector(List selectorItems, String pseudoSelector, CssSelectorParserMatch match) { + pseudoSelector = pseudoSelector.toLowerCase(); + int start = match.getIndex() + pseudoSelector.length(); + String source = match.getSource(); + if (start < source.length() && source.charAt(start) == '(') { + int bracketDepth = 1; + int curr = start + 1; + while(bracketDepth > 0 && curr < source.length()) { + if (source.charAt(curr) == '(') { + ++bracketDepth; + } else if (source.charAt(curr) == ')') { + --bracketDepth; + } else if (source.charAt(curr) == '"' || source.charAt(curr) == '\'') { + curr = CssUtils.findNextUnescapedChar(source, source.charAt(curr), curr + 1); + } + ++curr; + } + if (bracketDepth == 0) { + match.next(curr); + pseudoSelector += source.substring(start, curr); + } else { + match.next(); + } + } else { + match.next(); + } + /* + This :: notation is introduced by the current document in order to establish a discrimination between + pseudo-classes and pseudo-elements. + For compatibility with existing style sheets, user agents must also accept the previous one-colon + notation for pseudo-elements introduced in CSS levels 1 and 2 (namely, :first-line, :first-letter, :before and :after). + This compatibility is not allowed for the new pseudo-elements introduced in this specification. + */ + if (pseudoSelector.startsWith("::")) { + selectorItems.add(new CssPseudoElementSelectorItem(pseudoSelector.substring(2))); + } else if (pseudoSelector.startsWith(":") && legacyPseudoElements.contains(pseudoSelector.substring(1))) { + selectorItems.add(new CssPseudoElementSelectorItem(pseudoSelector.substring(1))); + } else { + ICssSelectorItem pseudoClassSelectorItem = CssPseudoClassSelectorItem.create(pseudoSelector.substring(1)); + if (pseudoClassSelectorItem == null) { + throw new IllegalArgumentException(MessageFormatUtil.format(LogMessageConstant.UNSUPPORTED_PSEUDO_CSS_SELECTOR, pseudoSelector)); + } + selectorItems.add(pseudoClassSelectorItem); + } + } } diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/AtRuleBlockState.java b/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/AtRuleBlockState.java index c6e2dcd93f..b427ae6613 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/AtRuleBlockState.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/AtRuleBlockState.java @@ -62,7 +62,7 @@ class AtRuleBlockState implements IParserState { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.parse.syntax.IParserState#process(char) + * @see com.itextpdf.styledxmlparser.css.parse.syntax.IParserState#process(char) */ @Override public void process(char ch) { diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/CommentEndState.java b/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/CommentEndState.java index 5c76b68606..7d1efbc29e 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/CommentEndState.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/CommentEndState.java @@ -62,7 +62,7 @@ class CommentEndState implements IParserState { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.parse.syntax.IParserState#process(char) + * @see com.itextpdf.styledxmlparser.css.parse.syntax.IParserState#process(char) */ @Override public void process(char ch) { diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/CommentInnerState.java b/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/CommentInnerState.java index 33a16b868b..41bd77382d 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/CommentInnerState.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/CommentInnerState.java @@ -62,7 +62,7 @@ class CommentInnerState implements IParserState { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.parse.syntax.IParserState#process(char) + * @see com.itextpdf.styledxmlparser.css.parse.syntax.IParserState#process(char) */ @Override public void process(char ch) { diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/CommentStartState.java b/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/CommentStartState.java index 52f7090ec5..c73082cbb0 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/CommentStartState.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/CommentStartState.java @@ -62,7 +62,7 @@ class CommentStartState implements IParserState { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.parse.syntax.IParserState#process(char) + * @see com.itextpdf.styledxmlparser.css.parse.syntax.IParserState#process(char) */ @Override public void process(char ch) { diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/ConditionalGroupAtRuleBlockState.java b/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/ConditionalGroupAtRuleBlockState.java index 8114bd8200..e7c79d73d1 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/ConditionalGroupAtRuleBlockState.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/ConditionalGroupAtRuleBlockState.java @@ -62,7 +62,7 @@ class ConditionalGroupAtRuleBlockState implements IParserState { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.parse.syntax.IParserState#process(char) + * @see com.itextpdf.styledxmlparser.css.parse.syntax.IParserState#process(char) */ @Override // TODO use UnknownState? diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/PropertiesState.java b/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/PropertiesState.java index c43d1c2756..cd2e81eb86 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/PropertiesState.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/PropertiesState.java @@ -63,7 +63,7 @@ class PropertiesState implements IParserState { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.parse.syntax.IParserState#process(char) + * @see com.itextpdf.styledxmlparser.css.parse.syntax.IParserState#process(char) */ @Override public void process(char ch) { diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/RuleState.java b/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/RuleState.java index 50f8c6e796..0e02d73a00 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/RuleState.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/RuleState.java @@ -62,7 +62,7 @@ class RuleState implements IParserState { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.parse.syntax.IParserState#process(char) + * @see com.itextpdf.styledxmlparser.css.parse.syntax.IParserState#process(char) */ @Override public void process(char ch) { diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/UnknownState.java b/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/UnknownState.java index ee1433ac85..87cce72be2 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/UnknownState.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/parse/syntax/UnknownState.java @@ -62,7 +62,7 @@ class UnknownState implements IParserState { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.parse.syntax.IParserState#process(char) + * @see com.itextpdf.styledxmlparser.css.parse.syntax.IParserState#process(char) */ @Override public void process(char ch) { diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/pseudo/CssPseudoElementNode.java b/src/main/java/com/itextpdf/styledxmlparser/css/pseudo/CssPseudoElementNode.java new file mode 100644 index 0000000000..5af16ea488 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/pseudo/CssPseudoElementNode.java @@ -0,0 +1,177 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.pseudo; + + + +import com.itextpdf.styledxmlparser.css.CssContextNode; +import com.itextpdf.styledxmlparser.node.IAttribute; +import com.itextpdf.styledxmlparser.node.IAttributes; +import com.itextpdf.styledxmlparser.node.ICustomElementNode; +import com.itextpdf.styledxmlparser.node.IElementNode; +import com.itextpdf.styledxmlparser.node.INode; + +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * {@link IElementNode} implementation for pseudo elements. + */ +public class CssPseudoElementNode extends CssContextNode implements IElementNode, ICustomElementNode { + + /** The pseudo element name. */ + private String pseudoElementName; + + /** The pseudo element tag name. */ + private String pseudoElementTagName; + + /** + * Creates a new {@link CssPseudoElementNode} instance. + * + * @param parentNode the parent node + * @param pseudoElementName the pseudo element name + */ + public CssPseudoElementNode(INode parentNode, String pseudoElementName) { + super(parentNode); + this.pseudoElementName = pseudoElementName; + this.pseudoElementTagName = CssPseudoElementUtil.createPseudoElementTagName(pseudoElementName); + } + + /** + * Gets the pseudo element name. + * + * @return the pseudo element name + */ + public String getPseudoElementName() { + return pseudoElementName; + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.html.node.IElementNode#name() + */ + @Override + public String name() { + return pseudoElementTagName; + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.html.node.IElementNode#getAttributes() + */ + @Override + public IAttributes getAttributes() { + return new AttributesStub(); + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.html.node.IElementNode#getAttribute(java.lang.String) + */ + @Override + public String getAttribute(String key) { + return null; + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.html.node.IElementNode#getAdditionalHtmlStyles() + */ + @Override + public List> getAdditionalHtmlStyles() { + return null; + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.html.node.IElementNode#addAdditionalHtmlStyles(java.util.Map) + */ + @Override + public void addAdditionalHtmlStyles(Map styles) { + throw new UnsupportedOperationException(); + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.html.node.IElementNode#getLang() + */ + @Override + public String getLang() { + return null; + } + + /** + * A simple {@link IAttributes} implementation. + */ + private static class AttributesStub implements IAttributes { + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.html.node.IAttributes#getAttribute(java.lang.String) + */ + @Override + public String getAttribute(String key) { + return null; + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.html.node.IAttributes#setAttribute(java.lang.String, java.lang.String) + */ + @Override + public void setAttribute(String key, String value) { + throw new UnsupportedOperationException(); + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.html.node.IAttributes#size() + */ + @Override + public int size() { + return 0; + } + + /* (non-Javadoc) + * @see java.lang.Iterable#iterator() + */ + @Override + public Iterator iterator() { + return Collections.emptyIterator(); + } + } +} + diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/pseudo/CssPseudoElementUtil.java b/src/main/java/com/itextpdf/styledxmlparser/css/pseudo/CssPseudoElementUtil.java new file mode 100644 index 0000000000..461687d01e --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/pseudo/CssPseudoElementUtil.java @@ -0,0 +1,80 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.pseudo; + + +import com.itextpdf.styledxmlparser.node.IElementNode; + +/** + * Utilities class for pseudo elements. + */ +public class CssPseudoElementUtil { + + /** + * The prefix for pseudo elements. + */ + private static final String TAG_NAME_PREFIX = "pseudo-element::"; + + /** + * Creates the pseudo element tag name. + * + * @param pseudoElementName the pseudo element name + * @return the tag name + */ + public static String createPseudoElementTagName(String pseudoElementName) { + return TAG_NAME_PREFIX + pseudoElementName; + } + + /** + * Checks for before or after elements. + * + * @param node the node + * @return true, if successful + */ + public static boolean hasBeforeAfterElements(IElementNode node) { + if (node == null || node instanceof CssPseudoElementNode || node.name().startsWith(TAG_NAME_PREFIX)) { + return false; + } + return true; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/pseudo/package-info.java b/src/main/java/com/itextpdf/styledxmlparser/css/pseudo/package-info.java new file mode 100644 index 0000000000..163281ef16 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/pseudo/package-info.java @@ -0,0 +1 @@ +package com.itextpdf.styledxmlparser.css.pseudo; \ No newline at end of file diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/AbstractCssContext.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/AbstractCssContext.java new file mode 100644 index 0000000000..9185d497f0 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/AbstractCssContext.java @@ -0,0 +1,75 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2018 iText Group NV + Authors: iText Software. + + 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.styledxmlparser.css.resolve; + +import com.itextpdf.styledxmlparser.css.ICssResolver; + +/** + * Container for CSS context properties that influence CSS resolution. + * This class only contains properties relevant for any generic XML+CSS combo: + * specific properties must be implemented in a project-specific subclass. + * Used by {@link ICssResolver}. + */ +public abstract class AbstractCssContext { + + /** The quotes depth. */ + private int quotesDepth = 0; + + /** + * Gets the quotes depth. + * + * @return the quotes depth + */ + public int getQuotesDepth() { + return quotesDepth; + } + + /** + * Sets the quotes depth. + * + * @param quotesDepth the new quotes depth + */ + public void setQuotesDepth(int quotesDepth) { + this.quotesDepth = quotesDepth; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssDefaults.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssDefaults.java new file mode 100644 index 0000000000..3aa333544e --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssDefaults.java @@ -0,0 +1,162 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.resolve; + + +import com.itextpdf.styledxmlparser.LogMessageConstant; +import com.itextpdf.styledxmlparser.css.CommonCssConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.itextpdf.io.util.MessageFormatUtil; +import java.util.HashMap; +import java.util.Map; + +/** + * Helper class that allows you to get the default values of CSS properties. + */ +public class CssDefaults { + + /** A map with properties and their default values. */ + private static final Map defaultValues = new HashMap<>(); + + static { + defaultValues.put(CommonCssConstants.COLOR, "black"); // not specified, varies from browser to browser + defaultValues.put(CommonCssConstants.OPACITY, "1"); + + defaultValues.put(CommonCssConstants.BACKGROUND_ATTACHMENT, CommonCssConstants.SCROLL); + defaultValues.put(CommonCssConstants.BACKGROUND_BLEND_MODE, CommonCssConstants.NORMAL); + defaultValues.put(CommonCssConstants.BACKGROUND_COLOR, CommonCssConstants.TRANSPARENT); + defaultValues.put(CommonCssConstants.BACKGROUND_IMAGE, CommonCssConstants.NONE); + defaultValues.put(CommonCssConstants.BACKGROUND_POSITION, "0% 0%"); + defaultValues.put(CommonCssConstants.BACKGROUND_REPEAT, CommonCssConstants.REPEAT); + defaultValues.put(CommonCssConstants.BACKGROUND_CLIP, CommonCssConstants.BORDER_BOX); + defaultValues.put(CommonCssConstants.BACKGROUND_ORIGIN, CommonCssConstants.PADDING_BOX); + defaultValues.put(CommonCssConstants.BACKGROUND_SIZE, CommonCssConstants.AUTO); + + defaultValues.put(CommonCssConstants.BORDER_BOTTOM_COLOR, CommonCssConstants.CURRENTCOLOR); + defaultValues.put(CommonCssConstants.BORDER_LEFT_COLOR, CommonCssConstants.CURRENTCOLOR); + defaultValues.put(CommonCssConstants.BORDER_RIGHT_COLOR, CommonCssConstants.CURRENTCOLOR); + defaultValues.put(CommonCssConstants.BORDER_TOP_COLOR, CommonCssConstants.CURRENTCOLOR); + defaultValues.put(CommonCssConstants.BORDER_BOTTOM_STYLE, CommonCssConstants.NONE); + defaultValues.put(CommonCssConstants.BORDER_LEFT_STYLE, CommonCssConstants.NONE); + defaultValues.put(CommonCssConstants.BORDER_RIGHT_STYLE, CommonCssConstants.NONE); + defaultValues.put(CommonCssConstants.BORDER_TOP_STYLE, CommonCssConstants.NONE); + defaultValues.put(CommonCssConstants.BORDER_BOTTOM_WIDTH, CommonCssConstants.MEDIUM); + defaultValues.put(CommonCssConstants.BORDER_LEFT_WIDTH, CommonCssConstants.MEDIUM); + defaultValues.put(CommonCssConstants.BORDER_RIGHT_WIDTH, CommonCssConstants.MEDIUM); + defaultValues.put(CommonCssConstants.BORDER_TOP_WIDTH, CommonCssConstants.MEDIUM); + defaultValues.put(CommonCssConstants.BORDER_WIDTH, CommonCssConstants.MEDIUM); + defaultValues.put(CommonCssConstants.BORDER_IMAGE, CommonCssConstants.NONE); + + defaultValues.put(CommonCssConstants.BORDER_RADIUS, "0"); + defaultValues.put(CommonCssConstants.BORDER_BOTTOM_LEFT_RADIUS, "0"); + defaultValues.put(CommonCssConstants.BORDER_BOTTOM_RIGHT_RADIUS, "0"); + defaultValues.put(CommonCssConstants.BORDER_TOP_LEFT_RADIUS, "0"); + defaultValues.put(CommonCssConstants.BORDER_TOP_RIGHT_RADIUS, "0"); + + defaultValues.put(CommonCssConstants.BOX_SHADOW, CommonCssConstants.NONE); + + defaultValues.put(CommonCssConstants.FLOAT, CommonCssConstants.NONE); + defaultValues.put(CommonCssConstants.FONT_WEIGHT, CommonCssConstants.NORMAL); + defaultValues.put(CommonCssConstants.FONT_SIZE, CommonCssConstants.MEDIUM); + defaultValues.put(CommonCssConstants.FONT_STYLE, CommonCssConstants.NORMAL); + defaultValues.put(CommonCssConstants.FONT_VARIANT, CommonCssConstants.NORMAL); + + defaultValues.put(CommonCssConstants.HYPHENS, CommonCssConstants.MANUAL); + + defaultValues.put(CommonCssConstants.LINE_HEIGHT, CommonCssConstants.NORMAL); + defaultValues.put(CommonCssConstants.LIST_STYLE_TYPE, CommonCssConstants.DISC); + defaultValues.put(CommonCssConstants.LIST_STYLE_IMAGE, CommonCssConstants.NONE); + defaultValues.put(CommonCssConstants.LIST_STYLE_POSITION, CommonCssConstants.OUTSIDE); + + defaultValues.put(CommonCssConstants.MARGIN_BOTTOM, "0"); + defaultValues.put(CommonCssConstants.MARGIN_LEFT, "0"); + defaultValues.put(CommonCssConstants.MARGIN_RIGHT, "0"); + defaultValues.put(CommonCssConstants.MARGIN_TOP, "0"); + + defaultValues.put(CommonCssConstants.MIN_HEIGHT, "0"); + + defaultValues.put(CommonCssConstants.OUTLINE_COLOR, CommonCssConstants.CURRENTCOLOR); + defaultValues.put(CommonCssConstants.OUTLINE_STYLE, CommonCssConstants.NONE); + defaultValues.put(CommonCssConstants.OUTLINE_WIDTH, CommonCssConstants.MEDIUM); + + defaultValues.put(CommonCssConstants.PADDING_BOTTOM, "0"); + defaultValues.put(CommonCssConstants.PADDING_LEFT, "0"); + defaultValues.put(CommonCssConstants.PADDING_RIGHT, "0"); + defaultValues.put(CommonCssConstants.PADDING_TOP, "0"); + + defaultValues.put(CommonCssConstants.PAGE_BREAK_AFTER, CommonCssConstants.AUTO); + defaultValues.put(CommonCssConstants.PAGE_BREAK_BEFORE, CommonCssConstants.AUTO); + defaultValues.put(CommonCssConstants.PAGE_BREAK_INSIDE, CommonCssConstants.AUTO); + + defaultValues.put(CommonCssConstants.POSITION, CommonCssConstants.STATIC); + + defaultValues.put(CommonCssConstants.QUOTES, "\"\\00ab\" \"\\00bb\""); + + defaultValues.put(CommonCssConstants.TEXT_ALIGN, CommonCssConstants.START); + defaultValues.put(CommonCssConstants.TEXT_DECORATION, CommonCssConstants.NONE); + defaultValues.put(CommonCssConstants.TEXT_TRANSFORM, CommonCssConstants.NONE); + defaultValues.put(CommonCssConstants.TEXT_DECORATION, CommonCssConstants.NONE); + + defaultValues.put(CommonCssConstants.WHITE_SPACE, CommonCssConstants.NORMAL); + defaultValues.put(CommonCssConstants.WIDTH, CommonCssConstants.AUTO); + + // TODO not complete + } + + /** + * Gets the default value of a property. + * + * @param property the property + * @return the default value + */ + public static String getDefaultValue(String property) { + String defaultVal = defaultValues.get(property); + if (defaultVal == null) { + Logger logger = LoggerFactory.getLogger(CssDefaults.class); + logger.error(MessageFormatUtil.format(LogMessageConstant.DEFAULT_VALUE_OF_CSS_PROPERTY_UNKNOWN, property)); + } + return defaultVal; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssInheritance.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssInheritance.java new file mode 100644 index 0000000000..357532340d --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssInheritance.java @@ -0,0 +1,142 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.resolve; + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +/** + * Helper class that allows you to check if a property is inheritable. + */ +public class CssInheritance { + + /** + * Set of inheritable properties + * in accordance with "http://www.w3schools.com/cssref/" + * and "https://developer.mozilla.org/en-US/docs/Web/CSS/Reference" + */ + private static final Set inheritableProperties = new HashSet<>(Arrays.asList( + + // Color Properties + CommonCssConstants.COLOR, + + // Basic Box Properties + CommonCssConstants.VISIBILITY, + + // Text Properties + CommonCssConstants.HANGING_PUNCTUATION, + CommonCssConstants.HYPHENS, + CommonCssConstants.LETTER_SPACING, + CommonCssConstants.LINE_HEIGHT, + CommonCssConstants.OVERFLOW_WRAP, + CommonCssConstants.TAB_SIZE, + CommonCssConstants.TEXT_ALIGN, + CommonCssConstants.TEXT_ALIGN_LAST, + CommonCssConstants.TEXT_INDENT, + CommonCssConstants.TEXT_JUSTIFY, + CommonCssConstants.TEXT_TRANSFORM, + CommonCssConstants.WHITE_SPACE, + CommonCssConstants.WORD_BREAK, + CommonCssConstants.WORD_SPACING, + CommonCssConstants.WORDWRAP, + + // Text Decoration Properties + CommonCssConstants.TEXT_SHADOW, + CommonCssConstants.TEXT_UNDERLINE_POSITION, + + // Font Properties + CommonCssConstants.FONT, + CommonCssConstants.FONT_FAMILY, + CommonCssConstants.FONT_FEATURE_SETTINGS, + CommonCssConstants.FONT_KERNING, + CommonCssConstants.FONT_LANGUAGE_OVERRIDE, + CommonCssConstants.FONT_SIZE, + CommonCssConstants.FONT_SIZE_ADJUST, + CommonCssConstants.FONT_STRETCH, + CommonCssConstants.FONT_STYLE, + CommonCssConstants.FONT_SYNTHESIS, + CommonCssConstants.FONT_VARIANT, + CommonCssConstants.FONT_VARIANT_ALTERNATES, + CommonCssConstants.FONT_VARIANT_CAPS, + CommonCssConstants.FONT_VARIANT_EAST_ASIAN, + CommonCssConstants.FONT_VARIANT_LIGATURES, + CommonCssConstants.FONT_VARIANT_NUMERIC, + CommonCssConstants.FONT_VARIANT_POSITION, + CommonCssConstants.FONT_WEIGHT, + + // Writing Modes Properties + CommonCssConstants.DIRECTION, + CommonCssConstants.TEXT_ORIENTATION, + CommonCssConstants.TEXT_COMBINE_UPRIGHT, + CommonCssConstants.UNICODE_BIDI, + CommonCssConstants.WRITING_MODE, + + // Table Properties + CommonCssConstants.BORDER_COLLAPSE, + CommonCssConstants.BORDER_SPACING, + CommonCssConstants.CAPTION_SIDE, + CommonCssConstants.EMPTY_CELLS, + + // Lists and Counters Properties + CommonCssConstants.LIST_STYLE, + CommonCssConstants.LIST_STYLE_IMAGE, + CommonCssConstants.LIST_STYLE_POSITION, + CommonCssConstants.LIST_STYLE_TYPE, + + // Generated Content for Paged Media + CommonCssConstants.QUOTES + )); + + /** + * Checks if a property is inheritable. + * + * @param cssProperty the CSS property + * @return true, if the property is inheritable + */ + public static boolean isInheritable(String cssProperty) { + return inheritableProperties.contains(cssProperty); + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssPropertyMerger.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssPropertyMerger.java new file mode 100644 index 0000000000..80403e850f --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssPropertyMerger.java @@ -0,0 +1,106 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.resolve; + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; + +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.Set; + +/** + * Utilities class to merge CSS properties. + */ +public final class CssPropertyMerger { + + /** + * Creates a new {@link CssPropertyMerger} class. + */ + private CssPropertyMerger() { + } + + /** + * Merges text decoration. + * + * @param firstValue the first value + * @param secondValue the second value + * @return the merged value + */ + public static String mergeTextDecoration(String firstValue, String secondValue) { + if (firstValue == null) { + return secondValue; + } else if (secondValue == null) { + return firstValue; + } + + Set merged = normalizeTextDecoration(firstValue); + merged.addAll(normalizeTextDecoration(secondValue)); + + StringBuilder sb = new StringBuilder(); + for (String mergedProp : merged) { + if (sb.length() != 0) { + sb.append(" "); + } + sb.append(mergedProp); + } + return sb.length() != 0 ? sb.toString() : CommonCssConstants.NONE; + } + + /** + * Normalizes text decoration values. + * + * @param value the text decoration value + * @return a set of normalized decoration values + */ + private static Set normalizeTextDecoration(String value) { + String[] parts = value.split("\\s+"); + // LinkedHashSet to make order invariant of JVM + Set merged = new LinkedHashSet<>(); + merged.addAll(Arrays.asList(parts)); + // if none and any other decoration are used together, none is displayed + if (merged.contains(CommonCssConstants.NONE)) { + merged.clear(); + } + return merged; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssQuotes.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssQuotes.java new file mode 100644 index 0000000000..3ee3ec196b --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssQuotes.java @@ -0,0 +1,195 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.resolve; + +import com.itextpdf.io.util.MessageFormatUtil; +import com.itextpdf.styledxmlparser.LogMessageConstant; +import com.itextpdf.styledxmlparser.css.CommonCssConstants; +import com.itextpdf.styledxmlparser.css.parse.CssDeclarationValueTokenizer; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; + +/** + * Helper class to deal with quoted values in strings. + */ +public class CssQuotes { + + /** + * The empty quote value. + */ + private static final String EMPTY_QUOTE = ""; + + /** + * The open quotes. + */ + private ArrayList openQuotes; + + /** + * The close quotes. + */ + private ArrayList closeQuotes; + + /** + * Creates a new {@link CssQuotes} instance. + * + * @param openQuotes the open quotes + * @param closeQuotes the close quotes + */ + private CssQuotes(ArrayList openQuotes, ArrayList closeQuotes) { + this.openQuotes = openQuotes; + this.closeQuotes = closeQuotes; + } + + /** + * Creates a {@link CssQuotes} instance. + * + * @param quotesString the quotes string + * @param fallbackToDefault indicates whether it's OK to fall back to the default + * @return the resulting {@link CssQuotes} instance + */ + public static CssQuotes createQuotes(String quotesString, boolean fallbackToDefault) { + boolean error = false; + ArrayList> quotes = new ArrayList<>(2); + quotes.add(new ArrayList()); + quotes.add(new ArrayList()); + if (quotesString != null) { + if (quotesString.equals(CommonCssConstants.NONE)) { + quotes.get(0).add(EMPTY_QUOTE); + quotes.get(1).add(EMPTY_QUOTE); + return new CssQuotes(quotes.get(0), quotes.get(1)); + } + CssDeclarationValueTokenizer tokenizer = new CssDeclarationValueTokenizer(quotesString); + CssDeclarationValueTokenizer.Token token; + for (int i = 0; ((token = tokenizer.getNextValidToken()) != null); ++i) { + if (token.isString()) { + quotes.get(i % 2).add(token.getValue()); + } else { + error = true; + break; + } + } + if (quotes.get(0).size() == quotes.get(1).size() && !quotes.get(0).isEmpty() && !error) { + return new CssQuotes(quotes.get(0), quotes.get(1)); + } else { + LoggerFactory.getLogger(CssQuotes.class).error(MessageFormatUtil.format(LogMessageConstant.QUOTES_PROPERTY_INVALID, quotesString)); + } + } + return fallbackToDefault ? createDefaultQuotes() : null; + } + + /** + * Creates the default {@link CssQuotes} instance. + * + * @return the {@link CssQuotes} instance + */ + public static CssQuotes createDefaultQuotes() { + ArrayList openQuotes = new ArrayList<>(); + ArrayList closeQuotes = new ArrayList<>(); + openQuotes.add("\u00ab"); + closeQuotes.add("\u00bb"); + return new CssQuotes(openQuotes, closeQuotes); + } + + /** + * Resolves quotes. + * + * @param value the value + * @param context the CSS context + * @return the quote string + */ + public String resolveQuote(String value, AbstractCssContext context) { + int depth = context.getQuotesDepth(); + if (CommonCssConstants.OPEN_QUOTE.equals(value)) { + increaseDepth(context); + return getQuote(depth, openQuotes); + } else if (CommonCssConstants.CLOSE_QUOTE.equals(value)) { + decreaseDepth(context); + return getQuote(depth - 1, closeQuotes); + } else if (CommonCssConstants.NO_OPEN_QUOTE.equals(value)) { + increaseDepth(context); + return EMPTY_QUOTE; + } else if (CommonCssConstants.NO_CLOSE_QUOTE.equals(value)) { + decreaseDepth(context); + return EMPTY_QUOTE; + } + return null; + } + + /** + * Increases the quote depth. + * + * @param context the context + */ + private void increaseDepth(AbstractCssContext context) { + context.setQuotesDepth(context.getQuotesDepth() + 1); + } + + /** + * Decreases the quote depth. + * + * @param context the context + */ + private void decreaseDepth(AbstractCssContext context) { + if (context.getQuotesDepth() > 0) { + context.setQuotesDepth(context.getQuotesDepth() - 1); + } + } + + /** + * Gets the quote. + * + * @param depth the depth + * @param quotes the quotes + * @return the requested quote string + */ + private String getQuote(int depth, ArrayList quotes) { + if (depth >= quotes.size()) { + return quotes.get(quotes.size() - 1); + } + if (depth < 0) { + return EMPTY_QUOTE; + } + return quotes.get(depth); + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/ShorthandResolverFactory.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/ShorthandResolverFactory.java index 245e57dad2..09fd0dd23a 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/ShorthandResolverFactory.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/ShorthandResolverFactory.java @@ -1,6 +1,6 @@ /* This file is part of the iText (R) project. - Copyright (c) 1998-2018 iText Group NV + Copyright (c) 1998-2017 iText Group NV Authors: Bruno Lowagie, Paulo Soares, et al. This program is free software; you can redistribute it and/or modify @@ -44,9 +44,22 @@ This file is part of the iText (R) project. -import com.itextpdf.styledxmlparser.css.CssConstants; +import com.itextpdf.styledxmlparser.css.CommonCssConstants; +import com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.BackgroundShorthandResolver; +import com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.BorderBottomShorthandResolver; +import com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.BorderColorShorthandResolver; +import com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.BorderLeftShorthandResolver; +import com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.BorderRadiusShorthandResolver; +import com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.BorderRightShorthandResolver; import com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.BorderShorthandResolver; +import com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.BorderStyleShorthandResolver; +import com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.BorderTopShorthandResolver; +import com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.BorderWidthShorthandResolver; import com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.FontShorthandResolver; +import com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.ListStyleShorthandResolver; +import com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.MarginShorthandResolver; +import com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.OutlineShorthandResolver; +import com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.PaddingShorthandResolver; import java.util.HashMap; import java.util.Map; @@ -60,8 +73,21 @@ public class ShorthandResolverFactory { private static final Map shorthandResolvers; static { shorthandResolvers = new HashMap<>(); - shorthandResolvers.put(CssConstants.BORDER, new BorderShorthandResolver()); - shorthandResolvers.put( CssConstants.FONT,new FontShorthandResolver() ); + shorthandResolvers.put(CommonCssConstants.BACKGROUND, new BackgroundShorthandResolver()); + shorthandResolvers.put(CommonCssConstants.BORDER, new BorderShorthandResolver()); + shorthandResolvers.put(CommonCssConstants.BORDER_BOTTOM, new BorderBottomShorthandResolver()); + shorthandResolvers.put(CommonCssConstants.BORDER_COLOR, new BorderColorShorthandResolver()); + shorthandResolvers.put(CommonCssConstants.BORDER_LEFT, new BorderLeftShorthandResolver()); + shorthandResolvers.put(CommonCssConstants.BORDER_RADIUS, new BorderRadiusShorthandResolver()); + shorthandResolvers.put(CommonCssConstants.BORDER_RIGHT, new BorderRightShorthandResolver()); + shorthandResolvers.put(CommonCssConstants.BORDER_STYLE, new BorderStyleShorthandResolver()); + shorthandResolvers.put(CommonCssConstants.BORDER_TOP, new BorderTopShorthandResolver()); + shorthandResolvers.put(CommonCssConstants.BORDER_WIDTH, new BorderWidthShorthandResolver()); + shorthandResolvers.put(CommonCssConstants.FONT, new FontShorthandResolver()); + shorthandResolvers.put(CommonCssConstants.LIST_STYLE, new ListStyleShorthandResolver()); + shorthandResolvers.put(CommonCssConstants.MARGIN, new MarginShorthandResolver()); + shorthandResolvers.put(CommonCssConstants.OUTLINE, new OutlineShorthandResolver()); + shorthandResolvers.put(CommonCssConstants.PADDING, new PaddingShorthandResolver()); // TODO text-decoration is a shorthand in CSS3, however it is not yet supported in any major browsers } diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/AbstractBorderShorthandResolver.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/AbstractBorderShorthandResolver.java index fe7fc62b4e..2eb62593fe 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/AbstractBorderShorthandResolver.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/AbstractBorderShorthandResolver.java @@ -42,21 +42,17 @@ This file is part of the iText (R) project. */ package com.itextpdf.styledxmlparser.css.resolve.shorthand.impl; - -import com.itextpdf.io.util.MessageFormatUtil; import com.itextpdf.styledxmlparser.LogMessageConstant; -import com.itextpdf.styledxmlparser.css.CssConstants; +import com.itextpdf.styledxmlparser.css.CommonCssConstants; import com.itextpdf.styledxmlparser.css.CssDeclaration; import com.itextpdf.styledxmlparser.css.resolve.shorthand.IShorthandResolver; import com.itextpdf.styledxmlparser.css.util.CssUtils; + +import com.itextpdf.io.util.MessageFormatUtil; +import java.util.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - /** * Abstract {@link IShorthandResolver} implementation for borders. */ @@ -79,7 +75,7 @@ public abstract class AbstractBorderShorthandResolver implements IShorthandResol protected abstract String getPrefix(); /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.resolve.shorthand.IShorthandResolver#resolveShorthand(java.lang.String) + * @see com.itextpdf.styledxmlparser.css.resolve.shorthand.IShorthandResolver#resolveShorthand(java.lang.String) */ @Override public List resolveShorthand(String shorthandExpression) { @@ -87,7 +83,7 @@ public List resolveShorthand(String shorthandExpression) { String stylePropName = MessageFormatUtil.format(_0_STYLE, getPrefix()); String colorPropName = MessageFormatUtil.format(_0_COLOR, getPrefix()); - if (CssConstants.INITIAL.equals(shorthandExpression) || CssConstants.INHERIT.equals(shorthandExpression)) { + if (CommonCssConstants.INITIAL.equals(shorthandExpression) || CommonCssConstants.INHERIT.equals(shorthandExpression)) { return Arrays.asList( new CssDeclaration(widthPropName, shorthandExpression), new CssDeclaration(stylePropName, shorthandExpression), @@ -101,15 +97,15 @@ public List resolveShorthand(String shorthandExpression) { String borderWidthValue = null; for (String value : props) { - if (CssConstants.INITIAL.equals(value) || CssConstants.INHERIT.equals(value)) { + if (CommonCssConstants.INITIAL.equals(value) || CommonCssConstants.INHERIT.equals(value)) { Logger logger = LoggerFactory.getLogger(AbstractBorderShorthandResolver.class); logger.warn(MessageFormatUtil.format(LogMessageConstant.INVALID_CSS_PROPERTY_DECLARATION, shorthandExpression)); return Collections.emptyList(); } - if (CssConstants.BORDER_WIDTH_VALUES.contains(value) || CssUtils.isNumericValue(value) + if (CommonCssConstants.BORDER_WIDTH_VALUES.contains(value) || CssUtils.isNumericValue(value) || CssUtils.isMetricValue(value) || CssUtils.isRelativeValue(value)) { borderWidthValue = value; - } else if (CssConstants.BORDER_STYLE_VALUES.contains(value) || value.equals(CssConstants.AUTO)) { // AUTO property value is needed for outline property only + } else if (CommonCssConstants.BORDER_STYLE_VALUES.contains(value) || value.equals(CommonCssConstants.AUTO)) { // AUTO property value is needed for outline property only borderStyleValue = value; } else if (CssUtils.isColorProperty(value)) { borderColorValue = value; @@ -117,9 +113,9 @@ public List resolveShorthand(String shorthandExpression) { } List resolvedDecl = new ArrayList<>(); - resolvedDecl.add(new CssDeclaration(widthPropName, borderWidthValue == null ? CssConstants.INITIAL : borderWidthValue)); - resolvedDecl.add(new CssDeclaration(stylePropName, borderStyleValue == null ? CssConstants.INITIAL : borderStyleValue)); - resolvedDecl.add(new CssDeclaration(colorPropName, borderColorValue == null ? CssConstants.INITIAL : borderColorValue)); + resolvedDecl.add(new CssDeclaration(widthPropName, borderWidthValue == null ? CommonCssConstants.INITIAL : borderWidthValue)); + resolvedDecl.add(new CssDeclaration(stylePropName, borderStyleValue == null ? CommonCssConstants.INITIAL : borderStyleValue)); + resolvedDecl.add(new CssDeclaration(colorPropName, borderColorValue == null ? CommonCssConstants.INITIAL : borderColorValue)); return resolvedDecl; } } diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/AbstractBoxShorthandResolver.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/AbstractBoxShorthandResolver.java index e55ff3db52..4d0426bc6f 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/AbstractBoxShorthandResolver.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/AbstractBoxShorthandResolver.java @@ -44,7 +44,7 @@ This file is part of the iText (R) project. import com.itextpdf.io.util.MessageFormatUtil; import com.itextpdf.styledxmlparser.LogMessageConstant; -import com.itextpdf.styledxmlparser.css.CssConstants; +import com.itextpdf.styledxmlparser.css.CommonCssConstants; import com.itextpdf.styledxmlparser.css.CssDeclaration; import com.itextpdf.styledxmlparser.css.resolve.shorthand.IShorthandResolver; import org.slf4j.Logger; @@ -86,7 +86,7 @@ public abstract class AbstractBoxShorthandResolver implements IShorthandResolver protected abstract String getPostfix(); /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.resolve.shorthand.IShorthandResolver#resolveShorthand(java.lang.String) + * @see com.itextpdf.styledxmlparser.css.resolve.shorthand.IShorthandResolver#resolveShorthand(java.lang.String) */ @Override public List resolveShorthand(String shorthandExpression) { @@ -103,7 +103,7 @@ public List resolveShorthand(String shorthandExpression) { resolvedDecl.add(new CssDeclaration(leftProperty, props[0])); } else { for (String prop : props) { - if (CssConstants.INHERIT.equals(prop) || CssConstants.INITIAL.equals(prop)) { + if (CommonCssConstants.INHERIT.equals(prop) || CommonCssConstants.INITIAL.equals(prop)) { Logger logger = LoggerFactory.getLogger(AbstractBoxShorthandResolver.class); logger.warn(MessageFormatUtil.format(LogMessageConstant.INVALID_CSS_PROPERTY_DECLARATION, shorthandExpression)); return Collections.emptyList(); diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/AbstractCornersShorthandResolver.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/AbstractCornersShorthandResolver.java new file mode 100644 index 0000000000..d7eb07d07a --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/AbstractCornersShorthandResolver.java @@ -0,0 +1,143 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.resolve.shorthand.impl; + +import com.itextpdf.io.util.MessageFormatUtil; +import com.itextpdf.styledxmlparser.css.CssDeclaration; +import com.itextpdf.styledxmlparser.css.resolve.shorthand.IShorthandResolver; + +import java.util.ArrayList; +import java.util.List; + +/** + * Abstract {@link IShorthandResolver} implementation for corners definitions. + */ +public abstract class AbstractCornersShorthandResolver implements IShorthandResolver { + + /** + * The template for -bottom-left properties. + */ + private static final String _0_BOTTOM_LEFT_1 = "{0}-bottom-left{1}"; + + /** + * The template for -bottom-right properties. + */ + private static final String _0_BOTTOM_RIGHT_1 = "{0}-bottom-right{1}"; + + /** + * The template for -top-left properties. + */ + private static final String _0_TOP_LEFT_1 = "{0}-top-left{1}"; + + /** + * The template for -top-right properties. + */ + private static final String _0_TOP_RIGHT_1 = "{0}-top-right{1}"; + + /** + * Gets the prefix of a property. + * + * @return the prefix + */ + protected abstract String getPrefix(); + + /** + * Gets the postfix of a property. + * + * @return the postfix + */ + protected abstract String getPostfix(); + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.resolve.shorthand.IShorthandResolver#resolveShorthand(java.lang.String) + */ + @Override + public List resolveShorthand(String shorthandExpression) { + String[] props = shorthandExpression.split("\\s*\\/\\s*"); + String[][] properties = new String[props.length][]; + for (int i = 0; i < props.length; i++) { + properties[i] = props[i].split("\\s+"); + } + + String[] resultExpressions = new String[4]; + for (int i = 0; i < resultExpressions.length; i++) { + resultExpressions[i] = ""; + } + + List resolvedDecl = new ArrayList<>(); + String topLeftProperty = MessageFormatUtil.format(_0_TOP_LEFT_1, getPrefix(), getPostfix()); + String topRightProperty = MessageFormatUtil.format(_0_TOP_RIGHT_1, getPrefix(), getPostfix()); + String bottomRightProperty = MessageFormatUtil.format(_0_BOTTOM_RIGHT_1, getPrefix(), getPostfix()); + String bottomLeftProperty = MessageFormatUtil.format(_0_BOTTOM_LEFT_1, getPrefix(), getPostfix()); + + for (int i = 0; i < properties.length; i++) { + if (properties[i].length == 1) { + resultExpressions[0] += properties[i][0] + " "; + resultExpressions[1] += properties[i][0] + " "; + resultExpressions[2] += properties[i][0] + " "; + resultExpressions[3] += properties[i][0] + " "; + } else if (properties[i].length == 2) { + resultExpressions[0] += properties[i][0] + " "; + resultExpressions[1] += properties[i][1] + " "; + resultExpressions[2] += properties[i][0] + " "; + resultExpressions[3] += properties[i][1] + " "; + } else if (properties[i].length == 3) { + resultExpressions[0] += properties[i][0] + " "; + resultExpressions[1] += properties[i][1] + " "; + resultExpressions[2] += properties[i][2] + " "; + resultExpressions[3] += properties[i][1] + " "; + } else if (properties[i].length == 4) { + resultExpressions[0] += properties[i][0] + " "; + resultExpressions[1] += properties[i][1] + " "; + resultExpressions[2] += properties[i][2] + " "; + resultExpressions[3] += properties[i][3] + " "; + } + } + + resolvedDecl.add(new CssDeclaration(topLeftProperty, resultExpressions[0])); + resolvedDecl.add(new CssDeclaration(topRightProperty, resultExpressions[1])); + resolvedDecl.add(new CssDeclaration(bottomRightProperty, resultExpressions[2])); + resolvedDecl.add(new CssDeclaration(bottomLeftProperty, resultExpressions[3])); + return resolvedDecl; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BackgroundShorthandResolver.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BackgroundShorthandResolver.java new file mode 100644 index 0000000000..94ed819f0d --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BackgroundShorthandResolver.java @@ -0,0 +1,235 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.resolve.shorthand.impl; + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.itextpdf.io.util.MessageFormatUtil; +import com.itextpdf.styledxmlparser.LogMessageConstant; +import com.itextpdf.styledxmlparser.css.CssDeclaration; +import com.itextpdf.styledxmlparser.css.resolve.shorthand.IShorthandResolver; +import com.itextpdf.styledxmlparser.css.util.CssUtils; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * {@link IShorthandResolver} implementation for backgrounds. + */ +public class BackgroundShorthandResolver implements IShorthandResolver { + + /** The Constant UNDEFINED_TYPE. */ + private static final int UNDEFINED_TYPE = -1; + + /** The Constant BACKGROUND_COLOR_TYPE. */ + private static final int BACKGROUND_COLOR_TYPE = 0; + + /** The Constant BACKGROUND_IMAGE_TYPE. */ + private static final int BACKGROUND_IMAGE_TYPE = 1; + + /** The Constant BACKGROUND_POSITION_TYPE. */ + private static final int BACKGROUND_POSITION_TYPE = 2; + + /** The Constant BACKGROUND_POSITION_OR_SIZE_TYPE. */ + private static final int BACKGROUND_POSITION_OR_SIZE_TYPE = 3; // might have the same type, but position always precedes size + + /** The Constant BACKGROUND_REPEAT_TYPE. */ + private static final int BACKGROUND_REPEAT_TYPE = 4; + + /** The Constant BACKGROUND_ORIGIN_OR_CLIP_TYPE. */ + private static final int BACKGROUND_ORIGIN_OR_CLIP_TYPE = 5; // have the same possible values but apparently origin values precedes clip value + + /** The Constant BACKGROUND_CLIP_TYPE. */ + private static final int BACKGROUND_CLIP_TYPE = 6; + + /** The Constant BACKGROUND_ATTACHMENT_TYPE. */ + private static final int BACKGROUND_ATTACHMENT_TYPE = 7; + + // With CSS3, you can apply multiple backgrounds to elements. These are layered atop one another + // with the first background you provide on top and the last background listed in the back. Only + // the last background can include a background color. + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.resolve.shorthand.IShorthandResolver#resolveShorthand(java.lang.String) + */ + @Override + public List resolveShorthand(String shorthandExpression) { + if (CommonCssConstants.INITIAL.equals(shorthandExpression) || CommonCssConstants.INHERIT.equals(shorthandExpression)) { + return Arrays.asList( + new CssDeclaration(CommonCssConstants.BACKGROUND_COLOR, shorthandExpression), + new CssDeclaration(CommonCssConstants.BACKGROUND_IMAGE, shorthandExpression), + new CssDeclaration(CommonCssConstants.BACKGROUND_POSITION, shorthandExpression), + new CssDeclaration(CommonCssConstants.BACKGROUND_SIZE, shorthandExpression), + new CssDeclaration(CommonCssConstants.BACKGROUND_REPEAT, shorthandExpression), + new CssDeclaration(CommonCssConstants.BACKGROUND_ORIGIN, shorthandExpression), + new CssDeclaration(CommonCssConstants.BACKGROUND_CLIP, shorthandExpression), + new CssDeclaration(CommonCssConstants.BACKGROUND_ATTACHMENT, shorthandExpression) + ); + } + + List commaSeparatedExpressions = splitMultipleBackgrounds(shorthandExpression); + + // TODO ignore multiple backgrounds at the moment + String backgroundExpression = commaSeparatedExpressions.get(0); + String[] resolvedProps = new String[8]; + + String[] props = backgroundExpression.split("\\s+"); + boolean slashEncountered = false; + for (String value : props) { + int slashCharInd = value.indexOf('/'); + if (slashCharInd > 0 && !value.contains("url(")) { + slashEncountered = true; + String value1 = value.substring(0, slashCharInd); + String value2 = value.substring(slashCharInd + 1, value.length()); + putPropertyBasedOnType(resolvePropertyType(value1), value1, resolvedProps, false); + putPropertyBasedOnType(resolvePropertyType(value2), value2, resolvedProps, true); + } else { + putPropertyBasedOnType(resolvePropertyType(value), value, resolvedProps, slashEncountered); + } + + } + + for (int i = 0; i < resolvedProps.length; ++i) { + if (resolvedProps[i] == null) { + resolvedProps[i] = CommonCssConstants.INITIAL; + } + } + List cssDeclarations = Arrays.asList( + new CssDeclaration(CommonCssConstants.BACKGROUND_COLOR, resolvedProps[BACKGROUND_COLOR_TYPE]), + new CssDeclaration(CommonCssConstants.BACKGROUND_IMAGE, resolvedProps[BACKGROUND_IMAGE_TYPE]), + new CssDeclaration(CommonCssConstants.BACKGROUND_POSITION, resolvedProps[BACKGROUND_POSITION_TYPE]), + new CssDeclaration(CommonCssConstants.BACKGROUND_SIZE, resolvedProps[BACKGROUND_POSITION_OR_SIZE_TYPE]), + new CssDeclaration(CommonCssConstants.BACKGROUND_REPEAT, resolvedProps[BACKGROUND_REPEAT_TYPE]), + new CssDeclaration(CommonCssConstants.BACKGROUND_ORIGIN, resolvedProps[BACKGROUND_ORIGIN_OR_CLIP_TYPE]), + new CssDeclaration(CommonCssConstants.BACKGROUND_CLIP, resolvedProps[BACKGROUND_CLIP_TYPE]), + new CssDeclaration(CommonCssConstants.BACKGROUND_ATTACHMENT, resolvedProps[BACKGROUND_ATTACHMENT_TYPE]) + ); + + return cssDeclarations; + } + + /** + * Resolves the property type. + * + * @param value the value + * @return the property type value + */ + private int resolvePropertyType(String value) { + if (value.contains("url(") || CommonCssConstants.NONE.equals(value)) { + return BACKGROUND_IMAGE_TYPE; + } else if (CommonCssConstants.BACKGROUND_REPEAT_VALUES.contains(value)) { + return BACKGROUND_REPEAT_TYPE; + } else if (CommonCssConstants.BACKGROUND_ATTACHMENT_VALUES.contains(value)) { + return BACKGROUND_ATTACHMENT_TYPE; + } else if (CommonCssConstants.BACKGROUND_POSITION_VALUES.contains(value)) { + return BACKGROUND_POSITION_TYPE; + } else if (CssUtils.isNumericValue(value) || CssUtils.isMetricValue(value) || CssUtils.isRelativeValue(value)) { + return BACKGROUND_POSITION_OR_SIZE_TYPE; + } else if (CommonCssConstants.BACKGROUND_SIZE_VALUES.contains(value)) { + return BACKGROUND_POSITION_OR_SIZE_TYPE; + } else if(CssUtils.isColorProperty(value)) { + return BACKGROUND_COLOR_TYPE; + } else if (CommonCssConstants.BACKGROUND_ORIGIN_OR_CLIP_VALUES.contains(value)) { + return BACKGROUND_ORIGIN_OR_CLIP_TYPE; + } + return UNDEFINED_TYPE; + } + + /** + * Registers a property based on its type. + * + * @param type the property type + * @param value the property value + * @param resolvedProps the resolved properties + * @param slashEncountered indicates whether a slash was encountered + */ + private void putPropertyBasedOnType(int type, String value, String[] resolvedProps, boolean slashEncountered) { + if (type == UNDEFINED_TYPE) { + Logger logger = LoggerFactory.getLogger(BackgroundShorthandResolver.class); + logger.error(MessageFormatUtil.format(LogMessageConstant.WAS_NOT_ABLE_TO_DEFINE_BACKGROUND_CSS_SHORTHAND_PROPERTIES, value)); + return; + } + if (type == BACKGROUND_POSITION_OR_SIZE_TYPE && !slashEncountered) { + type = BACKGROUND_POSITION_TYPE; + } + + if (type == BACKGROUND_ORIGIN_OR_CLIP_TYPE && resolvedProps[BACKGROUND_ORIGIN_OR_CLIP_TYPE] != null) { + type = BACKGROUND_CLIP_TYPE; + } + + if ((type == BACKGROUND_POSITION_OR_SIZE_TYPE || type == BACKGROUND_POSITION_TYPE) && resolvedProps[type] != null) { + resolvedProps[type] += " " + value; + } else { + resolvedProps[type] = value; + } + } + + /** + * Splits multiple backgrounds. + * + * @param shorthandExpression the shorthand expression + * @return the list of backgrounds + */ + private List splitMultipleBackgrounds(String shorthandExpression) { + List commaSeparatedExpressions = new ArrayList<>(); + boolean isInsideParentheses = false; // in order to avoid split inside rgb/rgba color definition + int prevStart = 0; + for (int i = 0; i < shorthandExpression.length(); ++i) { + if (shorthandExpression.charAt(i) == ',' && !isInsideParentheses) { + commaSeparatedExpressions.add(shorthandExpression.substring(prevStart, i)); + prevStart = i + 1; + } else if (shorthandExpression.charAt(i) == '(') { + isInsideParentheses = true; + } else if (shorthandExpression.charAt(i) == ')') { + isInsideParentheses = false; + } + } + + if (commaSeparatedExpressions.isEmpty()) { + commaSeparatedExpressions.add(shorthandExpression); + } + return commaSeparatedExpressions; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderBottomShorthandResolver.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderBottomShorthandResolver.java new file mode 100644 index 0000000000..9163334327 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderBottomShorthandResolver.java @@ -0,0 +1,59 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.resolve.shorthand.impl; + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; + +/** + * {@link AbstractBorderShorthandResolver} implementation for bottom borders. + */ +public class BorderBottomShorthandResolver extends AbstractBorderShorthandResolver { + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.AbstractBorderShorthandResolver#getPrefix() + */ + @Override + protected String getPrefix() { + return CommonCssConstants.BORDER_BOTTOM; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderColorShorthandResolver.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderColorShorthandResolver.java new file mode 100644 index 0000000000..0b321afc09 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderColorShorthandResolver.java @@ -0,0 +1,67 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.resolve.shorthand.impl; + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; + +/** + * {@link AbstractBoxShorthandResolver} implementation for border colors. + */ +public class BorderColorShorthandResolver extends AbstractBoxShorthandResolver { + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.AbstractBoxShorthandResolver#getPrefix() + */ + @Override + protected String getPrefix() { + return CommonCssConstants.BORDER; + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.AbstractBoxShorthandResolver#getPostfix() + */ + @Override + protected String getPostfix() { + return "-color"; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderLeftShorthandResolver.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderLeftShorthandResolver.java new file mode 100644 index 0000000000..a750941410 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderLeftShorthandResolver.java @@ -0,0 +1,59 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.resolve.shorthand.impl; + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; + +/** + * {@link AbstractBorderShorthandResolver} implementation for left borders. + */ +public class BorderLeftShorthandResolver extends AbstractBorderShorthandResolver { + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.AbstractBorderShorthandResolver#getPrefix() + */ + @Override + protected String getPrefix() { + return CommonCssConstants.BORDER_LEFT; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderRadiusShorthandResolver.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderRadiusShorthandResolver.java new file mode 100644 index 0000000000..8eb101b3d4 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderRadiusShorthandResolver.java @@ -0,0 +1,67 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.resolve.shorthand.impl; + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; + +/** + * {@link AbstractCornersShorthandResolver} implementation for border radius. + */ +public class BorderRadiusShorthandResolver extends AbstractCornersShorthandResolver { + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.AbstractBoxShorthandResolver#getPrefix() + */ + @Override + protected String getPrefix() { + return CommonCssConstants.BORDER; + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.AbstractBoxShorthandResolver#getPostfix() + */ + @Override + protected String getPostfix() { + return "-radius"; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderRightShorthandResolver.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderRightShorthandResolver.java new file mode 100644 index 0000000000..d019c8c9d3 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderRightShorthandResolver.java @@ -0,0 +1,59 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.resolve.shorthand.impl; + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; + +/** + * {@link AbstractBorderShorthandResolver} implementation for right borders. + */ +public class BorderRightShorthandResolver extends AbstractBorderShorthandResolver { + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.AbstractBorderShorthandResolver#getPrefix() + */ + @Override + protected String getPrefix() { + return CommonCssConstants.BORDER_RIGHT; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderShorthandResolver.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderShorthandResolver.java index a38888dac2..a8d4efa3ae 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderShorthandResolver.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderShorthandResolver.java @@ -43,7 +43,7 @@ This file is part of the iText (R) project. package com.itextpdf.styledxmlparser.css.resolve.shorthand.impl; import com.itextpdf.io.util.MessageFormatUtil; -import com.itextpdf.styledxmlparser.css.CssConstants; +import com.itextpdf.styledxmlparser.css.CommonCssConstants; import com.itextpdf.styledxmlparser.css.CssDeclaration; import com.itextpdf.styledxmlparser.css.resolve.shorthand.IShorthandResolver; import com.itextpdf.styledxmlparser.css.resolve.shorthand.ShorthandResolverFactory; @@ -59,15 +59,15 @@ This file is part of the iText (R) project. public class BorderShorthandResolver extends AbstractBorderShorthandResolver { /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.resolve.shorthand.impl.AbstractBorderShorthandResolver#getPrefix() + * @see com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.AbstractBorderShorthandResolver#getPrefix() */ @Override protected String getPrefix() { - return CssConstants.BORDER; + return CommonCssConstants.BORDER; } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.resolve.shorthand.impl.AbstractBorderShorthandResolver#resolveShorthand(java.lang.String) + * @see com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.AbstractBorderShorthandResolver#resolveShorthand(java.lang.String) */ @Override public List resolveShorthand(String shorthandExpression) { diff --git a/src/main/java/com/itextpdf/styledxmlparser/HtmlUtils.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderStyleShorthandResolver.java similarity index 74% rename from src/main/java/com/itextpdf/styledxmlparser/HtmlUtils.java rename to src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderStyleShorthandResolver.java index d7b8db6a7f..75862a1275 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/HtmlUtils.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderStyleShorthandResolver.java @@ -1,6 +1,6 @@ /* This file is part of the iText (R) project. - Copyright (c) 1998-2018 iText Group NV + Copyright (c) 1998-2017 iText Group NV Authors: Bruno Lowagie, Paulo Soares, et al. This program is free software; you can redistribute it and/or modify @@ -40,31 +40,28 @@ This file is part of the iText (R) project. For more information, please contact iText Software Corp. at this address: sales@itextpdf.com */ -package com.itextpdf.styledxmlparser; +package com.itextpdf.styledxmlparser.css.resolve.shorthand.impl; - -import com.itextpdf.styledxmlparser.node.IElementNode; +import com.itextpdf.styledxmlparser.css.CommonCssConstants; /** - * Utilities class with HTML-related functionality. + * {@link AbstractBoxShorthandResolver} implementation for border styles. */ -public final class HtmlUtils { +public class BorderStyleShorthandResolver extends AbstractBoxShorthandResolver { - /** - * Creates a new {@link HtmlUtils} instance. + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.AbstractBoxShorthandResolver#getPrefix() */ - private HtmlUtils() { + @Override + protected String getPrefix() { + return CommonCssConstants.BORDER; } - /** - * Checks if an {@link IElementNode} represents a style sheet link. - * - * @param headChildElement the head child element - * @return true, if the element node represents a style sheet link + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.AbstractBoxShorthandResolver#getPostfix() */ - public static boolean isStyleSheetLink(IElementNode headChildElement) { - return headChildElement.name().equals(TagConstants.LINK) - && AttributeConstants.STYLESHEET.equals(headChildElement.getAttribute(AttributeConstants.REL)); + @Override + protected String getPostfix() { + return "-style"; } - } diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderTopShorthandResolver.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderTopShorthandResolver.java new file mode 100644 index 0000000000..4a19630453 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderTopShorthandResolver.java @@ -0,0 +1,59 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.resolve.shorthand.impl; + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; + +/** + * {@link AbstractBorderShorthandResolver} implementation for top borders. + */ +public class BorderTopShorthandResolver extends AbstractBorderShorthandResolver { + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.AbstractBorderShorthandResolver#getPrefix() + */ + @Override + protected String getPrefix() { + return CommonCssConstants.BORDER_TOP; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderWidthShorthandResolver.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderWidthShorthandResolver.java new file mode 100644 index 0000000000..914db836bd --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/BorderWidthShorthandResolver.java @@ -0,0 +1,67 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.resolve.shorthand.impl; + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; + +/** + * {@link AbstractBoxShorthandResolver} implementation for border widths. + */ +public class BorderWidthShorthandResolver extends AbstractBoxShorthandResolver { + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.AbstractBoxShorthandResolver#getPrefix() + */ + @Override + protected String getPrefix() { + return CommonCssConstants.BORDER; + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.AbstractBoxShorthandResolver#getPostfix() + */ + @Override + protected String getPostfix() { + return "-width"; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/FontShorthandResolver.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/FontShorthandResolver.java index 28fc6e8e2b..b44edfabe3 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/FontShorthandResolver.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/FontShorthandResolver.java @@ -42,7 +42,7 @@ This file is part of the iText (R) project. */ package com.itextpdf.styledxmlparser.css.resolve.shorthand.impl; -import com.itextpdf.styledxmlparser.css.CssConstants; +import com.itextpdf.styledxmlparser.css.CommonCssConstants; import com.itextpdf.styledxmlparser.css.CssDeclaration; import com.itextpdf.styledxmlparser.css.resolve.shorthand.IShorthandResolver; import com.itextpdf.styledxmlparser.css.util.CssUtils; @@ -59,24 +59,24 @@ public class FontShorthandResolver implements IShorthandResolver { /** Unsupported shorthand values. */ private static final Set UNSUPPORTED_VALUES_OF_FONT_SHORTHAND = new HashSet<>(Arrays.asList( - CssConstants.CAPTION, CssConstants.ICON, CssConstants.MENU, CssConstants.MESSAGE_BOX, - CssConstants.SMALL_CAPTION, CssConstants.STATUS_BAR + CommonCssConstants.CAPTION, CommonCssConstants.ICON, CommonCssConstants.MENU, CommonCssConstants.MESSAGE_BOX, + CommonCssConstants.SMALL_CAPTION, CommonCssConstants.STATUS_BAR )); /** Font weight values. */ private static final Set FONT_WEIGHT_NOT_DEFAULT_VALUES = new HashSet<>(Arrays.asList( - CssConstants.BOLD, CssConstants.BOLDER, CssConstants.LIGHTER, + CommonCssConstants.BOLD, CommonCssConstants.BOLDER, CommonCssConstants.LIGHTER, "100", "200", "300", "400", "500", "600", "700", "800", "900" )); /** Font size values. */ private static final Set FONT_SIZE_VALUES = new HashSet<>(Arrays.asList( - CssConstants.MEDIUM, CssConstants.XX_SMALL, CssConstants.X_SMALL, CssConstants.SMALL, CssConstants.LARGE, - CssConstants.X_LARGE, CssConstants.XX_LARGE, CssConstants.SMALLER, CssConstants.LARGER + CommonCssConstants.MEDIUM, CommonCssConstants.XX_SMALL, CommonCssConstants.X_SMALL, CommonCssConstants.SMALL, CommonCssConstants.LARGE, + CommonCssConstants.X_LARGE, CommonCssConstants.XX_LARGE, CommonCssConstants.SMALLER, CommonCssConstants.LARGER )); /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.resolve.shorthand.IShorthandResolver#resolveShorthand(java.lang.String) + * @see com.itextpdf.styledxmlparser.css.resolve.shorthand.IShorthandResolver#resolveShorthand(java.lang.String) */ @Override public List resolveShorthand(String shorthandExpression) { @@ -84,14 +84,14 @@ public List resolveShorthand(String shorthandExpression) { Logger logger = LoggerFactory.getLogger(FontShorthandResolver.class); logger.error(MessageFormatUtil.format("The \"{0}\" value of CSS shorthand property \"font\" is not supported", shorthandExpression)); } - if (CssConstants.INITIAL.equals(shorthandExpression) || CssConstants.INHERIT.equals(shorthandExpression)) { + if (CommonCssConstants.INITIAL.equals(shorthandExpression) || CommonCssConstants.INHERIT.equals(shorthandExpression)) { return Arrays.asList( - new CssDeclaration(CssConstants.FONT_STYLE, shorthandExpression), - new CssDeclaration(CssConstants.FONT_VARIANT, shorthandExpression), - new CssDeclaration(CssConstants.FONT_WEIGHT, shorthandExpression), - new CssDeclaration(CssConstants.FONT_SIZE, shorthandExpression), - new CssDeclaration(CssConstants.LINE_HEIGHT, shorthandExpression), - new CssDeclaration(CssConstants.FONT_FAMILY, shorthandExpression) + new CssDeclaration(CommonCssConstants.FONT_STYLE, shorthandExpression), + new CssDeclaration(CommonCssConstants.FONT_VARIANT, shorthandExpression), + new CssDeclaration(CommonCssConstants.FONT_WEIGHT, shorthandExpression), + new CssDeclaration(CommonCssConstants.FONT_SIZE, shorthandExpression), + new CssDeclaration(CommonCssConstants.LINE_HEIGHT, shorthandExpression), + new CssDeclaration(CommonCssConstants.FONT_FAMILY, shorthandExpression) ); } @@ -105,9 +105,9 @@ public List resolveShorthand(String shorthandExpression) { List properties = getFontProperties(shorthandExpression.replaceAll("\\s*,\\s*", ",")); for (String value : properties) { int slashSymbolIndex = value.indexOf('/'); - if (CssConstants.ITALIC.equals(value) || CssConstants.OBLIQUE.equals(value)) { + if (CommonCssConstants.ITALIC.equals(value) || CommonCssConstants.OBLIQUE.equals(value)) { fontStyleValue = value; - } else if (CssConstants.SMALL_CAPS.equals(value)) { + } else if (CommonCssConstants.SMALL_CAPS.equals(value)) { fontVariantValue = value; } else if (FONT_WEIGHT_NOT_DEFAULT_VALUES.contains(value)) { fontWeightValue = value; @@ -123,12 +123,12 @@ public List resolveShorthand(String shorthandExpression) { } List cssDeclarations = Arrays.asList( - new CssDeclaration(CssConstants.FONT_STYLE, fontStyleValue == null ? CssConstants.INITIAL : fontStyleValue), - new CssDeclaration(CssConstants.FONT_VARIANT, fontVariantValue == null ? CssConstants.INITIAL : fontVariantValue), - new CssDeclaration(CssConstants.FONT_WEIGHT, fontWeightValue == null ? CssConstants.INITIAL : fontWeightValue), - new CssDeclaration(CssConstants.FONT_SIZE, fontSizeValue == null ? CssConstants.INITIAL : fontSizeValue), - new CssDeclaration(CssConstants.LINE_HEIGHT, lineHeightValue == null ? CssConstants.INITIAL : lineHeightValue), - new CssDeclaration(CssConstants.FONT_FAMILY, fontFamilyValue == null ? CssConstants.INITIAL : fontFamilyValue) + new CssDeclaration(CommonCssConstants.FONT_STYLE, fontStyleValue == null ? CommonCssConstants.INITIAL : fontStyleValue), + new CssDeclaration(CommonCssConstants.FONT_VARIANT, fontVariantValue == null ? CommonCssConstants.INITIAL : fontVariantValue), + new CssDeclaration(CommonCssConstants.FONT_WEIGHT, fontWeightValue == null ? CommonCssConstants.INITIAL : fontWeightValue), + new CssDeclaration(CommonCssConstants.FONT_SIZE, fontSizeValue == null ? CommonCssConstants.INITIAL : fontSizeValue), + new CssDeclaration(CommonCssConstants.LINE_HEIGHT, lineHeightValue == null ? CommonCssConstants.INITIAL : lineHeightValue), + new CssDeclaration(CommonCssConstants.FONT_FAMILY, fontFamilyValue == null ? CommonCssConstants.INITIAL : fontFamilyValue) ); return cssDeclarations; diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/ListStyleShorthandResolver.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/ListStyleShorthandResolver.java new file mode 100644 index 0000000000..ee8639b2b2 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/ListStyleShorthandResolver.java @@ -0,0 +1,103 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.resolve.shorthand.impl; + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; +import com.itextpdf.styledxmlparser.css.CssDeclaration; +import com.itextpdf.styledxmlparser.css.resolve.shorthand.IShorthandResolver; +import java.util.*; + +/** + * {@link IShorthandResolver} implementation for list styles. + */ +public class ListStyleShorthandResolver implements IShorthandResolver { + + /** The list style types (disc, decimal,...). */ + private static final Set LIST_STYLE_TYPE_VALUES = new HashSet<>(Arrays.asList( + CommonCssConstants.DISC, CommonCssConstants.ARMENIAN, CommonCssConstants.CIRCLE, CommonCssConstants.CJK_IDEOGRAPHIC, + CommonCssConstants.DECIMAL, CommonCssConstants.DECIMAL_LEADING_ZERO, CommonCssConstants.GEORGIAN, CommonCssConstants.HEBREW, + CommonCssConstants.HIRAGANA, CommonCssConstants.HIRAGANA_IROHA, CommonCssConstants.LOWER_ALPHA, CommonCssConstants.LOWER_GREEK, + CommonCssConstants.LOWER_LATIN, CommonCssConstants.LOWER_ROMAN, CommonCssConstants.NONE, CommonCssConstants.SQUARE, + CommonCssConstants.UPPER_ALPHA, CommonCssConstants.UPPER_LATIN, CommonCssConstants.UPPER_ROMAN + )); + + /** The list style positions (inside, outside). */ + private static final Set LIST_STYLE_POSITION_VALUES = new HashSet<>(Arrays.asList( + CommonCssConstants.INSIDE, CommonCssConstants.OUTSIDE + )); + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.resolve.shorthand.IShorthandResolver#resolveShorthand(java.lang.String) + */ + @Override + public List resolveShorthand(String shorthandExpression) { + if (CommonCssConstants.INITIAL.equals(shorthandExpression) || CommonCssConstants.INHERIT.equals(shorthandExpression)) { + return Arrays.asList( + new CssDeclaration(CommonCssConstants.LIST_STYLE_TYPE, shorthandExpression), + new CssDeclaration(CommonCssConstants.LIST_STYLE_POSITION, shorthandExpression), + new CssDeclaration(CommonCssConstants.LIST_STYLE_IMAGE, shorthandExpression)); + } + + String[] props = shorthandExpression.split("\\s+"); + + String listStyleTypeValue = null; + String listStylePositionValue = null; + String listStyleImageValue = null; + + for (String value : props) { + if (value.contains("url(") || CommonCssConstants.NONE.equals(value) && listStyleTypeValue != null) { + listStyleImageValue = value; + } else if (LIST_STYLE_TYPE_VALUES.contains(value)) { + listStyleTypeValue = value; + } else if (LIST_STYLE_POSITION_VALUES.contains(value)) { + listStylePositionValue = value; + } + } + + List resolvedDecl = new ArrayList<>(); + resolvedDecl.add(new CssDeclaration(CommonCssConstants.LIST_STYLE_TYPE, listStyleTypeValue == null ? CommonCssConstants.INITIAL : listStyleTypeValue)); + resolvedDecl.add(new CssDeclaration(CommonCssConstants.LIST_STYLE_POSITION, listStylePositionValue == null ? CommonCssConstants.INITIAL : listStylePositionValue)); + resolvedDecl.add(new CssDeclaration(CommonCssConstants.LIST_STYLE_IMAGE, listStyleImageValue == null ? CommonCssConstants.INITIAL : listStyleImageValue)); + return resolvedDecl; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/MarginShorthandResolver.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/MarginShorthandResolver.java new file mode 100644 index 0000000000..8fe931f05a --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/MarginShorthandResolver.java @@ -0,0 +1,67 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.resolve.shorthand.impl; + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; + +/** + * {@link AbstractBoxShorthandResolver} implementation for margins. + */ +public class MarginShorthandResolver extends AbstractBoxShorthandResolver { + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.AbstractBoxShorthandResolver#getPrefix() + */ + @Override + protected String getPrefix() { + return CommonCssConstants.MARGIN; + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.AbstractBoxShorthandResolver#getPostfix() + */ + @Override + protected String getPostfix() { + return ""; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/OutlineShorthandResolver.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/OutlineShorthandResolver.java new file mode 100644 index 0000000000..f898a35201 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/OutlineShorthandResolver.java @@ -0,0 +1,59 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.resolve.shorthand.impl; + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; + +/** + * {@link AbstractBorderShorthandResolver} implementation for outlines. + */ +public class OutlineShorthandResolver extends AbstractBorderShorthandResolver { + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.AbstractBorderShorthandResolver#getPrefix() + */ + @Override + protected String getPrefix() { + return CommonCssConstants.OUTLINE; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/PaddingShorthandResolver.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/PaddingShorthandResolver.java new file mode 100644 index 0000000000..b9b8b2b5d6 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/impl/PaddingShorthandResolver.java @@ -0,0 +1,67 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.resolve.shorthand.impl; + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; + +/** + * {@link AbstractBoxShorthandResolver} implementation for paddings. + */ +public class PaddingShorthandResolver extends AbstractBoxShorthandResolver { + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.AbstractBoxShorthandResolver#getPrefix() + */ + @Override + protected String getPrefix() { + return CommonCssConstants.PADDING; + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.resolve.shorthand.impl.AbstractBoxShorthandResolver#getPostfix() + */ + @Override + protected String getPostfix() { + return ""; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/AbstractCssSelector.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/AbstractCssSelector.java index 3a3188c2f4..e58c110e41 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/selector/AbstractCssSelector.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/AbstractCssSelector.java @@ -54,7 +54,7 @@ This file is part of the iText (R) project. public abstract class AbstractCssSelector implements ICssSelector { /** The selector items. */ - List selectorItems; + protected List selectorItems; /** * Creates a new {@link AbstractCssSelector} instance. @@ -70,7 +70,7 @@ public List getSelectorItems() { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.selector.ICssSelector#calculateSpecificity() + * @see com.itextpdf.styledxmlparser.css.selector.ICssSelector#calculateSpecificity() */ @Override public int calculateSpecificity() { diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/CssPageMarginBoxSelector.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/CssPageMarginBoxSelector.java new file mode 100644 index 0000000000..f66363dcd9 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/CssPageMarginBoxSelector.java @@ -0,0 +1,93 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.selector; + +import com.itextpdf.styledxmlparser.css.page.PageMarginBoxContextNode; +import com.itextpdf.styledxmlparser.node.INode; + +/** + * {@link ICssSelector} implementation for CSS page margin box selectors. + */ +public class CssPageMarginBoxSelector implements ICssSelector { + + /** The page margin box name. */ + private String pageMarginBoxName; + + /** The page selector. */ + private ICssSelector pageSelector; + + /** + * Creates a new {@link CssPageMarginBoxSelector} instance. + * + * @param pageMarginBoxName the page margin box name + * @param pageSelector the page selector + */ + public CssPageMarginBoxSelector(String pageMarginBoxName, ICssSelector pageSelector) { + this.pageMarginBoxName = pageMarginBoxName; + this.pageSelector = pageSelector; + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.selector.ICssSelector#calculateSpecificity() + */ + @Override + public int calculateSpecificity() { + return pageSelector.calculateSpecificity(); + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.selector.ICssSelector#matches(com.itextpdf.styledxmlparser.html.node.INode) + */ + @Override + public boolean matches(INode node) { + if (!(node instanceof PageMarginBoxContextNode)) { + return false; + } + PageMarginBoxContextNode marginBoxNode = (PageMarginBoxContextNode) node; + if (pageMarginBoxName.equals(marginBoxNode.getMarginBoxName())) { + INode parent = node.parentNode(); + return pageSelector.matches(parent); + } + return false; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/CssPageSelector.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/CssPageSelector.java new file mode 100644 index 0000000000..79a2251772 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/CssPageSelector.java @@ -0,0 +1,80 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.selector; + +import com.itextpdf.styledxmlparser.css.page.PageContextNode; +import com.itextpdf.styledxmlparser.css.parse.CssPageSelectorParser; +import com.itextpdf.styledxmlparser.css.selector.item.ICssSelectorItem; +import com.itextpdf.styledxmlparser.node.INode; + +/** + * {@link ICssSelector} implementation for CSS page selectors. + */ +public class CssPageSelector extends AbstractCssSelector { + + /** + * Creates a new {@link CssPageSelector} instance. + * + * @param pageSelectorStr the page selector + */ + public CssPageSelector(String pageSelectorStr) { + super(CssPageSelectorParser.parseSelectorItems(pageSelectorStr)); + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.selector.ICssSelector#matches(com.itextpdf.styledxmlparser.html.node.INode) + */ + @Override + public boolean matches(INode node) { + if (!(node instanceof PageContextNode)) { + return false; + } + + for (ICssSelectorItem selectorItem : selectorItems) { + if (!selectorItem.matches(node)) { + return false; + } + } + return true; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/CssSelector.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/CssSelector.java index c93958281f..5b3a8f7363 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/selector/CssSelector.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/CssSelector.java @@ -44,6 +44,8 @@ This file is part of the iText (R) project. import com.itextpdf.styledxmlparser.css.parse.CssSelectorParser; +import com.itextpdf.styledxmlparser.css.pseudo.CssPseudoElementNode; +import com.itextpdf.styledxmlparser.css.selector.item.CssPseudoElementSelectorItem; import com.itextpdf.styledxmlparser.css.selector.item.CssSeparatorSelectorItem; import com.itextpdf.styledxmlparser.css.selector.item.ICssSelectorItem; import com.itextpdf.styledxmlparser.node.IElementNode; @@ -75,7 +77,7 @@ public CssSelector(String selector) { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.selector.ICssSelector#matches(com.itextpdf.html2pdf.html.node.INode) + * @see com.itextpdf.styledxmlparser.css.selector.ICssSelector#matches(com.itextpdf.styledxmlparser.html.node.INode) */ public boolean matches(INode element) { return matches(element, selectorItems.size() - 1); @@ -96,9 +98,8 @@ private boolean matches(INode element, int lastSelectorItemInd) { return true; } //TODO: Consider pseudo-elements in SVG - //boolean isPseudoElement = element instanceof CssPseudoElementNode; + boolean isPseudoElement = element instanceof CssPseudoElementNode; for (int i = lastSelectorItemInd; i >= 0; i--) { - /* if (isPseudoElement && selectorItems.get(lastSelectorItemInd) instanceof CssPseudoElementSelectorItem && i < lastSelectorItemInd) { // Pseudo element selector item shall be at the end of the selector string // and be single pseudo element selector item in it. All other selector items are checked against @@ -106,7 +107,6 @@ private boolean matches(INode element, int lastSelectorItemInd) { element = element.parentNode(); isPseudoElement = false; } - */ ICssSelectorItem currentItem = selectorItems.get(i); if (currentItem instanceof CssSeparatorSelectorItem) { char separator = ((CssSeparatorSelectorItem) currentItem).getSeparator(); diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssAttributeSelectorItem.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssAttributeSelectorItem.java index 42922b8a7a..6c45b52ea3 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssAttributeSelectorItem.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssAttributeSelectorItem.java @@ -90,7 +90,7 @@ public CssAttributeSelectorItem(String attrSelector) { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.selector.item.ICssSelectorItem#getSpecificity() + * @see com.itextpdf.styledxmlparser.css.selector.item.ICssSelectorItem#getSpecificity() */ @Override public int getSpecificity() { @@ -98,7 +98,7 @@ public int getSpecificity() { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.selector.item.ICssSelectorItem#matches(com.itextpdf.html2pdf.html.node.INode) + * @see com.itextpdf.styledxmlparser.css.selector.item.ICssSelectorItem#matches(com.itextpdf.styledxmlparser.html.node.INode) */ @Override public boolean matches(INode node) { diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssClassSelectorItem.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssClassSelectorItem.java index 5df33e0a6b..9fad943e96 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssClassSelectorItem.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssClassSelectorItem.java @@ -43,7 +43,7 @@ This file is part of the iText (R) project. package com.itextpdf.styledxmlparser.css.selector.item; -import com.itextpdf.styledxmlparser.AttributeConstants; +import com.itextpdf.styledxmlparser.CommonAttributeConstants; import com.itextpdf.styledxmlparser.node.ICustomElementNode; import com.itextpdf.styledxmlparser.node.IDocumentNode; import com.itextpdf.styledxmlparser.node.IElementNode; @@ -67,7 +67,7 @@ public CssClassSelectorItem(String className) { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.selector.item.ICssSelectorItem#getSpecificity() + * @see com.itextpdf.styledxmlparser.css.selector.item.ICssSelectorItem#getSpecificity() */ @Override public int getSpecificity() { @@ -83,7 +83,7 @@ public String toString() { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.selector.item.ICssSelectorItem#matches(com.itextpdf.html2pdf.html.node.INode) + * @see com.itextpdf.styledxmlparser.css.selector.item.ICssSelectorItem#matches(com.itextpdf.styledxmlparser.html.node.INode) */ @Override public boolean matches(INode node) { @@ -91,7 +91,7 @@ public boolean matches(INode node) { return false; } IElementNode element = (IElementNode) node; - String classAttr = element.getAttribute(AttributeConstants.CLASS); + String classAttr = element.getAttribute(CommonAttributeConstants.CLASS); if (classAttr != null && classAttr.length() > 0) { String[] classNames = classAttr.split(" "); for (String currClassName: classNames) diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssIdSelectorItem.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssIdSelectorItem.java index 85ca681e93..a5ac12e790 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssIdSelectorItem.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssIdSelectorItem.java @@ -42,7 +42,7 @@ This file is part of the iText (R) project. */ package com.itextpdf.styledxmlparser.css.selector.item; -import com.itextpdf.styledxmlparser.AttributeConstants; +import com.itextpdf.styledxmlparser.CommonAttributeConstants; import com.itextpdf.styledxmlparser.node.ICustomElementNode; import com.itextpdf.styledxmlparser.node.IDocumentNode; import com.itextpdf.styledxmlparser.node.IElementNode; @@ -66,7 +66,7 @@ public CssIdSelectorItem(String id) { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.selector.item.ICssSelectorItem#getSpecificity() + * @see com.itextpdf.styledxmlparser.css.selector.item.ICssSelectorItem#getSpecificity() */ @Override public int getSpecificity() { @@ -74,7 +74,7 @@ public int getSpecificity() { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.selector.item.ICssSelectorItem#matches(com.itextpdf.html2pdf.html.node.INode) + * @see com.itextpdf.styledxmlparser.css.selector.item.ICssSelectorItem#matches(com.itextpdf.styledxmlparser.html.node.INode) */ @Override public boolean matches(INode node) { @@ -82,7 +82,7 @@ public boolean matches(INode node) { return false; } IElementNode element = (IElementNode) node; - return id.equals(element.getAttribute(AttributeConstants.ID)); + return id.equals(element.getAttribute(CommonAttributeConstants.ID)); } /* (non-Javadoc) diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPagePseudoClassSelectorItem.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPagePseudoClassSelectorItem.java new file mode 100644 index 0000000000..bac511aa38 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPagePseudoClassSelectorItem.java @@ -0,0 +1,88 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.selector.item; + +import com.itextpdf.styledxmlparser.css.page.PageContextConstants; +import com.itextpdf.styledxmlparser.css.page.PageContextNode; +import com.itextpdf.styledxmlparser.node.INode; + +/** + * {@link ICssSelectorItem} implementation for page pseudo classes selectors. + */ +public class CssPagePseudoClassSelectorItem implements ICssSelectorItem { + + /** Indicates if the page pseudo class is a spread pseudo class (left or right). */ + private boolean isSpreadPseudoClass; + + /** The page pseudo class. */ + private String pagePseudoClass; + + /** + * Creates a new {@link CssPagePseudoClassSelectorItem} instance. + * + * @param pagePseudoClass the page pseudo class name + */ + public CssPagePseudoClassSelectorItem(String pagePseudoClass) { + this.isSpreadPseudoClass = pagePseudoClass.equals(PageContextConstants.LEFT) || pagePseudoClass.equals(PageContextConstants.RIGHT); + this.pagePseudoClass = pagePseudoClass; + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.selector.item.ICssSelectorItem#getSpecificity() + */ + @Override + public int getSpecificity() { + return isSpreadPseudoClass ? CssSpecificityConstants.ELEMENT_SPECIFICITY : CssSpecificityConstants.CLASS_SPECIFICITY; + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.selector.item.ICssSelectorItem#matches(com.itextpdf.styledxmlparser.html.node.INode) + */ + @Override + public boolean matches(INode node) { + if (!(node instanceof PageContextNode)) { + return false; + } + return ((PageContextNode) node).getPageClasses().contains(pagePseudoClass); + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPageTypeSelectorItem.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPageTypeSelectorItem.java new file mode 100644 index 0000000000..0d8de68cbf --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPageTypeSelectorItem.java @@ -0,0 +1,84 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.selector.item; + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; +import com.itextpdf.styledxmlparser.css.page.PageContextNode; +import com.itextpdf.styledxmlparser.node.INode; + +/** + * {@link ICssSelectorItem} implementation for page type selectors. + */ +public class CssPageTypeSelectorItem implements ICssSelectorItem { + + /** The page type name. */ + private String pageTypeName; + + /** + * Creates a new {@link CssPageTypeSelectorItem} instance. + * + * @param pageTypeName the page type name + */ + public CssPageTypeSelectorItem(String pageTypeName) { + this.pageTypeName = pageTypeName; + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.selector.item.ICssSelectorItem#getSpecificity() + */ + @Override + public int getSpecificity() { + return CssSpecificityConstants.ID_SPECIFICITY; + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.selector.item.ICssSelectorItem#matches(com.itextpdf.styledxmlparser.html.node.INode) + */ + @Override + public boolean matches(INode node) { + if (!(node instanceof PageContextNode)) { + return false; + } + return !CommonCssConstants.AUTO.equals(pageTypeName.toLowerCase()) && pageTypeName.equals(((PageContextNode) node).getPageTypeName()); + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassChildSelectorItem.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassChildSelectorItem.java new file mode 100644 index 0000000000..ff431abe8e --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassChildSelectorItem.java @@ -0,0 +1,63 @@ +package com.itextpdf.styledxmlparser.css.selector.item; + +import com.itextpdf.styledxmlparser.node.IElementNode; +import com.itextpdf.styledxmlparser.node.INode; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +class CssPseudoClassChildSelectorItem extends CssPseudoClassSelectorItem { + + /** + * Creates a new {@link CssPseudoClassSelectorItem} instance. + * + * @param pseudoClass the pseudo class name + */ + CssPseudoClassChildSelectorItem(String pseudoClass) { + super(pseudoClass); + } + + CssPseudoClassChildSelectorItem(String pseudoClass, String arguments) { + super(pseudoClass, arguments); + } + + /** + * Gets the all the siblings of a child node. + * + * @param node the child node + * @return the sibling nodes + */ + List getAllSiblings(INode node) { + INode parentElement = node.parentNode(); + if (parentElement != null) { + List childrenUnmodifiable = parentElement.childNodes(); + List children = new ArrayList(childrenUnmodifiable.size()); + for (INode iNode : childrenUnmodifiable) { + if (iNode instanceof IElementNode) + children.add(iNode); + } + return children; + } + return Collections.emptyList(); + } + + /** + * Gets all siblings of a child node with the type of a child node. + * + * @param node the child node + * @return the sibling nodes with the type of a child node + */ + List getAllSiblingsOfNodeType(INode node) { + INode parentElement = node.parentNode(); + if (parentElement != null) { + List childrenUnmodifiable = parentElement.childNodes(); + List children = new ArrayList(childrenUnmodifiable.size()); + for (INode iNode : childrenUnmodifiable) { + if (iNode instanceof IElementNode && ((IElementNode) iNode).name().equals(((IElementNode) node).name())) + children.add(iNode); + } + return children; + } + return Collections.emptyList(); + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassEmptySelectorItem.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassEmptySelectorItem.java new file mode 100644 index 0000000000..4ff0117987 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassEmptySelectorItem.java @@ -0,0 +1,36 @@ +package com.itextpdf.styledxmlparser.css.selector.item; + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; +import com.itextpdf.styledxmlparser.node.ICustomElementNode; +import com.itextpdf.styledxmlparser.node.IDocumentNode; +import com.itextpdf.styledxmlparser.node.IElementNode; +import com.itextpdf.styledxmlparser.node.INode; +import com.itextpdf.styledxmlparser.node.ITextNode; + +class CssPseudoClassEmptySelectorItem extends CssPseudoClassSelectorItem { + private static final CssPseudoClassEmptySelectorItem instance = new CssPseudoClassEmptySelectorItem(); + + private CssPseudoClassEmptySelectorItem() { + super(CommonCssConstants.EMPTY); + } + + public static CssPseudoClassEmptySelectorItem getInstance() { + return instance; + } + + @Override + public boolean matches(INode node) { + if (!(node instanceof IElementNode) || node instanceof ICustomElementNode || node instanceof IDocumentNode) { + return false; + } + if (node.childNodes().isEmpty()) { + return true; + } + for (INode childNode : node.childNodes()) { + if (!(childNode instanceof ITextNode) || !((ITextNode) childNode).wholeText().isEmpty()) { + return false; + } + } + return true; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassFirstChildSelectorItem.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassFirstChildSelectorItem.java new file mode 100644 index 0000000000..eb4a7c5025 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassFirstChildSelectorItem.java @@ -0,0 +1,29 @@ +package com.itextpdf.styledxmlparser.css.selector.item; + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; +import com.itextpdf.styledxmlparser.node.ICustomElementNode; +import com.itextpdf.styledxmlparser.node.IDocumentNode; +import com.itextpdf.styledxmlparser.node.IElementNode; +import com.itextpdf.styledxmlparser.node.INode; +import java.util.List; + +class CssPseudoClassFirstChildSelectorItem extends CssPseudoClassChildSelectorItem { + private static final CssPseudoClassFirstChildSelectorItem instance = new CssPseudoClassFirstChildSelectorItem(); + + private CssPseudoClassFirstChildSelectorItem() { + super(CommonCssConstants.FIRST_CHILD); + } + + public static CssPseudoClassFirstChildSelectorItem getInstance() { + return instance; + } + + @Override + public boolean matches(INode node) { + if (!(node instanceof IElementNode) || node instanceof ICustomElementNode || node instanceof IDocumentNode) { + return false; + } + List children = getAllSiblings(node); + return !children.isEmpty() && node.equals(children.get(0)); + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassFirstOfTypeSelectorItem.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassFirstOfTypeSelectorItem.java new file mode 100644 index 0000000000..9ee92c1662 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassFirstOfTypeSelectorItem.java @@ -0,0 +1,29 @@ +package com.itextpdf.styledxmlparser.css.selector.item; + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; +import com.itextpdf.styledxmlparser.node.ICustomElementNode; +import com.itextpdf.styledxmlparser.node.IDocumentNode; +import com.itextpdf.styledxmlparser.node.IElementNode; +import com.itextpdf.styledxmlparser.node.INode; +import java.util.List; + +class CssPseudoClassFirstOfTypeSelectorItem extends CssPseudoClassChildSelectorItem { + private static final CssPseudoClassFirstOfTypeSelectorItem instance = new CssPseudoClassFirstOfTypeSelectorItem(); + + private CssPseudoClassFirstOfTypeSelectorItem() { + super(CommonCssConstants.FIRST_OF_TYPE); + } + + public static CssPseudoClassFirstOfTypeSelectorItem getInstance() { + return instance; + } + + @Override + public boolean matches(INode node) { + if (!(node instanceof IElementNode) || node instanceof ICustomElementNode || node instanceof IDocumentNode) { + return false; + } + List children = getAllSiblingsOfNodeType(node); + return !children.isEmpty() && node.equals(children.get(0)); + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassLastChildSelectorItem.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassLastChildSelectorItem.java new file mode 100644 index 0000000000..54bd0911b6 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassLastChildSelectorItem.java @@ -0,0 +1,29 @@ +package com.itextpdf.styledxmlparser.css.selector.item; + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; +import com.itextpdf.styledxmlparser.node.ICustomElementNode; +import com.itextpdf.styledxmlparser.node.IDocumentNode; +import com.itextpdf.styledxmlparser.node.IElementNode; +import com.itextpdf.styledxmlparser.node.INode; +import java.util.List; + +class CssPseudoClassLastChildSelectorItem extends CssPseudoClassChildSelectorItem { + private static final CssPseudoClassLastChildSelectorItem instance = new CssPseudoClassLastChildSelectorItem(); + + private CssPseudoClassLastChildSelectorItem() { + super(CommonCssConstants.LAST_CHILD); + } + + public static CssPseudoClassLastChildSelectorItem getInstance() { + return instance; + } + + @Override + public boolean matches(INode node) { + if (!(node instanceof IElementNode) || node instanceof ICustomElementNode || node instanceof IDocumentNode) { + return false; + } + List children = getAllSiblings(node); + return !children.isEmpty() && node.equals(children.get(children.size() - 1)); + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassLastOfTypeSelectorItem.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassLastOfTypeSelectorItem.java new file mode 100644 index 0000000000..f2bf714123 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassLastOfTypeSelectorItem.java @@ -0,0 +1,29 @@ +package com.itextpdf.styledxmlparser.css.selector.item; + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; +import com.itextpdf.styledxmlparser.node.ICustomElementNode; +import com.itextpdf.styledxmlparser.node.IDocumentNode; +import com.itextpdf.styledxmlparser.node.IElementNode; +import com.itextpdf.styledxmlparser.node.INode; +import java.util.List; + +class CssPseudoClassLastOfTypeSelectorItem extends CssPseudoClassChildSelectorItem { + private static final CssPseudoClassLastOfTypeSelectorItem instance = new CssPseudoClassLastOfTypeSelectorItem(); + + private CssPseudoClassLastOfTypeSelectorItem() { + super(CommonCssConstants.LAST_OF_TYPE); + } + + public static CssPseudoClassLastOfTypeSelectorItem getInstance() { + return instance; + } + + @Override + public boolean matches(INode node) { + if (!(node instanceof IElementNode) || node instanceof ICustomElementNode || node instanceof IDocumentNode) { + return false; + } + List children = getAllSiblingsOfNodeType(node); + return !children.isEmpty() && node.equals(children.get(children.size() - 1)); + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassNotSelectorItem.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassNotSelectorItem.java new file mode 100644 index 0000000000..1078af3bb8 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassNotSelectorItem.java @@ -0,0 +1,32 @@ +package com.itextpdf.styledxmlparser.css.selector.item; + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; +import com.itextpdf.styledxmlparser.css.parse.CssSelectorParser; +import com.itextpdf.styledxmlparser.css.selector.ICssSelector; +import com.itextpdf.styledxmlparser.node.ICustomElementNode; +import com.itextpdf.styledxmlparser.node.IDocumentNode; +import com.itextpdf.styledxmlparser.node.IElementNode; +import com.itextpdf.styledxmlparser.node.INode; + +import java.util.List; + +class CssPseudoClassNotSelectorItem extends CssPseudoClassSelectorItem { + private ICssSelector argumentsSelector; + + CssPseudoClassNotSelectorItem(ICssSelector argumentsSelector) { + super(CommonCssConstants.NOT, argumentsSelector.toString()); + this.argumentsSelector = argumentsSelector; + } + + public List getArgumentsSelector() { + return CssSelectorParser.parseSelectorItems(arguments); + } + + @Override + public boolean matches(INode node) { + if (!(node instanceof IElementNode) || node instanceof ICustomElementNode || node instanceof IDocumentNode) { + return false; + } + return !argumentsSelector.matches(node); + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassNthChildSelectorItem.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassNthChildSelectorItem.java new file mode 100644 index 0000000000..2d6217294a --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassNthChildSelectorItem.java @@ -0,0 +1,10 @@ +package com.itextpdf.styledxmlparser.css.selector.item; + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; + +class CssPseudoClassNthChildSelectorItem extends CssPseudoClassNthSelectorItem { + + CssPseudoClassNthChildSelectorItem(String arguments) { + super(CommonCssConstants.NTH_CHILD, arguments); + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassNthOfTypeSelectorItem.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassNthOfTypeSelectorItem.java new file mode 100644 index 0000000000..60fd7b7f51 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassNthOfTypeSelectorItem.java @@ -0,0 +1,24 @@ +package com.itextpdf.styledxmlparser.css.selector.item; + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; +import com.itextpdf.styledxmlparser.node.ICustomElementNode; +import com.itextpdf.styledxmlparser.node.IDocumentNode; +import com.itextpdf.styledxmlparser.node.IElementNode; +import com.itextpdf.styledxmlparser.node.INode; +import java.util.List; + +class CssPseudoClassNthOfTypeSelectorItem extends CssPseudoClassNthSelectorItem { + + public CssPseudoClassNthOfTypeSelectorItem(String arguments) { + super(CommonCssConstants.NTH_OF_TYPE, arguments); + } + + @Override + public boolean matches(INode node) { + if (!(node instanceof IElementNode) || node instanceof ICustomElementNode || node instanceof IDocumentNode) { + return false; + } + List children = getAllSiblingsOfNodeType(node); + return !children.isEmpty() && resolveNth(node, children); + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassNthSelectorItem.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassNthSelectorItem.java new file mode 100644 index 0000000000..41d695dd73 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassNthSelectorItem.java @@ -0,0 +1,90 @@ +package com.itextpdf.styledxmlparser.css.selector.item; + +import com.itextpdf.styledxmlparser.node.ICustomElementNode; +import com.itextpdf.styledxmlparser.node.IDocumentNode; +import com.itextpdf.styledxmlparser.node.IElementNode; +import com.itextpdf.styledxmlparser.node.INode; +import java.util.List; + +class CssPseudoClassNthSelectorItem extends CssPseudoClassChildSelectorItem { + /** + * The nth A. + */ + private int nthA; + + /** + * The nth B. + */ + private int nthB; + + CssPseudoClassNthSelectorItem(String pseudoClass, String arguments) { + super(pseudoClass, arguments); + getNthArguments(); + } + + @Override + public boolean matches(INode node) { + if (!(node instanceof IElementNode) || node instanceof ICustomElementNode || node instanceof IDocumentNode) { + return false; + } + List children = getAllSiblings(node); + return !children.isEmpty() && resolveNth(node, children); + } + + /** + * Gets the nth arguments. + */ + protected void getNthArguments() { + if (arguments.matches("((-|\\+)?[0-9]*n(\\s*(-|\\+)\\s*[0-9]+)?|(-|\\+)?[0-9]+|odd|even)")) { + if (arguments.equals("odd")) { + this.nthA = 2; + this.nthB = 1; + } else if (arguments.equals("even")) { + this.nthA = 2; + this.nthB = 0; + } else { + int indexOfN = arguments.indexOf('n'); + if (indexOfN == -1) { + this.nthA = 0; + this.nthB = Integer.valueOf(arguments); + } else { + String aParticle = arguments.substring(0, indexOfN).trim(); + if (aParticle.isEmpty()) + this.nthA = 0; + else if (aParticle.length() == 1 && !Character.isDigit(aParticle.charAt(0))) + this.nthA = aParticle.equals("+") ? 1 : -1; + else + this.nthA = Integer.valueOf(aParticle); + String bParticle = arguments.substring(indexOfN + 1).trim(); + if (!bParticle.isEmpty()) + this.nthB = Integer.valueOf(bParticle.charAt(0) + bParticle.substring(1).trim()); + else + this.nthB = 0; + } + } + } else { + this.nthA = 0; + this.nthB = 0; + } + } + + /** + * Resolves the nth. + * + * @param node a node + * @param children the children + * @return true, if successful + */ + protected boolean resolveNth(INode node, List children) { + if (!children.contains(node)) + return false; + if (this.nthA > 0) { + int temp = children.indexOf(node) + 1 - this.nthB; + return temp >= 0 && temp % this.nthA == 0; + } else if (this.nthA < 0) { + int temp = children.indexOf(node) + 1 - this.nthB; + return temp <= 0 && temp % this.nthA == 0; + } else + return (children.indexOf(node) + 1) - this.nthB == 0; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassRootSelectorItem.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassRootSelectorItem.java new file mode 100644 index 0000000000..73e97f7fa4 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassRootSelectorItem.java @@ -0,0 +1,28 @@ +package com.itextpdf.styledxmlparser.css.selector.item; + + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; +import com.itextpdf.styledxmlparser.node.ICustomElementNode; +import com.itextpdf.styledxmlparser.node.IDocumentNode; +import com.itextpdf.styledxmlparser.node.IElementNode; +import com.itextpdf.styledxmlparser.node.INode; + +class CssPseudoClassRootSelectorItem extends CssPseudoClassSelectorItem { + private static final CssPseudoClassRootSelectorItem instance = new CssPseudoClassRootSelectorItem(); + + private CssPseudoClassRootSelectorItem() { + super(CommonCssConstants.ROOT); + } + + public static CssPseudoClassRootSelectorItem getInstance() { + return instance; + } + + @Override + public boolean matches(INode node) { + if (!(node instanceof IElementNode) || node instanceof ICustomElementNode || node instanceof IDocumentNode) { + return false; + } + return node.parentNode() instanceof IDocumentNode; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassSelectorItem.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassSelectorItem.java new file mode 100644 index 0000000000..7d903068b1 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassSelectorItem.java @@ -0,0 +1,196 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.selector.item; + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; +import com.itextpdf.styledxmlparser.css.selector.CssSelector; +import com.itextpdf.styledxmlparser.node.INode; + +/** + * {@link ICssSelectorItem} implementation for pseudo class selectors. + */ +public abstract class CssPseudoClassSelectorItem implements ICssSelectorItem { + + /** + * The arguments. + */ + protected String arguments; + /** + * The pseudo class. + */ + private String pseudoClass; + + /** + * Creates a new {@link CssPseudoClassSelectorItem} instance. + * + * @param pseudoClass the pseudo class name + */ + protected CssPseudoClassSelectorItem(String pseudoClass) { + this(pseudoClass, ""); + } + + protected CssPseudoClassSelectorItem(String pseudoClass, String arguments) { + this.pseudoClass = pseudoClass; + this.arguments = arguments; + } + + public static CssPseudoClassSelectorItem create(String fullSelectorString) { + int indexOfParentheses = fullSelectorString.indexOf('('); + String pseudoClass; + String arguments; + if (indexOfParentheses == -1) { + pseudoClass = fullSelectorString; + arguments = ""; + } else { + pseudoClass = fullSelectorString.substring(0, indexOfParentheses); + arguments = fullSelectorString.substring(indexOfParentheses + 1, fullSelectorString.length() - 1).trim(); + } + return create(pseudoClass, arguments); + } + + public static CssPseudoClassSelectorItem create(String pseudoClass, String arguments) { + switch (pseudoClass) { + case CommonCssConstants.EMPTY: + return CssPseudoClassEmptySelectorItem.getInstance(); + case CommonCssConstants.FIRST_CHILD: + return CssPseudoClassFirstChildSelectorItem.getInstance(); + case CommonCssConstants.FIRST_OF_TYPE: + return CssPseudoClassFirstOfTypeSelectorItem.getInstance(); + case CommonCssConstants.LAST_CHILD: + return CssPseudoClassLastChildSelectorItem.getInstance(); + case CommonCssConstants.LAST_OF_TYPE: + return CssPseudoClassLastOfTypeSelectorItem.getInstance(); + case CommonCssConstants.NTH_CHILD: + return new CssPseudoClassNthChildSelectorItem(arguments); + case CommonCssConstants.NTH_OF_TYPE: + return new CssPseudoClassNthOfTypeSelectorItem(arguments); + case CommonCssConstants.NOT: + CssSelector selector = new CssSelector(arguments); + for (ICssSelectorItem item : selector.getSelectorItems()) { + if (item instanceof CssPseudoClassNotSelectorItem || item instanceof CssPseudoElementSelectorItem) { + return null; + } + } + return new CssPseudoClassNotSelectorItem(selector); + case CommonCssConstants.ROOT: + return CssPseudoClassRootSelectorItem.getInstance(); + case CommonCssConstants.LINK: + return new AlwaysApplySelectorItem(pseudoClass, arguments); + case CommonCssConstants.ACTIVE: + case CommonCssConstants.FOCUS: + case CommonCssConstants.HOVER: + case CommonCssConstants.TARGET: + case CommonCssConstants.VISITED: + return new AlwaysNotApplySelectorItem(pseudoClass, arguments); + //Still unsupported, should be addressed in DEVSIX-1440 + //case CommonCssConstants.CHECKED: + //case CommonCssConstants.DISABLED: + //case CommonCssConstants.ENABLED: + //case CommonCssConstants.IN_RANGE: + //case CommonCssConstants.INVALID: + //case CommonCssConstants.LANG: + //case CommonCssConstants.NTH_LAST_CHILD: + //case CommonCssConstants.NTH_LAST_OF_TYPE: + //case CommonCssConstants.ONLY_OF_TYPE: + //case CommonCssConstants.ONLY_CHILD: + //case CommonCssConstants.OPTIONAL: + //case CommonCssConstants.OUT_OF_RANGE: + //case CommonCssConstants.READ_ONLY: + //case CommonCssConstants.READ_WRITE: + //case CommonCssConstants.REQUIRED: + //case CommonCssConstants.VALID: + default: + return null; + } + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.selector.item.ICssSelectorItem#getSpecificity() + */ + @Override + public int getSpecificity() { + return CssSpecificityConstants.CLASS_SPECIFICITY; + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.selector.item.ICssSelectorItem#matches(com.itextpdf.styledxmlparser.html.node.INode) + */ + @Override + public boolean matches(INode node) { + return false; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return ":" + pseudoClass + (!arguments.isEmpty() ? "(" + arguments + ")" : ""); + } + + public String getPseudoClass() { + return pseudoClass; + } + + private static class AlwaysApplySelectorItem extends CssPseudoClassSelectorItem { + AlwaysApplySelectorItem(String pseudoClass, String arguments) { + super(pseudoClass, arguments); + } + + @Override + public boolean matches(INode node) { + return true; + } + } + + private static class AlwaysNotApplySelectorItem extends CssPseudoClassSelectorItem { + AlwaysNotApplySelectorItem(String pseudoClass, String arguments) { + super(pseudoClass, arguments); + } + + @Override + public boolean matches(INode node) { + return false; + } + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoElementSelectorItem.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoElementSelectorItem.java new file mode 100644 index 0000000000..97c3e805e2 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoElementSelectorItem.java @@ -0,0 +1,89 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.styledxmlparser.css.selector.item; + +import com.itextpdf.styledxmlparser.css.pseudo.CssPseudoElementNode; +import com.itextpdf.styledxmlparser.node.INode; + + +/** + * {@link ICssSelectorItem} implementation for pseudo element selectors. + */ +public class CssPseudoElementSelectorItem implements com.itextpdf.styledxmlparser.css.selector.item.ICssSelectorItem { + + /** The pseudo element name. */ + private String pseudoElementName; + + /** + * Creates a new {@link CssPseudoElementSelectorItem} instance. + * + * @param pseudoElementName the pseudo element name + */ + public CssPseudoElementSelectorItem(String pseudoElementName) { + this.pseudoElementName = pseudoElementName; + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.selector.item.ICssSelectorItem#getSpecificity() + */ + @Override + public int getSpecificity() { + return CssSpecificityConstants.ELEMENT_SPECIFICITY; + } + + /* (non-Javadoc) + * @see com.itextpdf.styledxmlparser.css.selector.item.ICssSelectorItem#matches(com.itextpdf.styledxmlparser.html.node.INode) + */ + @Override + public boolean matches(INode node) { + return node instanceof CssPseudoElementNode && ((CssPseudoElementNode) node).getPseudoElementName().equals(pseudoElementName); + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "::" + pseudoElementName; + } +} diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssSeparatorSelectorItem.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssSeparatorSelectorItem.java index d4c8ca97b0..c175452563 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssSeparatorSelectorItem.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssSeparatorSelectorItem.java @@ -63,7 +63,7 @@ public CssSeparatorSelectorItem(char separator) { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.selector.item.ICssSelectorItem#getSpecificity() + * @see com.itextpdf.styledxmlparser.css.selector.item.ICssSelectorItem#getSpecificity() */ @Override public int getSpecificity() { @@ -71,7 +71,7 @@ public int getSpecificity() { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.selector.item.ICssSelectorItem#matches(com.itextpdf.html2pdf.html.node.INode) + * @see com.itextpdf.styledxmlparser.css.selector.item.ICssSelectorItem#matches(com.itextpdf.styledxmlparser.html.node.INode) */ @Override public boolean matches(INode node) { diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssTagSelectorItem.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssTagSelectorItem.java index 7b827d73e0..da59c2b654 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssTagSelectorItem.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssTagSelectorItem.java @@ -70,7 +70,7 @@ public CssTagSelectorItem(String tagName) { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.selector.item.ICssSelectorItem#getSpecificity() + * @see com.itextpdf.styledxmlparser.css.selector.item.ICssSelectorItem#getSpecificity() */ @Override public int getSpecificity() { @@ -78,7 +78,7 @@ public int getSpecificity() { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.selector.item.ICssSelectorItem#matches(com.itextpdf.html2pdf.html.node.INode) + * @see com.itextpdf.styledxmlparser.css.selector.item.ICssSelectorItem#matches(com.itextpdf.styledxmlparser.html.node.INode) */ @Override public boolean matches(INode node) { diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/package-info.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/package-info.java new file mode 100644 index 0000000000..4672cd9d4a --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/package-info.java @@ -0,0 +1 @@ +package com.itextpdf.styledxmlparser.css.selector.item; \ No newline at end of file diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/package-info.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/package-info.java new file mode 100644 index 0000000000..0184028206 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/package-info.java @@ -0,0 +1 @@ +package com.itextpdf.styledxmlparser.css.selector; \ No newline at end of file diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/util/CssUtils.java b/src/main/java/com/itextpdf/styledxmlparser/css/util/CssUtils.java index 105d4728cf..0bd34ba972 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/util/CssUtils.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/util/CssUtils.java @@ -43,8 +43,10 @@ This file is part of the iText (R) project. package com.itextpdf.styledxmlparser.css.util; import com.itextpdf.io.util.MessageFormatUtil; +import com.itextpdf.kernel.colors.WebColors; +import com.itextpdf.layout.property.UnitValue; import com.itextpdf.styledxmlparser.LogMessageConstant; -import com.itextpdf.styledxmlparser.css.CssConstants; +import com.itextpdf.styledxmlparser.css.CommonCssConstants; import com.itextpdf.styledxmlparser.exceptions.StyledXMLParserException; import org.slf4j.Logger; @@ -55,8 +57,8 @@ This file is part of the iText (R) project. */ public class CssUtils { - private static final String[] METRIC_MEASUREMENTS = new String[]{CssConstants.PX, CssConstants.IN, CssConstants.CM, CssConstants.MM, CssConstants.PC, CssConstants.PT}; - private static final String[] RELATIVE_MEASUREMENTS = new String[]{CssConstants.PERCENTAGE, CssConstants.EM, CssConstants.EX, CssConstants.REM}; + private static final String[] METRIC_MEASUREMENTS = new String[] {CommonCssConstants.PX, CommonCssConstants.IN, CommonCssConstants.CM, CommonCssConstants.MM, CommonCssConstants.PC, CommonCssConstants.PT}; + private static final String[] RELATIVE_MEASUREMENTS = new String[] {CommonCssConstants.PERCENTAGE, CommonCssConstants.EM, CommonCssConstants.EX, CommonCssConstants.REM}; private static final float EPSILON = 0.000000000000001f; /** @@ -171,31 +173,31 @@ public static float parseAbsoluteLength(String length, String defaultMetric) { String unit = length.substring(pos); //points - if (unit.startsWith(CssConstants.PT) || unit.equals("") && defaultMetric.equals(CssConstants.PT)) { + if (unit.startsWith(CommonCssConstants.PT) || unit.equals("") && defaultMetric.equals(CommonCssConstants.PT)) { return f; } // inches - if (unit.startsWith(CssConstants.IN) || (unit.equals("") && defaultMetric.equals(CssConstants.IN))) { + if (unit.startsWith(CommonCssConstants.IN) || (unit.equals("") && defaultMetric.equals(CommonCssConstants.IN))) { return f * 72f; } // centimeters - else if (unit.startsWith(CssConstants.CM) || (unit.equals("") && defaultMetric.equals(CssConstants.CM))) { + else if (unit.startsWith(CommonCssConstants.CM) || (unit.equals("") && defaultMetric.equals(CommonCssConstants.CM))) { return (f / 2.54f) * 72f; } // quarter of a millimeter (1/40th of a centimeter). - else if (unit.startsWith(CssConstants.Q) || (unit.equals("") && defaultMetric.equals(CssConstants.Q))) { + else if (unit.startsWith(CommonCssConstants.Q) || (unit.equals("") && defaultMetric.equals(CommonCssConstants.Q))) { return (f / 2.54f) * 72f / 40; } // millimeters - else if (unit.startsWith(CssConstants.MM) || (unit.equals("") && defaultMetric.equals(CssConstants.MM))) { + else if (unit.startsWith(CommonCssConstants.MM) || (unit.equals("") && defaultMetric.equals(CommonCssConstants.MM))) { return (f / 25.4f) * 72f; } // picas - else if (unit.startsWith(CssConstants.PC) || (unit.equals("") && defaultMetric.equals(CssConstants.PC))) { + else if (unit.startsWith(CommonCssConstants.PC) || (unit.equals("") && defaultMetric.equals(CommonCssConstants.PC))) { return f * 12f; } // pixels (1px = 0.75pt). - else if (unit.startsWith(CssConstants.PX) || (unit.equals("") && defaultMetric.equals(CssConstants.PX))) { + else if (unit.startsWith(CommonCssConstants.PX) || (unit.equals("") && defaultMetric.equals(CommonCssConstants.PX))) { return f * 0.75f; } @@ -211,7 +213,7 @@ else if (unit.startsWith(CssConstants.PX) || (unit.equals("") && defaultMetric.e * @return the length as a float */ public static float parseAbsoluteLength(String length) { - return parseAbsoluteLength(length, CssConstants.PX); + return parseAbsoluteLength(length, CommonCssConstants.PX); } /** @@ -228,16 +230,61 @@ public static float parseRelativeValue(final String relativeValue, final float b return 0f; double f = Double.parseDouble(relativeValue.substring(0, pos)); String unit = relativeValue.substring(pos); - if (unit.startsWith(CssConstants.PERCENTAGE)) { + if (unit.startsWith(CommonCssConstants.PERCENTAGE)) { f = baseValue * f / 100; - } else if (unit.startsWith(CssConstants.EM) || unit.startsWith(CssConstants.REM)) { + } else if (unit.startsWith(CommonCssConstants.EM) || unit.startsWith(CommonCssConstants.REM)) { f = baseValue * f; - } else if (unit.startsWith(CssConstants.EX)) { + } else if (unit.startsWith(CommonCssConstants.EX)) { f = baseValue * f / 2; } return (float) f; } + /** + * Convenience method for parsing a value to pt. Possible values are:
    + *
  • a numeric value in pixels (e.g. 123, 1.23, .123),
  • + *
  • a value with a metric unit (px, in, cm, mm, pc or pt) attached to it,
  • + *
  • or a value with a relative value (%, em, ex).
  • + *
+ * + * @param value the value + * @param emValue the em value + * @param remValue the root em value + * @return the unit value + */ + public static UnitValue parseLengthValueToPt(final String value, final float emValue, final float remValue) { + if (isMetricValue(value) || isNumericValue(value)) { + return new UnitValue(UnitValue.POINT, parseAbsoluteLength(value)); + } else if (value != null && value.endsWith(CommonCssConstants.PERCENTAGE)) { + return new UnitValue(UnitValue.PERCENT, Float.parseFloat(value.substring(0, value.length() - 1))); + } else if (isRemValue(value)) { + return new UnitValue(UnitValue.POINT, parseRelativeValue(value, remValue)); + } else if (isRelativeValue(value)) { + return new UnitValue(UnitValue.POINT, parseRelativeValue(value, emValue)); + } + return null; + } + + /** + * Parses the border radius of specific corner. + * + * @param specificBorderRadius string that defines the border radius of specific corner. + * @param emValue the em value + * @param remValue the root em value + * @return an array of {@link UnitValue UnitValues} that define horizontal and vertical border radius values + */ + public static UnitValue[] parseSpecificCornerBorderRadius(String specificBorderRadius, final float emValue, final float remValue) { + if (null == specificBorderRadius) { + return null; + } + UnitValue[] cornerRadii = new UnitValue[2]; + String[] props = specificBorderRadius.split("\\s+"); + cornerRadii[0] = parseLengthValueToPt(props[0], emValue, remValue); + cornerRadii[1] = 2 == props.length ? parseLengthValueToPt(props[1], emValue, remValue) : cornerRadii[0]; + + return cornerRadii; + } + /** * Parses the resolution. * @@ -251,9 +298,9 @@ public static float parseResolution(String resolutionStr) { return 0f; float f = Float.parseFloat(resolutionStr.substring(0, pos)); String unit = resolutionStr.substring(pos); - if (unit.startsWith(CssConstants.DPCM)) { + if (unit.startsWith(CommonCssConstants.DPCM)) { f *= 2.54f; - } else if (unit.startsWith(CssConstants.DPPX)) { + } else if (unit.startsWith(CommonCssConstants.DPPX)) { f *= 96; } return f; @@ -328,7 +375,7 @@ public static boolean isRelativeValue(final String value) { * @return boolean true if value contains an allowed metric value. */ public static boolean isRemValue(final String value) { - return value != null && value.endsWith(CssConstants.REM) && isNumericValue(value.substring(0, value.length() - CssConstants.REM.length()).trim()); + return value != null && value.endsWith(CommonCssConstants.REM) && isNumericValue(value.substring(0, value.length() - CommonCssConstants.REM.length()).trim()); } /** @@ -402,13 +449,8 @@ public static int findNextUnescapedChar(String source, char ch, int startIndex) * @return true, if the value contains a color property */ public static boolean isColorProperty(String value) { - /* - return value.contains("rgb(") || value.contains("rgba(") || value.contains("#") - || WebColors.NAMES.containsKey(value.toLowerCase()) || CssConstants.TRANSPARENT.equals(value); -*/ - //TODO re-add Webcolors by either creating a dependency on kernel or moving webcolors to io return value.contains("rgb(") || value.contains("rgba(") || value.contains("#") - || CssConstants.TRANSPARENT.equals(value); + || WebColors.NAMES.containsKey(value.toLowerCase()) || CommonCssConstants.TRANSPARENT.equals(value); } /** @@ -418,5 +460,20 @@ public static boolean isColorProperty(String value) { public static boolean compareFloats(double f1, double f2) { return (Math.abs(f1 - f2) < EPSILON); } + /** + * Parses the RGBA color. + * + * @param colorValue the color value + * @return an RGBA value expressed as an array with four float values + */ + public static float[] parseRgbaColor(String colorValue) { + float[] rgbaColor = WebColors.getRGBAColor(colorValue); + if (rgbaColor == null) { + Logger logger = LoggerFactory.getLogger(CssUtils.class); + logger.error(MessageFormatUtil.format(com.itextpdf.io.LogMessageConstant.COLOR_NOT_PARSED, colorValue)); + rgbaColor = new float[]{0, 0, 0, 1}; + } + return rgbaColor; + } } diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/validate/CssDeclarationValidationMaster.java b/src/main/java/com/itextpdf/styledxmlparser/css/validate/CssDeclarationValidationMaster.java index aa8f20a5e8..796a998427 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/validate/CssDeclarationValidationMaster.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/validate/CssDeclarationValidationMaster.java @@ -43,7 +43,7 @@ This file is part of the iText (R) project. package com.itextpdf.styledxmlparser.css.validate; -import com.itextpdf.styledxmlparser.css.CssConstants; +import com.itextpdf.styledxmlparser.css.CommonCssConstants; import com.itextpdf.styledxmlparser.css.CssDeclaration; import com.itextpdf.styledxmlparser.css.validate.impl.datatype.CssColorValidator; import com.itextpdf.styledxmlparser.css.validate.impl.datatype.CssEnumValidator; @@ -68,31 +68,31 @@ public class CssDeclarationValidationMaster { static { // TODO lazy initialization? ICssDeclarationValidator colorCommonValidator = new MultiTypeDeclarationValidator( - new CssEnumValidator(CssConstants.TRANSPARENT, CssConstants.INITIAL, CssConstants.INHERIT, CssConstants.CURRENTCOLOR), + new CssEnumValidator(CommonCssConstants.TRANSPARENT, CommonCssConstants.INITIAL, CommonCssConstants.INHERIT, CommonCssConstants.CURRENTCOLOR), new CssColorValidator()); DEFAULT_VALIDATORS = new HashMap<>(); - DEFAULT_VALIDATORS.put(CssConstants.BACKGROUND_COLOR, colorCommonValidator); - DEFAULT_VALIDATORS.put(CssConstants.COLOR, colorCommonValidator); - DEFAULT_VALIDATORS.put(CssConstants.BORDER_COLOR, colorCommonValidator); - DEFAULT_VALIDATORS.put(CssConstants.BORDER_BOTTOM_COLOR, colorCommonValidator); - DEFAULT_VALIDATORS.put(CssConstants.BORDER_TOP_COLOR, colorCommonValidator); - DEFAULT_VALIDATORS.put(CssConstants.BORDER_LEFT_COLOR, colorCommonValidator); - DEFAULT_VALIDATORS.put(CssConstants.BORDER_RIGHT_COLOR, colorCommonValidator); - DEFAULT_VALIDATORS.put(CssConstants.FLOAT, + DEFAULT_VALIDATORS.put(CommonCssConstants.BACKGROUND_COLOR, colorCommonValidator); + DEFAULT_VALIDATORS.put(CommonCssConstants.COLOR, colorCommonValidator); + DEFAULT_VALIDATORS.put(CommonCssConstants.BORDER_COLOR, colorCommonValidator); + DEFAULT_VALIDATORS.put(CommonCssConstants.BORDER_BOTTOM_COLOR, colorCommonValidator); + DEFAULT_VALIDATORS.put(CommonCssConstants.BORDER_TOP_COLOR, colorCommonValidator); + DEFAULT_VALIDATORS.put(CommonCssConstants.BORDER_LEFT_COLOR, colorCommonValidator); + DEFAULT_VALIDATORS.put(CommonCssConstants.BORDER_RIGHT_COLOR, colorCommonValidator); + DEFAULT_VALIDATORS.put(CommonCssConstants.FLOAT, new SingleTypeDeclarationValidator( - new CssEnumValidator(CssConstants.LEFT, CssConstants.RIGHT, CssConstants.NONE, CssConstants.INHERIT, CssConstants.CENTER /*center comes from legacy*/))); - DEFAULT_VALIDATORS.put(CssConstants.PAGE_BREAK_BEFORE, + new CssEnumValidator(CommonCssConstants.LEFT, CommonCssConstants.RIGHT, CommonCssConstants.NONE, CommonCssConstants.INHERIT, CommonCssConstants.CENTER /*center comes from legacy*/))); + DEFAULT_VALIDATORS.put(CommonCssConstants.PAGE_BREAK_BEFORE, new SingleTypeDeclarationValidator( - new CssEnumValidator(CssConstants.AUTO, CssConstants.ALWAYS, CssConstants.AVOID, CssConstants.LEFT, CssConstants.RIGHT))); - DEFAULT_VALIDATORS.put(CssConstants.PAGE_BREAK_AFTER, + new CssEnumValidator(CommonCssConstants.AUTO, CommonCssConstants.ALWAYS, CommonCssConstants.AVOID, CommonCssConstants.LEFT, CommonCssConstants.RIGHT))); + DEFAULT_VALIDATORS.put(CommonCssConstants.PAGE_BREAK_AFTER, new SingleTypeDeclarationValidator( - new CssEnumValidator(CssConstants.AUTO, CssConstants.ALWAYS, CssConstants.AVOID, CssConstants.LEFT, CssConstants.RIGHT))); - DEFAULT_VALIDATORS.put(CssConstants.QUOTES, + new CssEnumValidator(CommonCssConstants.AUTO, CommonCssConstants.ALWAYS, CommonCssConstants.AVOID, CommonCssConstants.LEFT, CommonCssConstants.RIGHT))); + DEFAULT_VALIDATORS.put(CommonCssConstants.QUOTES, new MultiTypeDeclarationValidator( - new CssEnumValidator(CssConstants.INITIAL, CssConstants.INHERIT, CssConstants.NONE), + new CssEnumValidator(CommonCssConstants.INITIAL, CommonCssConstants.INHERIT, CommonCssConstants.NONE), new CssQuotesValidator())); - DEFAULT_VALIDATORS.put(CssConstants.TRANSFORM, + DEFAULT_VALIDATORS.put(CommonCssConstants.TRANSFORM, new SingleTypeDeclarationValidator(new CssTransformValidator())); } diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/datatype/CssColorValidator.java b/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/datatype/CssColorValidator.java index 7dad368af8..549f1c4546 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/datatype/CssColorValidator.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/datatype/CssColorValidator.java @@ -43,6 +43,7 @@ This file is part of the iText (R) project. package com.itextpdf.styledxmlparser.css.validate.impl.datatype; +import com.itextpdf.kernel.colors.WebColors; import com.itextpdf.styledxmlparser.css.validate.ICssDataTypeValidator; /** @@ -51,15 +52,11 @@ This file is part of the iText (R) project. public class CssColorValidator implements ICssDataTypeValidator { /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.validate.ICssDataTypeValidator#isValid(java.lang.String) + * @see com.itextpdf.styledxmlparser.css.validate.ICssDataTypeValidator#isValid(java.lang.String) */ @Override public boolean isValid(String objectString) { - /* float[] rgbaColor = WebColors.getRGBAColor(objectString); return rgbaColor != null; - */ - //TODO (RND-767): figure out the possible dependency on Kernel - return true; } } diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/datatype/CssEnumValidator.java b/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/datatype/CssEnumValidator.java index aeeefae23e..233d395569 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/datatype/CssEnumValidator.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/datatype/CssEnumValidator.java @@ -66,7 +66,7 @@ public CssEnumValidator(String... allowedValues) { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.validate.ICssDataTypeValidator#isValid(java.lang.String) + * @see com.itextpdf.styledxmlparser.css.validate.ICssDataTypeValidator#isValid(java.lang.String) */ @Override public boolean isValid(String objectString) { diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/datatype/CssIdentifierValidator.java b/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/datatype/CssIdentifierValidator.java index 8b7ad581ec..a6db624957 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/datatype/CssIdentifierValidator.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/datatype/CssIdentifierValidator.java @@ -56,7 +56,7 @@ This file is part of the iText (R) project. public class CssIdentifierValidator implements ICssDataTypeValidator { /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.validate.ICssDataTypeValidator#isValid(java.lang.String) + * @see com.itextpdf.styledxmlparser.css.validate.ICssDataTypeValidator#isValid(java.lang.String) */ @Override public boolean isValid(String objectString) { diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/datatype/CssQuotesValidator.java b/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/datatype/CssQuotesValidator.java index 2f0a973cfd..efa682efb6 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/datatype/CssQuotesValidator.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/datatype/CssQuotesValidator.java @@ -43,6 +43,7 @@ This file is part of the iText (R) project. package com.itextpdf.styledxmlparser.css.validate.impl.datatype; +import com.itextpdf.styledxmlparser.css.resolve.CssQuotes; import com.itextpdf.styledxmlparser.css.validate.ICssDataTypeValidator; /** @@ -51,15 +52,11 @@ This file is part of the iText (R) project. public class CssQuotesValidator implements ICssDataTypeValidator { /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.validate.ICssDataTypeValidator#isValid(java.lang.String) + * @see com.itextpdf.styledxmlparser.css.validate.ICssDataTypeValidator#isValid(java.lang.String) */ @Override public boolean isValid(String objectString) { - /* CssQuotes quotes = CssQuotes.createQuotes(objectString, false); return quotes != null; - */ - //TODO: decide on moving CSSQuotes - return true; } } diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/datatype/CssTransformValidator.java b/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/datatype/CssTransformValidator.java index da418a0e5a..c5812bd319 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/datatype/CssTransformValidator.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/datatype/CssTransformValidator.java @@ -43,7 +43,7 @@ This file is part of the iText (R) project. package com.itextpdf.styledxmlparser.css.validate.impl.datatype; -import com.itextpdf.styledxmlparser.css.CssConstants; +import com.itextpdf.styledxmlparser.css.CommonCssConstants; import com.itextpdf.styledxmlparser.css.validate.ICssDataTypeValidator; /** @@ -52,11 +52,11 @@ This file is part of the iText (R) project. public class CssTransformValidator implements ICssDataTypeValidator { /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.validate.ICssDataTypeValidator#isValid(java.lang.String) + * @see com.itextpdf.styledxmlparser.css.validate.ICssDataTypeValidator#isValid(java.lang.String) */ @Override public boolean isValid(String objectString) { - if (CssConstants.NONE.equals(objectString)) + if (CommonCssConstants.NONE.equals(objectString)) return true; String[] components = objectString.split("\\)"); for (String component : components) @@ -67,18 +67,18 @@ public boolean isValid(String objectString) { private boolean isValidComponent(String objectString) { String function, args; - if (!CssConstants.NONE.equals(objectString) && objectString.indexOf('(') > 0) { + if (!CommonCssConstants.NONE.equals(objectString) && objectString.indexOf('(') > 0) { function = objectString.substring(0, objectString.indexOf('(')).trim(); args = objectString.substring(objectString.indexOf('(') + 1); } else { return false; } - if (CssConstants.MATRIX.equals(function) || CssConstants.SCALE.equals(function) || - CssConstants.SCALE_X.equals(function) || CssConstants.SCALE_Y.equals(function)) { + if (CommonCssConstants.MATRIX.equals(function) || CommonCssConstants.SCALE.equals(function) || + CommonCssConstants.SCALE_X.equals(function) || CommonCssConstants.SCALE_Y.equals(function)) { String[] arg = args.split(","); - if (arg.length == 6 && CssConstants.MATRIX.equals(function) || - (arg.length == 1 || arg.length == 2) && CssConstants.SCALE.equals(function) || - arg.length == 1 && (CssConstants.SCALE_X.equals(function) || CssConstants.SCALE_Y.equals(function))) { + if (arg.length == 6 && CommonCssConstants.MATRIX.equals(function) || + (arg.length == 1 || arg.length == 2) && CommonCssConstants.SCALE.equals(function) || + arg.length == 1 && (CommonCssConstants.SCALE_X.equals(function) || CommonCssConstants.SCALE_Y.equals(function))) { int i = 0; for (; i < arg.length; i++) { try { @@ -91,17 +91,17 @@ private boolean isValidComponent(String objectString) { return true; } return false; - } else if (CssConstants.TRANSLATE.equals(function) - || CssConstants.TRANSLATE_X.equals(function) || CssConstants.TRANSLATE_Y.equals(function)) { + } else if (CommonCssConstants.TRANSLATE.equals(function) + || CommonCssConstants.TRANSLATE_X.equals(function) || CommonCssConstants.TRANSLATE_Y.equals(function)) { String[] arg = args.split(","); - if ((arg.length == 1 || arg.length == 2 && CssConstants.TRANSLATE.equals(function))) { + if ((arg.length == 1 || arg.length == 2 && CommonCssConstants.TRANSLATE.equals(function))) { for (String a : arg) if (!isValidForTranslate(a)) return false; return true; } return false; - } else if (CssConstants.ROTATE.equals(function)) { + } else if (CommonCssConstants.ROTATE.equals(function)) { try { float value = Float.parseFloat(args); if (value == 0.0f) @@ -119,10 +119,10 @@ private boolean isValidComponent(String objectString) { return true; } return false; - } else if (CssConstants.SKEW.equals(function) - || CssConstants.SKEW_X.equals(function) || CssConstants.SKEW_Y.equals(function)) { + } else if (CommonCssConstants.SKEW.equals(function) + || CommonCssConstants.SKEW_X.equals(function) || CommonCssConstants.SKEW_Y.equals(function)) { String[] arg = args.split(","); - if ((arg.length == 1) || (arg.length == 2 && CssConstants.SKEW.equals(function))) { + if ((arg.length == 1) || (arg.length == 2 && CommonCssConstants.SKEW.equals(function))) { for (int k = 0; k < arg.length; k++) { try { float value = Float.parseFloat(arg[k]); @@ -168,10 +168,10 @@ private static boolean isValidForTranslate(String string) { } catch (NumberFormatException exc) { return false; } - return (Float.parseFloat(string.substring(0, pos)) == 0.0f || string.substring(pos).equals(CssConstants.PT) || string.substring(pos).equals(CssConstants.IN) || - string.substring(pos).equals(CssConstants.CM) || string.substring(pos).equals(CssConstants.Q) || - string.substring(pos).equals(CssConstants.MM) || string.substring(pos).equals(CssConstants.PC) || - string.substring(pos).equals(CssConstants.PX) || string.substring(pos).equals(CssConstants.PERCENTAGE)); + return (Float.parseFloat(string.substring(0, pos)) == 0.0f || string.substring(pos).equals(CommonCssConstants.PT) || string.substring(pos).equals(CommonCssConstants.IN) || + string.substring(pos).equals(CommonCssConstants.CM) || string.substring(pos).equals(CommonCssConstants.Q) || + string.substring(pos).equals(CommonCssConstants.MM) || string.substring(pos).equals(CommonCssConstants.PC) || + string.substring(pos).equals(CommonCssConstants.PX) || string.substring(pos).equals(CommonCssConstants.PERCENTAGE)); } return false; } diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/declaration/MultiTypeDeclarationValidator.java b/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/declaration/MultiTypeDeclarationValidator.java index 0162361c20..eef45bbd9f 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/declaration/MultiTypeDeclarationValidator.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/declaration/MultiTypeDeclarationValidator.java @@ -68,7 +68,7 @@ public MultiTypeDeclarationValidator(ICssDataTypeValidator... allowedTypes) { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.validate.ICssDeclarationValidator#isValid(com.itextpdf.html2pdf.css.CssDeclaration) + * @see com.itextpdf.styledxmlparser.css.validate.ICssDeclarationValidator#isValid(com.itextpdf.styledxmlparser.css.CssDeclaration) */ @Override public boolean isValid(CssDeclaration cssDeclaration) { diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/declaration/SingleTypeDeclarationValidator.java b/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/declaration/SingleTypeDeclarationValidator.java index d919491702..832932c2a7 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/declaration/SingleTypeDeclarationValidator.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/validate/impl/declaration/SingleTypeDeclarationValidator.java @@ -65,7 +65,7 @@ public SingleTypeDeclarationValidator(ICssDataTypeValidator dataTypeValidator) { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.css.validate.ICssDeclarationValidator#isValid(com.itextpdf.html2pdf.css.CssDeclaration) + * @see com.itextpdf.styledxmlparser.css.validate.ICssDeclarationValidator#isValid(com.itextpdf.styledxmlparser.css.CssDeclaration) */ @Override public boolean isValid(CssDeclaration cssDeclaration) { diff --git a/src/main/java/com/itextpdf/styledxmlparser/jsoup/helper/DataUtil.java b/src/main/java/com/itextpdf/styledxmlparser/jsoup/helper/DataUtil.java index 38f3b616c8..cbcae5181c 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/jsoup/helper/DataUtil.java +++ b/src/main/java/com/itextpdf/styledxmlparser/jsoup/helper/DataUtil.java @@ -54,6 +54,7 @@ This file is part of the iText (R) project. import java.io.InputStream; import java.io.OutputStream; import java.io.RandomAccessFile; +import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.Random; @@ -165,7 +166,7 @@ static Document parseByteData(ByteBuffer byteData, String charsetName, String ba if (foundCharset != null && !foundCharset.equals(defaultCharset)) { // need to re-decode foundCharset = foundCharset.trim().replaceAll("[\"']", ""); charsetName = foundCharset; - byteData.rewind(); + ((Buffer) byteData).rewind(); docData = Charset.forName(foundCharset).decode(byteData).toString(); doc = null; } @@ -275,11 +276,11 @@ static String mimeBoundary() { } private static String detectCharsetFromBom(ByteBuffer byteData, String charsetName) { - byteData.mark(); + ((Buffer) byteData).mark(); byte[] bom = new byte[4]; if (byteData.remaining() >= bom.length) { byteData.get(bom); - byteData.rewind(); + ((Buffer) byteData).rewind(); } if (bom[0] == 0x00 && bom[1] == 0x00 && bom[2] == (byte) 0xFE && bom[3] == (byte) 0xFF || // BE bom[0] == (byte) 0xFF && bom[1] == (byte) 0xFE && bom[2] == 0x00 && bom[3] == 0x00) { // LE @@ -289,7 +290,7 @@ private static String detectCharsetFromBom(ByteBuffer byteData, String charsetNa charsetName = "UTF-16"; // in all Javas } else if (bom[0] == (byte) 0xEF && bom[1] == (byte) 0xBB && bom[2] == (byte) 0xBF) { charsetName = "UTF-8"; // in all Javas - byteData.position(3); // 16 and 32 decoders consume the BOM to determine be/le; utf-8 should be consumed here + ((Buffer) byteData).position(3); // 16 and 32 decoders consume the BOM to determine be/le; utf-8 should be consumed here } return charsetName; } diff --git a/src/main/java/com/itextpdf/styledxmlparser/jsoup/nodes/Element.java b/src/main/java/com/itextpdf/styledxmlparser/jsoup/nodes/Element.java index 332b8511bd..fe56a1929a 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/jsoup/nodes/Element.java +++ b/src/main/java/com/itextpdf/styledxmlparser/jsoup/nodes/Element.java @@ -354,9 +354,24 @@ public Element appendChild(Node child) { * @return this element, so that you can add more child nodes or elements. */ public Element prependChild(Node child) { - Validate.notNull(child); + return insertChild(0, child); + } - addChildren(0, child); + /** + * Inserts the given child node into this element at the specified index. Current node will be shifted to the + * right. The inserted nodes will be moved from their current parent. To prevent moving, copy the node first. + * + * @param index 0-based index to insert children at. Specify {@code 0} to insert at the start, {@code -1} at the + * end + * @param child child node to insert + * @return this element, for chaining. + */ + public Element insertChild(int index, Node child) { + if (index == -1) { + return appendChild(child); + } + Validate.notNull(child); + addChildren(index, child); return this; } diff --git a/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/JsoupHtmlParser.java b/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/JsoupHtmlParser.java index 8690f6f4dc..4883b6c86c 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/JsoupHtmlParser.java +++ b/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/JsoupHtmlParser.java @@ -43,7 +43,7 @@ This file is part of the iText (R) project. package com.itextpdf.styledxmlparser.node.impl.jsoup; import com.itextpdf.io.util.MessageFormatUtil; -import com.itextpdf.styledxmlparser.IHtmlParser; +import com.itextpdf.styledxmlparser.IXmlParser; import com.itextpdf.styledxmlparser.jsoup.Jsoup; import com.itextpdf.styledxmlparser.jsoup.nodes.Comment; import com.itextpdf.styledxmlparser.jsoup.nodes.DataNode; @@ -68,13 +68,13 @@ This file is part of the iText (R) project. /** * Class that uses JSoup to parse HTML. */ -public class JsoupHtmlParser implements IHtmlParser { +public class JsoupHtmlParser implements IXmlParser { /** The logger. */ private static Logger logger = LoggerFactory.getLogger(JsoupHtmlParser.class); /* (non-Javadoc) - * @see com.itextpdf.html2pdf.html.IHtmlParser#parse(java.io.InputStream, java.lang.String) + * @see com.itextpdf.styledxmlparser.html.IXmlParser#parse(java.io.InputStream, java.lang.String) */ @Override public IDocumentNode parse(InputStream htmlStream, String charset) throws IOException { @@ -91,7 +91,7 @@ public IDocumentNode parse(InputStream htmlStream, String charset) throws IOExce } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.html.IHtmlParser#parse(java.lang.String) + * @see com.itextpdf.styledxmlparser.html.IXmlParser#parse(java.lang.String) */ @Override public IDocumentNode parse(String html) { diff --git a/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/JsoupXmlParser.java b/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/JsoupXmlParser.java index 9b428b5ede..71c956f511 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/JsoupXmlParser.java +++ b/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/JsoupXmlParser.java @@ -43,7 +43,7 @@ This file is part of the iText (R) project. package com.itextpdf.styledxmlparser.node.impl.jsoup; import com.itextpdf.io.util.MessageFormatUtil; -import com.itextpdf.styledxmlparser.IHtmlParser; +import com.itextpdf.styledxmlparser.IXmlParser; import com.itextpdf.styledxmlparser.LogMessageConstant; import com.itextpdf.styledxmlparser.jsoup.Jsoup; import com.itextpdf.styledxmlparser.jsoup.nodes.Comment; @@ -69,13 +69,13 @@ This file is part of the iText (R) project. /** * Class that uses JSoup to parse HTML. */ -public class JsoupXmlParser implements IHtmlParser { +public class JsoupXmlParser implements IXmlParser { /** The logger. */ private static Logger logger = LoggerFactory.getLogger(JsoupXmlParser.class); /* (non-Javadoc) - * @see com.itextpdf.html2pdf.html.IHtmlParser#parse(java.io.InputStream, java.lang.String) + * @see com.itextpdf.styledxmlparser.html.IXmlParser#parse(java.io.InputStream, java.lang.String) */ @Override public IDocumentNode parse(InputStream xmlStream, String charset) throws IOException { @@ -92,7 +92,7 @@ public IDocumentNode parse(InputStream xmlStream, String charset) throws IOExcep } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.html.IHtmlParser#parse(java.lang.String) + * @see com.itextpdf.styledxmlparser.html.IXmlParser#parse(java.lang.String) */ @Override public IDocumentNode parse(String xml) { diff --git a/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/node/JsoupAttribute.java b/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/node/JsoupAttribute.java index 20afd824c9..17dd26d041 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/node/JsoupAttribute.java +++ b/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/node/JsoupAttribute.java @@ -66,7 +66,7 @@ public JsoupAttribute(Attribute attribute) { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.html.node.IAttribute#getKey() + * @see com.itextpdf.styledxmlparser.html.node.IAttribute#getKey() */ @Override public String getKey() { @@ -74,7 +74,7 @@ public String getKey() { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.html.node.IAttribute#getValue() + * @see com.itextpdf.styledxmlparser.html.node.IAttribute#getValue() */ @Override public String getValue() { diff --git a/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/node/JsoupAttributes.java b/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/node/JsoupAttributes.java index 6f06f93123..ef64434cfe 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/node/JsoupAttributes.java +++ b/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/node/JsoupAttributes.java @@ -70,7 +70,7 @@ public JsoupAttributes(Attributes attributes) { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.html.node.IAttributes#getAttribute(java.lang.String) + * @see com.itextpdf.styledxmlparser.html.node.IAttributes#getAttribute(java.lang.String) */ @Override public String getAttribute(String key) { @@ -78,7 +78,7 @@ public String getAttribute(String key) { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.html.node.IAttributes#setAttribute(java.lang.String, java.lang.String) + * @see com.itextpdf.styledxmlparser.html.node.IAttributes#setAttribute(java.lang.String, java.lang.String) */ @Override public void setAttribute(String key, String value) { @@ -89,7 +89,7 @@ public void setAttribute(String key, String value) { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.html.node.IAttributes#size() + * @see com.itextpdf.styledxmlparser.html.node.IAttributes#size() */ @Override public int size() { diff --git a/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/node/JsoupDataNode.java b/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/node/JsoupDataNode.java index 10e7698c6a..1b83913f46 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/node/JsoupDataNode.java +++ b/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/node/JsoupDataNode.java @@ -65,7 +65,7 @@ public JsoupDataNode(DataNode dataNode) { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.html.node.IDataNode#getWholeData() + * @see com.itextpdf.styledxmlparser.html.node.IDataNode#getWholeData() */ @Override public String getWholeData() { diff --git a/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/node/JsoupElementNode.java b/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/node/JsoupElementNode.java index 699464160a..8836ff6603 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/node/JsoupElementNode.java +++ b/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/node/JsoupElementNode.java @@ -44,7 +44,7 @@ This file is part of the iText (R) project. -import com.itextpdf.styledxmlparser.AttributeConstants; +import com.itextpdf.styledxmlparser.CommonAttributeConstants; import com.itextpdf.styledxmlparser.jsoup.nodes.Element; import com.itextpdf.styledxmlparser.node.IAttributes; import com.itextpdf.styledxmlparser.node.IElementNode; @@ -83,11 +83,11 @@ public JsoupElementNode(Element element) { super(element); this.element = element; this.attributes = new JsoupAttributes(element.attributes()); - this.lang = getAttribute(AttributeConstants.LANG); + this.lang = getAttribute(CommonAttributeConstants.LANG); } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.html.node.IElementNode#name() + * @see com.itextpdf.styledxmlparser.html.node.IElementNode#name() */ @Override public String name() { @@ -95,14 +95,14 @@ public String name() { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.html.node.IElementNode#getAttributes() + * @see com.itextpdf.styledxmlparser.html.node.IElementNode#getAttributes() */ public IAttributes getAttributes() { return attributes; } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.html.node.IElementNode#getAttribute(java.lang.String) + * @see com.itextpdf.styledxmlparser.html.node.IElementNode#getAttribute(java.lang.String) */ @Override public String getAttribute(String key) { @@ -110,7 +110,7 @@ public String getAttribute(String key) { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.html.node.IStylesContainer#setStyles(java.util.Map) + * @see com.itextpdf.styledxmlparser.html.node.IStylesContainer#setStyles(java.util.Map) */ @Override public void setStyles(Map elementResolvedStyles) { @@ -118,7 +118,7 @@ public void setStyles(Map elementResolvedStyles) { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.html.node.IStylesContainer#getStyles() + * @see com.itextpdf.styledxmlparser.html.node.IStylesContainer#getStyles() */ @Override public Map getStyles() { @@ -126,7 +126,7 @@ public Map getStyles() { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.html.node.IElementNode#getAdditionalHtmlStyles() + * @see com.itextpdf.styledxmlparser.html.node.IElementNode#getAdditionalHtmlStyles() */ @Override public List> getAdditionalHtmlStyles() { @@ -134,7 +134,7 @@ public List> getAdditionalHtmlStyles() { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.html.node.IElementNode#addAdditionalHtmlStyles(java.util.Map) + * @see com.itextpdf.styledxmlparser.html.node.IElementNode#addAdditionalHtmlStyles(java.util.Map) */ @Override public void addAdditionalHtmlStyles(Map styles) { @@ -145,7 +145,7 @@ public void addAdditionalHtmlStyles(Map styles) { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.html.node.IElementNode#getLang() + * @see com.itextpdf.styledxmlparser.html.node.IElementNode#getLang() */ @Override public String getLang() { diff --git a/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/node/JsoupNode.java b/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/node/JsoupNode.java index f491d10149..ab70b99f56 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/node/JsoupNode.java +++ b/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/node/JsoupNode.java @@ -75,7 +75,7 @@ public JsoupNode(Node node) { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.html.node.INode#childNodes() + * @see com.itextpdf.styledxmlparser.html.node.INode#childNodes() */ @Override public List childNodes() { @@ -83,7 +83,7 @@ public List childNodes() { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.html.node.INode#addChild(com.itextpdf.html2pdf.html.node.INode) + * @see com.itextpdf.styledxmlparser.html.node.INode#addChild(com.itextpdf.styledxmlparser.html.node.INode) */ @Override public void addChild(INode node) { @@ -97,7 +97,7 @@ public void addChild(INode node) { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.html.node.INode#parentNode() + * @see com.itextpdf.styledxmlparser.html.node.INode#parentNode() */ @Override public INode parentNode() { diff --git a/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/node/JsoupTextNode.java b/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/node/JsoupTextNode.java index e6d35b0949..a8ea399014 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/node/JsoupTextNode.java +++ b/src/main/java/com/itextpdf/styledxmlparser/node/impl/jsoup/node/JsoupTextNode.java @@ -65,7 +65,7 @@ public JsoupTextNode(TextNode textNode) { } /* (non-Javadoc) - * @see com.itextpdf.html2pdf.html.node.ITextNode#wholeText() + * @see com.itextpdf.styledxmlparser.html.node.ITextNode#wholeText() */ @Override public String wholeText() { diff --git a/src/main/java/com/itextpdf/styledxmlparser/resolver/font/DefaultFontProvider.java b/src/main/java/com/itextpdf/styledxmlparser/resolver/font/BasicFontProvider.java similarity index 58% rename from src/main/java/com/itextpdf/styledxmlparser/resolver/font/DefaultFontProvider.java rename to src/main/java/com/itextpdf/styledxmlparser/resolver/font/BasicFontProvider.java index ae11861eb5..4e69ea588a 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/resolver/font/DefaultFontProvider.java +++ b/src/main/java/com/itextpdf/styledxmlparser/resolver/font/BasicFontProvider.java @@ -42,77 +42,33 @@ This file is part of the iText (R) project. */ package com.itextpdf.styledxmlparser.resolver.font; -import com.itextpdf.io.util.ResourceUtil; -import com.itextpdf.io.util.StreamUtil; import com.itextpdf.layout.font.FontProvider; -import java.io.InputStream; - /** - * The default {@link FontProvider} that, as opposed to - * the font provider in iText 7, also includes a series of fonts that - * are shipped with the implementation. + * A basic {@link FontProvider} that allows configuring in the constructor which fonts are loaded by default. */ -public class DefaultFontProvider extends FontProvider { - - /** The path to the shipped fonts. */ - private static final String SHIPPED_FONT_RESOURCE_PATH = "com/itextpdf/html2pdf/font/"; - - /** The file names of the shipped fonts. */ - private static final String[] SHIPPED_FONT_NAMES = new String[] { - "FreeMono.ttf", - "FreeMonoBold.ttf", - "FreeMonoBoldOblique.ttf", - "FreeMonoOblique.ttf", - "FreeSans.ttf", - "FreeSansBold.ttf", - "FreeSansBoldOblique.ttf", - "FreeSansOblique.ttf", - "FreeSerif.ttf", - "FreeSerifBold.ttf", - "FreeSerifBoldItalic.ttf", - "FreeSerifItalic.ttf", - }; +public class BasicFontProvider extends FontProvider { /** - * Creates a new {@link DefaultFontProvider} instance. + * Creates a new {@link BasicFontProvider} instance. */ - public DefaultFontProvider() { - this(true, true, false); + public BasicFontProvider() { + this(true, false); } /** - * Creates a new {@link DefaultFontProvider} instance. + * Creates a new {@link BasicFontProvider} instance. * * @param registerStandardPdfFonts use true if you want to register the standard Type 1 fonts (can't be embedded) - * @param registerShippedFreeFonts use true if you want to register the shipped fonts (can be embedded) * @param registerSystemFonts use true if you want to register the system fonts (can require quite some resources) */ - public DefaultFontProvider(boolean registerStandardPdfFonts, boolean registerShippedFreeFonts, boolean registerSystemFonts) { + public BasicFontProvider(boolean registerStandardPdfFonts, boolean registerSystemFonts) { super(); if (registerStandardPdfFonts) { addStandardPdfFonts(); } - if (registerShippedFreeFonts) { - addShippedFreeFonts(); - } if (registerSystemFonts) { addSystemFonts(); } } - - /** - * Adds the shipped free fonts. - */ - private void addShippedFreeFonts() { - for (String fontName : SHIPPED_FONT_NAMES) { - InputStream stream = ResourceUtil.getResourceStream(SHIPPED_FONT_RESOURCE_PATH + fontName); - try { - byte[] fontProgramBytes = StreamUtil.inputStreamToArray(stream); - addFont(fontProgramBytes); - } catch (Exception exc) { - } - } - } - } diff --git a/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolver.java b/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolver.java index c4e7d777da..9e59a0a601 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolver.java +++ b/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolver.java @@ -53,6 +53,7 @@ This file is part of the iText (R) project. import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; @@ -71,6 +72,8 @@ public class ResourceResolver { // TODO provide a way to configure capacity, manually reset or disable the image cache? private SimpleImageCache imageCache; + /** Identifier string used when loading in base64 images**/ + public static final String BASE64IDENTIFIER = "base64"; /** * Creates {@link ResourceResolver} instance. If {@code baseUri} is a string that represents an absolute URI with any schema * except "file" - resources url values will be resolved exactly as "new URL(baseUrl, uriString)". Otherwise base URI @@ -104,10 +107,10 @@ public PdfImageXObject retrieveImage(String src) { if (src == null) { return null; } - if (src.contains("base64")) { + if (src.contains(BASE64IDENTIFIER)) { try { String fixedSrc = src.replaceAll("\\s", ""); - fixedSrc = fixedSrc.substring(fixedSrc.indexOf("base64") + 7); + fixedSrc = fixedSrc.substring(fixedSrc.indexOf(BASE64IDENTIFIER) + 7); PdfImageXObject imageXObject = imageCache.getImage(fixedSrc); if (imageXObject == null) { imageXObject = new PdfImageXObject( ImageDataFactory.create( Base64.decode(fixedSrc))); @@ -148,31 +151,75 @@ public InputStream retrieveStyleSheet(String uri) throws IOException { } /** + * Deprecated: use retrieveBytesFromResource instead + * Replaced by retrieveBytesFromResource for the sake of method name clarity. + * * Retrieve a resource as a byte array from a source that * can either be a link to a file, or a base64 encoded {@link String}. * * @param src either link to file or base64 encoded stream. * @return byte[] on success, otherwise null. */ + @Deprecated public byte[] retrieveStream(String src) { + try { + return StreamUtil.inputStreamToArray(retrieveResourceAsInputStream(src)); + }catch(Exception e){ + Logger logger = LoggerFactory.getLogger(ResourceResolver.class); + logger.error(MessageFormatUtil.format(LogMessageConstant.UNABLE_TO_RETRIEVE_STREAM_WITH_GIVEN_BASE_URI, uriResolver.getBaseUri(), src), e); + return null; + } + } + + /** + * Retrieve a resource as a byte array from a source that + * can either be a link to a file, or a base64 encoded {@link String}. + * + * @param src either link to file or base64 encoded stream. + * @return byte[] on success, otherwise null. + */ + public byte[] retrieveBytesFromResource(String src) { + InputStream stream = retrieveResourceAsInputStream(src); + if(stream !=null) { + try { + return StreamUtil.inputStreamToArray(stream); + }catch(IOException ioe){ + Logger logger = LoggerFactory.getLogger(ResourceResolver.class); + logger.error(MessageFormatUtil.format(LogMessageConstant.UNABLE_TO_RETRIEVE_STREAM_WITH_GIVEN_BASE_URI, uriResolver.getBaseUri(), src), ioe); + return null; + } + }else{ + return null; + } + + + } + + /** + * Retrieve the resource found in src as an InputStream + * @param src path to the resource + * @return InputStream for the resource + */ + public InputStream retrieveResourceAsInputStream(String src){ if (src.contains("base64")) { try { String fixedSrc = src.replaceAll("\\s", ""); fixedSrc = fixedSrc.substring(fixedSrc.indexOf("base64") + 7); - return Base64.decode(fixedSrc); + return new ByteArrayInputStream(Base64.decode(fixedSrc)); } catch (Exception ignored) { } } try { - return StreamUtil.inputStreamToArray(uriResolver.resolveAgainstBaseUri(src).openStream()); + return uriResolver.resolveAgainstBaseUri(src).openStream(); } catch (Exception e) { Logger logger = LoggerFactory.getLogger(ResourceResolver.class); - logger.error( MessageFormatUtil.format(LogMessageConstant.UNABLE_TO_RETRIEVE_STREAM_WITH_GIVEN_BASE_URI, uriResolver.getBaseUri(), src), e); + logger.error(MessageFormatUtil.format(LogMessageConstant.UNABLE_TO_RETRIEVE_STREAM_WITH_GIVEN_BASE_URI, uriResolver.getBaseUri(), src), e); return null; } } + /** * Resolves a given URI against the base URI. * @@ -190,4 +237,20 @@ public URL resolveAgainstBaseUri(String uri) throws MalformedURLException { public void resetCache() { imageCache.reset(); } + + + /** + * Check if the type of image located at the passed is supported by the {@link ImageDataFactory} + * @param src location of the image resource + * @return true if the image type is supported, false otherwise + */ + public boolean isImageTypeSupportedByImageDataFactory(String src){ + try { + URL url = uriResolver.resolveAgainstBaseUri(src); + url = UrlUtil.getFinalURL(url); + return ImageDataFactory.isSupportedType(url); + }catch(Exception e){ + return false; + } + } } diff --git a/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolver.java b/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolver.java index 4a6fb29764..251f968523 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolver.java +++ b/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolver.java @@ -146,7 +146,7 @@ private void resolveBaseUrlOrPath(String base) { } if (baseUrl == null) { - // TODO Html2PdfException? + // TODO styledxmlparserException? throw new IllegalArgumentException(MessageFormatUtil.format("Invalid base URI: {0}", base)); } } diff --git a/src/test/java/com/itextpdf/html2pdf/css/CssStyleSheetParserTest.java b/src/test/java/com/itextpdf/html2pdf/css/CssStyleSheetParserTest.java deleted file mode 100644 index 7b2f7e0283..0000000000 --- a/src/test/java/com/itextpdf/html2pdf/css/CssStyleSheetParserTest.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - This file is part of the iText (R) project. - Copyright (c) 1998-2017 iText Group NV - Authors: iText Software. - - 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.html2pdf.css; - -import com.itextpdf.io.util.StreamUtil; -import com.itextpdf.styledxmlparser.css.CssStyleSheet; -import com.itextpdf.styledxmlparser.css.parse.CssStyleSheetParser; -import com.itextpdf.test.ExtendedITextTest; -import com.itextpdf.test.annotations.type.UnitTest; -import java.io.FileInputStream; -import java.io.IOException; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -@Category(UnitTest.class) -public class CssStyleSheetParserTest extends ExtendedITextTest { - - private static final String sourceFolder = "./src/test/resources/com/itextpdf/styledxmlparser/css/CssStyleSheetParserTest/"; - - @BeforeClass - public static void beforeClass() { - } - - @Test - public void test01() throws IOException { - String cssFile = sourceFolder + "css01.css"; - CssStyleSheet styleSheet = CssStyleSheetParser.parse(new FileInputStream(cssFile)); - Assert.assertEquals(getCssFileContents(cssFile), styleSheet.toString()); - } - - @Test - public void test02() throws IOException { - String cssFile = sourceFolder + "css02.css"; - String cmpFile = sourceFolder + "cmp_css02.css"; - CssStyleSheet styleSheet = CssStyleSheetParser.parse(new FileInputStream(cssFile)); - Assert.assertEquals(getCssFileContents(cmpFile), styleSheet.toString()); - } - - @Test - public void test03() throws IOException { - String cssFile = sourceFolder + "css03.css"; - String cmpFile = sourceFolder + "cmp_css03.css"; - CssStyleSheet styleSheet = CssStyleSheetParser.parse(new FileInputStream(cssFile)); - Assert.assertEquals(getCssFileContents(cmpFile), styleSheet.toString()); - } - - @Test - public void test04() throws IOException { - String cssFile = sourceFolder + "css04.css"; - CssStyleSheet styleSheet = CssStyleSheetParser.parse(new FileInputStream(cssFile)); - Assert.assertEquals("", styleSheet.toString()); - } - - @Test - public void test05() throws IOException { - String cssFile = sourceFolder + "css05.css"; - String cmpFile = sourceFolder + "cmp_css05.css"; - CssStyleSheet styleSheet = CssStyleSheetParser.parse(new FileInputStream(cssFile)); - Assert.assertEquals(getCssFileContents(cmpFile), styleSheet.toString()); - } - - @Test - public void test06() throws IOException { - String cssFile = sourceFolder + "css06.css"; - String cmpFile = sourceFolder + "cmp_css06.css"; - CssStyleSheet styleSheet = CssStyleSheetParser.parse(new FileInputStream(cssFile)); - Assert.assertEquals(getCssFileContents(cmpFile), styleSheet.toString()); - } - - @Test - public void test07() throws IOException { - String cssFile = sourceFolder + "css07.css"; - CssStyleSheet styleSheet = CssStyleSheetParser.parse(new FileInputStream(cssFile)); - Assert.assertEquals(getCssFileContents(cssFile), styleSheet.toString()); - } - - @Test - public void test08() throws IOException { - String cssFile = sourceFolder + "css08.css"; - String cmpFile = sourceFolder + "cmp_css08.css"; - CssStyleSheet styleSheet = CssStyleSheetParser.parse(new FileInputStream(cssFile)); - Assert.assertEquals(getCssFileContents(cmpFile), styleSheet.toString()); - } - - @Test - public void test09() throws IOException { - String cssFile = sourceFolder + "css09.css"; - CssStyleSheet styleSheet = CssStyleSheetParser.parse(new FileInputStream(cssFile)); - Assert.assertEquals(getCssFileContents(cssFile), styleSheet.toString()); - } - - @Test - public void test10() throws IOException { - String cssFile = sourceFolder + "css10.css"; - String cmpFile = sourceFolder + "cmp_css10.css"; - CssStyleSheet styleSheet = CssStyleSheetParser.parse(new FileInputStream(cssFile)); - Assert.assertEquals(getCssFileContents(cmpFile), styleSheet.toString()); - } - - @Test - public void test11() throws IOException { - // TODO in this test declarations of the page at-rule with compound selector are duplicated. - // See CssPageRule#addBodyCssDeclarations() method for the reason and possible solution if this becomes important. - - String cssFile = sourceFolder + "css11.css"; - String cmpFile = sourceFolder + "cmp_css11.css"; - CssStyleSheet styleSheet = CssStyleSheetParser.parse(new FileInputStream(cssFile)); - Assert.assertEquals(getCssFileContents(cmpFile), styleSheet.toString()); - } - - @Test - public void test12() throws IOException { - String cssFile = sourceFolder + "css12.css"; - String cmpFile = sourceFolder + "cmp_css12.css"; - CssStyleSheet styleSheet = CssStyleSheetParser.parse(new FileInputStream(cssFile)); - Assert.assertEquals(getCssFileContents(cmpFile), styleSheet.toString()); - } - - private String getCssFileContents(String filePath) throws IOException { - byte[] bytes = StreamUtil.inputStreamToArray(new FileInputStream(filePath)); - String content = new String(bytes); - content = content.trim(); - content = content.replace("\r\n", "\n"); - return content; - } -} diff --git a/src/test/java/com/itextpdf/html2pdf/css/CssMatchingTest.java b/src/test/java/com/itextpdf/styledxmlparser/css/CssMatchingTest.java similarity index 93% rename from src/test/java/com/itextpdf/html2pdf/css/CssMatchingTest.java rename to src/test/java/com/itextpdf/styledxmlparser/css/CssMatchingTest.java index cbe562ed5f..532fcd1fa9 100644 --- a/src/test/java/com/itextpdf/html2pdf/css/CssMatchingTest.java +++ b/src/test/java/com/itextpdf/styledxmlparser/css/CssMatchingTest.java @@ -40,24 +40,23 @@ This file is part of the iText (R) project. For more information, please contact iText Software Corp. at this address: sales@itextpdf.com */ -package com.itextpdf.html2pdf.css; +package com.itextpdf.styledxmlparser.css; - -import com.itextpdf.styledxmlparser.IHtmlParser; -import com.itextpdf.styledxmlparser.css.CssDeclaration; -import com.itextpdf.styledxmlparser.css.CssStyleSheet; +import com.itextpdf.styledxmlparser.IXmlParser; import com.itextpdf.styledxmlparser.css.media.MediaDeviceDescription; import com.itextpdf.styledxmlparser.css.parse.CssStyleSheetParser; import com.itextpdf.styledxmlparser.node.IDocumentNode; import com.itextpdf.styledxmlparser.node.IElementNode; -import com.itextpdf.styledxmlparser.node.impl.jsoup.JsoupXmlParser; +import com.itextpdf.styledxmlparser.node.impl.jsoup.JsoupHtmlParser; import com.itextpdf.styledxmlparser.node.impl.jsoup.node.JsoupDocumentNode; import com.itextpdf.styledxmlparser.node.impl.jsoup.node.JsoupElementNode; import com.itextpdf.test.ExtendedITextTest; import com.itextpdf.test.annotations.type.UnitTest; + import java.io.FileInputStream; import java.io.IOException; import java.util.List; + import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; @@ -76,7 +75,7 @@ public static void beforeClass() { public void test01() throws IOException { String htmlFileName = sourceFolder + "html01.html"; String cssFileName = sourceFolder + "css01.css"; - IHtmlParser htmlParser = new JsoupXmlParser(); + IXmlParser htmlParser = new JsoupHtmlParser(); IDocumentNode document = htmlParser.parse(new FileInputStream(htmlFileName), "UTF-8"); CssStyleSheet css = CssStyleSheetParser.parse(new FileInputStream(cssFileName)); MediaDeviceDescription deviceDescription = new MediaDeviceDescription("all"); @@ -90,7 +89,7 @@ public void test01() throws IOException { public void test02() throws IOException { String htmlFileName = sourceFolder + "html02.html"; String cssFileName = sourceFolder + "css02.css"; - IHtmlParser htmlParser = new JsoupXmlParser(); + IXmlParser htmlParser = new JsoupHtmlParser(); IDocumentNode document = htmlParser.parse(new FileInputStream(htmlFileName), "UTF-8"); CssStyleSheet css = CssStyleSheetParser.parse(new FileInputStream(cssFileName)); MediaDeviceDescription deviceDescription = new MediaDeviceDescription("all"); @@ -105,7 +104,7 @@ public void test02() throws IOException { public void test03() throws IOException { String htmlFileName = sourceFolder + "html03.html"; String cssFileName = sourceFolder + "css03.css"; - IHtmlParser htmlParser = new JsoupXmlParser(); + IXmlParser htmlParser = new JsoupHtmlParser(); IDocumentNode document = htmlParser.parse(new FileInputStream(htmlFileName), "UTF-8"); CssStyleSheet css = CssStyleSheetParser.parse(new FileInputStream(cssFileName)); MediaDeviceDescription deviceDescription = new MediaDeviceDescription("all"); @@ -120,7 +119,7 @@ public void test03() throws IOException { public void test04() throws IOException { String htmlFileName = sourceFolder + "html04.html"; String cssFileName = sourceFolder + "css04.css"; - IHtmlParser htmlParser = new JsoupXmlParser(); + IXmlParser htmlParser = new JsoupHtmlParser(); IDocumentNode document = htmlParser.parse(new FileInputStream(htmlFileName), "UTF-8"); CssStyleSheet css = CssStyleSheetParser.parse(new FileInputStream(cssFileName)); MediaDeviceDescription deviceDescription = new MediaDeviceDescription("all"); @@ -134,7 +133,7 @@ public void test04() throws IOException { public void test05() throws IOException { String htmlFileName = sourceFolder + "html05.html"; String cssFileName = sourceFolder + "css05.css"; - IHtmlParser htmlParser = new JsoupXmlParser(); + IXmlParser htmlParser = new JsoupHtmlParser(); IDocumentNode document = htmlParser.parse(new FileInputStream(htmlFileName), "UTF-8"); CssStyleSheet css = CssStyleSheetParser.parse(new FileInputStream(cssFileName)); MediaDeviceDescription deviceDescription = new MediaDeviceDescription("all"); @@ -148,7 +147,7 @@ public void test05() throws IOException { public void test06() throws IOException { String htmlFileName = sourceFolder + "html06.html"; String cssFileName = sourceFolder + "css06.css"; - IHtmlParser htmlParser = new JsoupXmlParser(); + IXmlParser htmlParser = new JsoupHtmlParser(); IDocumentNode document = htmlParser.parse(new FileInputStream(htmlFileName), "UTF-8"); CssStyleSheet css = CssStyleSheetParser.parse(new FileInputStream(cssFileName)); MediaDeviceDescription deviceDescription = new MediaDeviceDescription("all"); diff --git a/src/test/java/com/itextpdf/styledxmlparser/css/media/CssMediaRuleTest.java b/src/test/java/com/itextpdf/styledxmlparser/css/media/CssMediaRuleTest.java index 06cd9c1b89..7f296814c2 100644 --- a/src/test/java/com/itextpdf/styledxmlparser/css/media/CssMediaRuleTest.java +++ b/src/test/java/com/itextpdf/styledxmlparser/css/media/CssMediaRuleTest.java @@ -1,6 +1,6 @@ package com.itextpdf.styledxmlparser.css.media; -import com.itextpdf.styledxmlparser.IHtmlParser; +import com.itextpdf.styledxmlparser.IXmlParser; import com.itextpdf.styledxmlparser.css.CssDeclaration; import com.itextpdf.styledxmlparser.css.CssRuleSet; import com.itextpdf.styledxmlparser.css.CssStyleSheet; @@ -34,7 +34,7 @@ public static void beforeClass() { public void test01() throws IOException { String htmlFileName = sourceFolder + "html01.html"; String cssFileName = sourceFolder + "css01.css"; - IHtmlParser htmlParser = new JsoupHtmlParser(); + IXmlParser htmlParser = new JsoupHtmlParser(); IDocumentNode document = htmlParser.parse(new FileInputStream(htmlFileName), "UTF-8"); CssStyleSheet css = CssStyleSheetParser.parse(new FileInputStream(cssFileName)); MediaDeviceDescription deviceDescription = new MediaDeviceDescription(MediaType.PRINT); @@ -50,7 +50,7 @@ public void test01() throws IOException { public void test02() throws IOException { String htmlFileName = sourceFolder + "html02.html"; String cssFileName = sourceFolder + "css02.css"; - IHtmlParser htmlParser = new JsoupHtmlParser(); + IXmlParser htmlParser = new JsoupHtmlParser(); IDocumentNode document = htmlParser.parse(new FileInputStream(htmlFileName), "UTF-8"); CssStyleSheet css = CssStyleSheetParser.parse(new FileInputStream(cssFileName)); IElementNode element = new JsoupElementNode(((JsoupDocumentNode) document).getDocument().getElementsByTag("p").first()); @@ -74,7 +74,7 @@ public void test02() throws IOException { public void test03() throws IOException { String htmlFileName = sourceFolder + "html03.html"; String cssFileName = sourceFolder + "css03.css"; - IHtmlParser htmlParser = new JsoupHtmlParser(); + IXmlParser htmlParser = new JsoupHtmlParser(); IDocumentNode document = htmlParser.parse(new FileInputStream(htmlFileName), "UTF-8"); CssStyleSheet css = CssStyleSheetParser.parse(new FileInputStream(cssFileName)); MediaDeviceDescription deviceDescription = new MediaDeviceDescription(MediaType.PRINT); @@ -89,7 +89,7 @@ public void test03() throws IOException { public void test04() throws IOException { String htmlFileName = sourceFolder + "html04.html"; String cssFileName = sourceFolder + "css04.css"; - IHtmlParser htmlParser = new JsoupHtmlParser(); + IXmlParser htmlParser = new JsoupHtmlParser(); IDocumentNode document = htmlParser.parse(new FileInputStream(htmlFileName), "UTF-8"); CssStyleSheet css = CssStyleSheetParser.parse(new FileInputStream(cssFileName)); @@ -106,7 +106,7 @@ public void test04() throws IOException { public void test05() throws IOException { String htmlFileName = sourceFolder + "html05.html"; String cssFileName = sourceFolder + "css05.css"; - IHtmlParser htmlParser = new JsoupHtmlParser(); + IXmlParser htmlParser = new JsoupHtmlParser(); IDocumentNode document = htmlParser.parse(new FileInputStream(htmlFileName), "UTF-8"); CssStyleSheet css = CssStyleSheetParser.parse(new FileInputStream(cssFileName)); IElementNode element = new JsoupElementNode(((JsoupDocumentNode) document).getDocument().getElementsByTag("p").first()); @@ -130,7 +130,7 @@ public void test05() throws IOException { public void test06() throws IOException { String htmlFileName = sourceFolder + "html06.html"; String cssFileName = sourceFolder + "css06.css"; - IHtmlParser htmlParser = new JsoupHtmlParser(); + IXmlParser htmlParser = new JsoupHtmlParser(); IDocumentNode document = htmlParser.parse(new FileInputStream(htmlFileName), "UTF-8"); CssStyleSheet css = CssStyleSheetParser.parse(new FileInputStream(cssFileName)); IElementNode element = new JsoupElementNode(((JsoupDocumentNode) document).getDocument().getElementsByTag("p").first()); diff --git a/src/test/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/CssShorthandResolverTest.java b/src/test/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/CssShorthandResolverTest.java index eecdb78249..8767fdf45a 100644 --- a/src/test/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/CssShorthandResolverTest.java +++ b/src/test/java/com/itextpdf/styledxmlparser/css/resolve/shorthand/CssShorthandResolverTest.java @@ -42,7 +42,7 @@ This file is part of the iText (R) project. */ package com.itextpdf.styledxmlparser.css.resolve.shorthand; -import com.itextpdf.styledxmlparser.css.CssConstants; +import com.itextpdf.styledxmlparser.css.CommonCssConstants; import com.itextpdf.styledxmlparser.css.CssDeclaration; import com.itextpdf.test.ExtendedITextTest; import com.itextpdf.test.annotations.type.UnitTest; @@ -74,7 +74,7 @@ public void fontTest01() { "font-family: georgia,serif" ) ); - IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CssConstants.FONT ); + IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CommonCssConstants.FONT ); assertNotNull( resolver ); List resolvedShorthandProps = resolver.resolveShorthand( shorthandExpression ); compareResolvedProps( resolvedShorthandProps, expectedResolvedProperties ); @@ -92,7 +92,7 @@ public void fontTest02() { "font-family: georgia,serif" ) ); - IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CssConstants.FONT ); + IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CommonCssConstants.FONT ); assertNotNull( resolver ); List resolvedShorthandProps = resolver.resolveShorthand( shorthandExpression ); compareResolvedProps( resolvedShorthandProps, expectedResolvedProperties ); @@ -110,7 +110,7 @@ public void fontTest03() { "font-family: inherit" ) ); - IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CssConstants.FONT ); + IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CommonCssConstants.FONT ); assertNotNull( resolver ); List resolvedShorthandProps = resolver.resolveShorthand( shorthandExpression ); compareResolvedProps( resolvedShorthandProps, expectedResolvedProperties ); @@ -128,7 +128,7 @@ public void fontTest04() { "font-family: georgia,serif,\"Times New Roman\"" ) ); - IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CssConstants.FONT ); + IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CommonCssConstants.FONT ); assertNotNull( resolver ); List resolvedShorthandProps = resolver.resolveShorthand( shorthandExpression ); compareResolvedProps( resolvedShorthandProps, expectedResolvedProperties ); @@ -146,7 +146,7 @@ public void fontTest05() { "font-family: georgia,\"Times New Roman\",serif" ) ); - IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CssConstants.FONT ); + IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CommonCssConstants.FONT ); assertNotNull( resolver ); List resolvedShorthandProps = resolver.resolveShorthand( shorthandExpression ); compareResolvedProps( resolvedShorthandProps, expectedResolvedProperties ); @@ -164,7 +164,7 @@ public void fontTest06() { "font-family: georgia,\"Times New Roman\",serif" ) ); - IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CssConstants.FONT ); + IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CommonCssConstants.FONT ); assertNotNull( resolver ); List resolvedShorthandProps = resolver.resolveShorthand( shorthandExpression ); compareResolvedProps( resolvedShorthandProps, expectedResolvedProperties ); @@ -182,7 +182,7 @@ public void fontTest07() { "font-family: georgia,\"Times New Roman\"" ) ); - IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CssConstants.FONT ); + IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CommonCssConstants.FONT ); assertNotNull( resolver ); List resolvedShorthandProps = resolver.resolveShorthand( shorthandExpression ); compareResolvedProps( resolvedShorthandProps, expectedResolvedProperties ); @@ -200,7 +200,7 @@ public void fontTest08() { "font-family: georgia,'Times New Roman'" ) ); - IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CssConstants.FONT ); + IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CommonCssConstants.FONT ); assertNotNull( resolver ); List resolvedShorthandProps = resolver.resolveShorthand( shorthandExpression ); compareResolvedProps( resolvedShorthandProps, expectedResolvedProperties ); @@ -218,7 +218,7 @@ public void fontTest09() { "font-family: georgia,'Times New Roman',serif" ) ); - IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CssConstants.FONT ); + IShorthandResolver resolver = ShorthandResolverFactory.getShorthandResolver( CommonCssConstants.FONT ); assertNotNull( resolver ); List resolvedShorthandProps = resolver.resolveShorthand( shorthandExpression ); compareResolvedProps( resolvedShorthandProps, expectedResolvedProperties ); diff --git a/src/test/java/com/itextpdf/styledxmlparser/css/selector/item/SpecificityCalculationTest.java b/src/test/java/com/itextpdf/styledxmlparser/css/selector/item/SpecificityCalculationTest.java new file mode 100644 index 0000000000..b9e2116be9 --- /dev/null +++ b/src/test/java/com/itextpdf/styledxmlparser/css/selector/item/SpecificityCalculationTest.java @@ -0,0 +1,209 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 iText Group NV + Authors: iText Software. + + 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.styledxmlparser.css.selector.item; + +import com.itextpdf.styledxmlparser.css.selector.CssPageSelector; +import com.itextpdf.styledxmlparser.css.selector.CssSelector; +import com.itextpdf.styledxmlparser.css.selector.item.CssSpecificityConstants; +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 SpecificityCalculationTest extends ExtendedITextTest { + + // https://www.smashingmagazine.com/2007/07/css-specificity-things-you-should-know/ + // https://specificity.keegan.st/ + + @Test + public void test01() { + Assert.assertEquals(0, getSpecificity("*")); + } + + @Test + public void test02() { + Assert.assertEquals(1, getSpecificity("li")); + } + + @Test + public void test03() { + Assert.assertEquals(2, getSpecificity("li:first-line")); + } + + @Test + public void test04() { + Assert.assertEquals(2, getSpecificity("ul li")); + } + + @Test + public void test05() { + Assert.assertEquals(3, getSpecificity("ul ol+li")); + } + + @Test + public void test06() { + Assert.assertEquals(CssSpecificityConstants.CLASS_SPECIFICITY + CssSpecificityConstants.ELEMENT_SPECIFICITY, getSpecificity("h1 + *[rel=up]")); + } + + @Test + public void test07() { + Assert.assertEquals(CssSpecificityConstants.CLASS_SPECIFICITY + CssSpecificityConstants.ELEMENT_SPECIFICITY * 3, getSpecificity("ul ol li.red")); + } + + @Test + public void test08() { + Assert.assertEquals(CssSpecificityConstants.CLASS_SPECIFICITY * 2 + CssSpecificityConstants.ELEMENT_SPECIFICITY, getSpecificity("li.red.level")); + } + + @Test + public void test09() { + Assert.assertEquals(CssSpecificityConstants.CLASS_SPECIFICITY, getSpecificity(".sith")); + } + + @Test + public void test10() { + Assert.assertEquals(CssSpecificityConstants.CLASS_SPECIFICITY + CssSpecificityConstants.ELEMENT_SPECIFICITY * 2, getSpecificity("div p.sith")); + } + + @Test + public void test11() { + Assert.assertEquals(CssSpecificityConstants.ID_SPECIFICITY, getSpecificity("#sith")); + } + + @Test + public void test12() { + Assert.assertEquals(CssSpecificityConstants.ID_SPECIFICITY + CssSpecificityConstants.CLASS_SPECIFICITY + CssSpecificityConstants.ELEMENT_SPECIFICITY * 2, getSpecificity("body #darkside .sith p")); + } + + @Test + public void test13() { + Assert.assertEquals(CssSpecificityConstants.CLASS_SPECIFICITY * 2 + CssSpecificityConstants.ELEMENT_SPECIFICITY * 2, getSpecificity("li:first-child h2 .title")); + } + + @Test + public void test14() { + Assert.assertEquals(CssSpecificityConstants.ID_SPECIFICITY + CssSpecificityConstants.CLASS_SPECIFICITY * 2 + CssSpecificityConstants.ELEMENT_SPECIFICITY, getSpecificity("#nav .selected > a:hover")); + } + + @Test + public void test15() { + Assert.assertEquals(2, getSpecificity("p:before")); + Assert.assertEquals(2, getSpecificity("p::before")); + } + + @Test + public void test16() { + Assert.assertEquals(2, getSpecificity("a::hover")); + } + + @Test + public void test17() { + Assert.assertEquals(CssSpecificityConstants.CLASS_SPECIFICITY * 2, getSpecificity(".class_name:nth-child(3n + 1)")); + } + + @Test + public void test18() { + Assert.assertEquals(CssSpecificityConstants.CLASS_SPECIFICITY * 2, getSpecificity(".class_name:nth-child(2n - 3)")); + } + + @Test + public void test19() { + Assert.assertEquals(CssSpecificityConstants.CLASS_SPECIFICITY * 2, getSpecificity(".class_name:hover")); + } + + @Test + public void test20() { + Assert.assertEquals(CssSpecificityConstants.CLASS_SPECIFICITY, getSpecificity(":not(p)")); + } + + @Test + public void test21() { + Assert.assertEquals(CssSpecificityConstants.CLASS_SPECIFICITY, getSpecificity(":not(#id)")); + } + + @Test + public void test22() { + Assert.assertEquals(CssSpecificityConstants.CLASS_SPECIFICITY, getSpecificity(":not(.class_name)")); + } + + @Test + public void pageTest01() { + Assert.assertEquals(CssSpecificityConstants.ID_SPECIFICITY, getPageSelectorSpecificity("customPageName")); + } + + @Test + public void pageTest02() { + Assert.assertEquals(CssSpecificityConstants.ID_SPECIFICITY + CssSpecificityConstants.CLASS_SPECIFICITY, getPageSelectorSpecificity("customPageName:first")); + } + + @Test + public void pageTest03() { + Assert.assertEquals(CssSpecificityConstants.ID_SPECIFICITY + CssSpecificityConstants.CLASS_SPECIFICITY * 2, getPageSelectorSpecificity("customPageName:first:blank")); + } + + @Test + public void pageTest04() { + Assert.assertEquals(CssSpecificityConstants.ELEMENT_SPECIFICITY * 2, getPageSelectorSpecificity(":left:right")); + } + + @Test + public void pageTest05() { + Assert.assertEquals(CssSpecificityConstants.ID_SPECIFICITY + CssSpecificityConstants.CLASS_SPECIFICITY, getPageSelectorSpecificity("left:blank")); + } + + @Test + public void pageTest06() { + Assert.assertEquals(CssSpecificityConstants.ELEMENT_SPECIFICITY + CssSpecificityConstants.CLASS_SPECIFICITY, getPageSelectorSpecificity(":left:blank")); + } + + private int getSpecificity(String selector) { + return new CssSelector(selector).calculateSpecificity(); + } + + private int getPageSelectorSpecificity(String selector) { + return new CssPageSelector(selector).calculateSpecificity(); + } + +} diff --git a/src/test/java/com/itextpdf/styledxmlparser/css/util/CssUtilTest.java b/src/test/java/com/itextpdf/styledxmlparser/css/util/CssUtilTest.java new file mode 100644 index 0000000000..a7d196196f --- /dev/null +++ b/src/test/java/com/itextpdf/styledxmlparser/css/util/CssUtilTest.java @@ -0,0 +1,109 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 iText Group NV + Authors: iText Software. + + 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.styledxmlparser.css.util; + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; +import com.itextpdf.test.ExtendedITextTest; +import com.itextpdf.test.annotations.type.UnitTest; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import static org.junit.Assert.assertEquals; + +@Category(UnitTest.class) +public class CssUtilTest extends ExtendedITextTest { + + @Test + public void validateMetricValue() { + assertEquals(true, CssUtils.isMetricValue("1px")); + assertEquals(true, CssUtils.isMetricValue("1in")); + assertEquals(true, CssUtils.isMetricValue("1cm")); + assertEquals(true, CssUtils.isMetricValue("1mm")); + assertEquals(true, CssUtils.isMetricValue("1pc")); + assertEquals(false, CssUtils.isMetricValue("1em")); + assertEquals(false, CssUtils.isMetricValue("1rem")); + assertEquals(false,CssUtils.isMetricValue("1ex")); + assertEquals(true, CssUtils.isMetricValue("1pt")); + assertEquals(false, CssUtils.isMetricValue("1inch")); + assertEquals(false, CssUtils.isMetricValue("+1m")); + } + + @Test + public void validateNumericValue() { + assertEquals(true, CssUtils.isNumericValue("1")); + assertEquals(true, CssUtils.isNumericValue("12")); + assertEquals(true, CssUtils.isNumericValue("1.2")); + assertEquals(true, CssUtils.isNumericValue(".12")); + assertEquals(false, CssUtils.isNumericValue("12f")); + assertEquals(false, CssUtils.isNumericValue("f1.2")); + assertEquals(false, CssUtils.isNumericValue(".12f")); + } + + @Test + public void parseLength() { + assertEquals(9, CssUtils.parseAbsoluteLength("12"), 0); + assertEquals(576, CssUtils.parseAbsoluteLength("8inch"), 0); + assertEquals(576, CssUtils.parseAbsoluteLength("8", CommonCssConstants.IN), 0); + } + + @Test + public void normalizeProperty() { + assertEquals("part1 part2", CssUtils.normalizeCssProperty(" part1 part2 ")); + assertEquals("\" the next quote is ESCAPED \\\\\\\" still IN string \"", CssUtils.normalizeCssProperty("\" the next quote is ESCAPED \\\\\\\" still IN string \"")); + assertEquals("\" the next quote is NOT ESCAPED \\\\\" not in the string", CssUtils.normalizeCssProperty("\" the next quote is NOT ESCAPED \\\\\" NOT in THE string")); + assertEquals("\" You CAN put 'Single Quotes' in double quotes WITHOUT escaping\"", CssUtils.normalizeCssProperty("\" You CAN put 'Single Quotes' in double quotes WITHOUT escaping\"")); + assertEquals("' You CAN put \"DOUBLE Quotes\" in double quotes WITHOUT escaping'", CssUtils.normalizeCssProperty("' You CAN put \"DOUBLE Quotes\" in double quotes WITHOUT escaping'")); + assertEquals("\" ( BLA \" attr(href)\" BLA ) \"", CssUtils.normalizeCssProperty("\" ( BLA \" AttR( Href )\" BLA ) \"")); + assertEquals("\" ( \"attr(href) \" ) \"", CssUtils.normalizeCssProperty("\" ( \"aTTr( hREf ) \" ) \"")); + assertEquals("rgba(255,255,255,0.2)", CssUtils.normalizeCssProperty("rgba( 255, 255 , 255 ,0.2 )")); + } + + @Test + public void normalizeUrlTest() { + assertEquals("url(data:application/font-woff;base64,2CBPCRXmgywtV1t4oWwjBju0kqkvfhPs0cYdMgFtDSY5uL7MIGT5wiGs078HrvBHekp0Yf=)", + CssUtils.normalizeCssProperty("url(data:application/font-woff;base64,2CBPCRXmgywtV1t4oWwjBju0kqkvfhPs0cYdMgFtDSY5uL7MIGT5wiGs078HrvBHekp0Yf=)")); + assertEquals("url(\"quoted Url\")", CssUtils.normalizeCssProperty(" url( \"quoted Url\")")); + assertEquals("url('quoted Url')", CssUtils.normalizeCssProperty(" url( 'quoted Url')")); + assertEquals("url(haveEscapedEndBracket\\))", CssUtils.normalizeCssProperty("url( haveEscapedEndBracket\\) )")); + } +} diff --git a/src/test/java/com/itextpdf/styledxmlparser/css/util/CssUtilsTest.java b/src/test/java/com/itextpdf/styledxmlparser/css/util/CssUtilsTest.java index ed333e0c89..ec74243853 100644 --- a/src/test/java/com/itextpdf/styledxmlparser/css/util/CssUtilsTest.java +++ b/src/test/java/com/itextpdf/styledxmlparser/css/util/CssUtilsTest.java @@ -44,7 +44,7 @@ This file is part of the iText (R) project. import com.itextpdf.io.util.MessageFormatUtil; import com.itextpdf.styledxmlparser.LogMessageConstant; -import com.itextpdf.styledxmlparser.css.CssConstants; +import com.itextpdf.styledxmlparser.css.CommonCssConstants; import com.itextpdf.styledxmlparser.exceptions.StyledXMLParserException; import com.itextpdf.test.annotations.type.UnitTest; @@ -81,7 +81,7 @@ public void parseAbsoluteLengthFromNull() { @Test public void parseAbsoluteLengthFrom10px() { String value = "10px"; - float actual = CssUtils.parseAbsoluteLength(value, CssConstants.PX); + float actual = CssUtils.parseAbsoluteLength(value, CommonCssConstants.PX); float expected = 7.5f; Assert.assertEquals(expected, actual, 0); @@ -90,7 +90,7 @@ public void parseAbsoluteLengthFrom10px() { @Test public void parseAbsoluteLengthFrom10cm() { String value = "10cm"; - float actual = CssUtils.parseAbsoluteLength(value, CssConstants.CM); + float actual = CssUtils.parseAbsoluteLength(value, CommonCssConstants.CM); float expected = 283.46457f; Assert.assertEquals(expected, actual, 0); @@ -99,7 +99,7 @@ public void parseAbsoluteLengthFrom10cm() { @Test public void parseAbsoluteLengthFrom10in() { String value = "10in"; - float actual = CssUtils.parseAbsoluteLength(value, CssConstants.IN); + float actual = CssUtils.parseAbsoluteLength(value, CommonCssConstants.IN); float expected = 720.0f; Assert.assertEquals(expected, actual, 0); @@ -108,7 +108,7 @@ public void parseAbsoluteLengthFrom10in() { @Test public void parseAbsoluteLengthFrom10pt() { String value = "10pt"; - float actual = CssUtils.parseAbsoluteLength(value, CssConstants.PT); + float actual = CssUtils.parseAbsoluteLength(value, CommonCssConstants.PT); float expected = 10.0f; Assert.assertEquals(expected, actual, 0); diff --git a/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolverTest.java b/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolverTest.java index 8e7f3a52e4..cc043b448a 100644 --- a/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolverTest.java +++ b/src/test/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolverTest.java @@ -66,7 +66,7 @@ public class ResourceResolverTest extends ExtendedITextTest { public ExpectedException junitExpectedException = ExpectedException.none(); @Test - @LogMessages(messages = @LogMessage(messageTemplate = LogMessageConstant.UNABLE_TO_RETRIEVE_STREAM_WITH_GIVEN_BASE_URI, count = 1)) + @LogMessages(messages = @LogMessage(messageTemplate = LogMessageConstant.UNABLE_TO_RETRIEVE_STREAM_WITH_GIVEN_BASE_URI, count = 2)) public void malformedResourceNameTest() { String fileName = "resourceResolverTest .png"; ResourceResolver resourceResolver = new ResourceResolver(baseUri); From 4b3bf61e90ccccf9115244d7c0e793c9fee98300 Mon Sep 17 00:00:00 2001 From: Alexey Subach Date: Mon, 25 Jun 2018 13:47:29 +0300 Subject: [PATCH 15/23] Open QueryParser class Make this class public so it is possible to reuse Jsoup selection logic with custom html tree implementations. Essentially this commit restores the changes that were lost during migration of Jsoup from pdfHTML --- .../styledxmlparser/jsoup/select/QueryParser.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/itextpdf/styledxmlparser/jsoup/select/QueryParser.java b/src/main/java/com/itextpdf/styledxmlparser/jsoup/select/QueryParser.java index 208a6cdca4..7ff6b11440 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/jsoup/select/QueryParser.java +++ b/src/main/java/com/itextpdf/styledxmlparser/jsoup/select/QueryParser.java @@ -42,20 +42,20 @@ This file is part of the iText (R) project. */ package com.itextpdf.styledxmlparser.jsoup.select; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - import com.itextpdf.styledxmlparser.jsoup.PortUtil; import com.itextpdf.styledxmlparser.jsoup.helper.StringUtil; import com.itextpdf.styledxmlparser.jsoup.helper.Validate; import com.itextpdf.styledxmlparser.jsoup.parser.TokenQueue; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * Parses a CSS selector into an Evaluator tree. */ -class QueryParser { +public class QueryParser { private final static String[] combinators = {",", ">", "+", "~", " "}; private static final String[] AttributeEvals = new String[]{"=", "!=", "^=", "$=", "*=", "~="}; From 0eefd3e618e638c18d2eac458a46da174e237be3 Mon Sep 17 00:00:00 2001 From: Samuel Huylebroeck Date: Tue, 12 Jun 2018 10:30:53 +0200 Subject: [PATCH 16/23] Property Inheritance support RND-880 --- .../styledxmlparser/LogMessageConstant.java | 2 + .../css/resolve/CssInheritance.java | 6 +- .../css/resolve/CssPropertyMerger.java | 1 - .../css/resolve/IStyleInheritance.java | 14 ++ .../css/resolve/CssInheritanceUnitTest.java | 23 ++++ .../resolve/CssPropertyMergerUnitTest.java | 123 ++++++++++++++++++ 6 files changed, 165 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/itextpdf/styledxmlparser/css/resolve/IStyleInheritance.java create mode 100644 src/test/java/com/itextpdf/styledxmlparser/css/resolve/CssInheritanceUnitTest.java create mode 100644 src/test/java/com/itextpdf/styledxmlparser/css/resolve/CssPropertyMergerUnitTest.java diff --git a/src/main/java/com/itextpdf/styledxmlparser/LogMessageConstant.java b/src/main/java/com/itextpdf/styledxmlparser/LogMessageConstant.java index c7ab1a6196..a736a368e7 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/LogMessageConstant.java +++ b/src/main/java/com/itextpdf/styledxmlparser/LogMessageConstant.java @@ -75,6 +75,8 @@ public final class LogMessageConstant { public static final String UNSUPPORTED_PSEUDO_CSS_SELECTOR = "Unsupported pseudo css selector: {0}"; /** The Constant WAS_NOT_ABLE_TO_DEFINE_BACKGROUND_CSS_SHORTHAND_PROPERTIES. */ public static final String WAS_NOT_ABLE_TO_DEFINE_BACKGROUND_CSS_SHORTHAND_PROPERTIES = "Was not able to define one of the background CSS shorthand properties: {0}"; + /** The Constant ERROR_RESOLVING_PARENT_STYLES. */ + public static final String ERROR_RESOLVING_PARENT_STYLES = "Element parent styles are not resolved. Styles for current element might be incorrect."; /** * Instantiates a new log message constant. */ diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssInheritance.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssInheritance.java index 357532340d..50963c05e6 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssInheritance.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssInheritance.java @@ -43,7 +43,6 @@ This file is part of the iText (R) project. package com.itextpdf.styledxmlparser.css.resolve; import com.itextpdf.styledxmlparser.css.CommonCssConstants; - import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -51,7 +50,7 @@ This file is part of the iText (R) project. /** * Helper class that allows you to check if a property is inheritable. */ -public class CssInheritance { +public class CssInheritance implements IStyleInheritance { /** * Set of inheritable properties @@ -136,7 +135,8 @@ public class CssInheritance { * @param cssProperty the CSS property * @return true, if the property is inheritable */ - public static boolean isInheritable(String cssProperty) { + @Override + public boolean isInheritable(String cssProperty) { return inheritableProperties.contains(cssProperty); } } diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssPropertyMerger.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssPropertyMerger.java index 80403e850f..6a0fb07807 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssPropertyMerger.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssPropertyMerger.java @@ -43,7 +43,6 @@ This file is part of the iText (R) project. package com.itextpdf.styledxmlparser.css.resolve; import com.itextpdf.styledxmlparser.css.CommonCssConstants; - import java.util.Arrays; import java.util.LinkedHashSet; import java.util.Set; diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/IStyleInheritance.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/IStyleInheritance.java new file mode 100644 index 0000000000..4558f7c942 --- /dev/null +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/IStyleInheritance.java @@ -0,0 +1,14 @@ +package com.itextpdf.styledxmlparser.css.resolve; + +/** + * Interface for attribute and style-inheritance logic + */ +public interface IStyleInheritance { + /** + * Checks if a property or attribute is inheritable is inheritable. + * + * @param propertyIdentifier the identifier for property + * @return true, if the property is inheritable, false otherwise + */ + boolean isInheritable(String propertyIdentifier); +} diff --git a/src/test/java/com/itextpdf/styledxmlparser/css/resolve/CssInheritanceUnitTest.java b/src/test/java/com/itextpdf/styledxmlparser/css/resolve/CssInheritanceUnitTest.java new file mode 100644 index 0000000000..bff230705c --- /dev/null +++ b/src/test/java/com/itextpdf/styledxmlparser/css/resolve/CssInheritanceUnitTest.java @@ -0,0 +1,23 @@ +package com.itextpdf.styledxmlparser.css.resolve; + +import com.itextpdf.styledxmlparser.css.CommonCssConstants; +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 CssInheritanceUnitTest { + + @Test + public void isInheritablePositiveTest(){ + IStyleInheritance cssInheritance = new CssInheritance(); + Assert.assertTrue(cssInheritance.isInheritable(CommonCssConstants.FONT_SIZE)); + } + + @Test + public void isInheritableNegativeTest(){ + IStyleInheritance cssInheritance = new CssInheritance(); + Assert.assertFalse(cssInheritance.isInheritable(CommonCssConstants.FOCUS)); + } +} diff --git a/src/test/java/com/itextpdf/styledxmlparser/css/resolve/CssPropertyMergerUnitTest.java b/src/test/java/com/itextpdf/styledxmlparser/css/resolve/CssPropertyMergerUnitTest.java new file mode 100644 index 0000000000..8f870b7e96 --- /dev/null +++ b/src/test/java/com/itextpdf/styledxmlparser/css/resolve/CssPropertyMergerUnitTest.java @@ -0,0 +1,123 @@ +package com.itextpdf.styledxmlparser.css.resolve; + +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 CssPropertyMergerUnitTest { + + @Test + public void mergeTextDecorationSimpleTest(){ + String firstValue="underline"; + String secondValue="strikethrough bold"; + + String expected="underline strikethrough bold"; + String actual = CssPropertyMerger.mergeTextDecoration(firstValue,secondValue); + + Assert.assertEquals(expected,actual); + } + + @Test + public void mergeTextDecorationNormalizeFirstTest(){ + String firstValue=" underline "; + String secondValue="strikethrough bold"; + + String expected="underline strikethrough bold"; + String actual = CssPropertyMerger.mergeTextDecoration(firstValue,secondValue); + + Assert.assertEquals(expected,actual); + + } + + @Test + public void mergeTextDecorationNormalizeSecondTest(){ + String firstValue="underline"; + String secondValue="strikethrough bold "; + + String expected="underline strikethrough bold"; + String actual = CssPropertyMerger.mergeTextDecoration(firstValue,secondValue); + + Assert.assertEquals(expected,actual); + } + + @Test + public void mergeTextDecorationFirstNullTest(){ + String firstValue=null; + String secondValue="strikethrough bold"; + + String expected="strikethrough bold"; + String actual = CssPropertyMerger.mergeTextDecoration(firstValue,secondValue); + + Assert.assertEquals(expected,actual); + } + + @Test + public void mergeTextDecorationSecondNullTest(){ + String firstValue="underline"; + String secondValue=null; + + String expected="underline"; + String actual = CssPropertyMerger.mergeTextDecoration(firstValue,secondValue); + + Assert.assertEquals(expected,actual); + } + + @Test + public void mergeTextDecorationBothNullTest(){ + String firstValue=null; + String secondValue=null; + + String expected=null; + String actual = CssPropertyMerger.mergeTextDecoration(firstValue,secondValue); + + Assert.assertEquals(expected,actual); + } + + + @Test + public void mergeTextDecorationEmpyInputsTest(){ + String firstValue=""; + String secondValue=""; + + String expected="none"; + String actual = CssPropertyMerger.mergeTextDecoration(firstValue,secondValue); + + Assert.assertEquals(expected,actual); + } + + @Test + public void mergeTextDecorationSecondInputContainsNoneTest(){ + String firstValue="underline"; + String secondValue="none strikethrough"; + + String expected="underline"; + String actual = CssPropertyMerger.mergeTextDecoration(firstValue,secondValue); + + Assert.assertEquals(expected,actual); + } + + @Test + public void mergeTextDecorationFirstInputNoneTest(){ + String firstValue="underline none"; + String secondValue="strikethrough"; + + String expected="strikethrough"; + String actual = CssPropertyMerger.mergeTextDecoration(firstValue,secondValue); + + Assert.assertEquals(expected,actual); + } + + @Test + public void mergeTextDecorationBothInputsNoneTest(){ + String firstValue="underline none"; + String secondValue="strikethrough none"; + + String expected="none"; + String actual = CssPropertyMerger.mergeTextDecoration(firstValue,secondValue); + + Assert.assertEquals(expected,actual); + } + +} From a24c9857963a9eea5560bc79ac83aafb430c7e2f Mon Sep 17 00:00:00 2001 From: Samuel Huylebroeck Date: Mon, 25 Jun 2018 16:12:20 +0200 Subject: [PATCH 17/23] fix findbugs errors RND-880, DEVSIX-1955 --- .../css/CommonCssConstants.java | 20 +++++++++---------- .../item/CssPseudoClassNthSelectorItem.java | 6 +++--- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/CommonCssConstants.java b/src/main/java/com/itextpdf/styledxmlparser/css/CommonCssConstants.java index dc730ce3f7..a7401dc46e 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/CommonCssConstants.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/CommonCssConstants.java @@ -684,24 +684,24 @@ public class CommonCssConstants { // properties possible values /** The Constant BACKGROUND_SIZE_VALUES. */ - public static final Set BACKGROUND_SIZE_VALUES = new HashSet<>( - Arrays.asList(AUTO, COVER, CONTAIN)); + public static final Set BACKGROUND_SIZE_VALUES = Collections.unmodifiableSet(new HashSet<>( + Arrays.asList(AUTO, COVER, CONTAIN))); /** The Constant BACKGROUND_ORIGIN_OR_CLIP_VALUES. */ - public static final Set BACKGROUND_ORIGIN_OR_CLIP_VALUES = new HashSet<>( - Arrays.asList(PADDING_BOX, BORDER_BOX, CONTENT_BOX)); + public static final Set BACKGROUND_ORIGIN_OR_CLIP_VALUES = Collections.unmodifiableSet(new HashSet<>( + Arrays.asList(PADDING_BOX, BORDER_BOX, CONTENT_BOX))); /** The Constant BACKGROUND_REPEAT_VALUES. */ - public static final Set BACKGROUND_REPEAT_VALUES = new HashSet<>( - Arrays.asList(REPEAT, NO_REPEAT, REPEAT_X, REPEAT_Y)); + public static final Set BACKGROUND_REPEAT_VALUES = Collections.unmodifiableSet(new HashSet<>( + Arrays.asList(REPEAT, NO_REPEAT, REPEAT_X, REPEAT_Y))); /** The Constant BACKGROUND_ATTACHMENT_VALUES. */ - public static final Set BACKGROUND_ATTACHMENT_VALUES = new HashSet<>( - Arrays.asList(FIXED, SCROLL, LOCAL)); + public static final Set BACKGROUND_ATTACHMENT_VALUES = Collections.unmodifiableSet(new HashSet<>( + Arrays.asList(FIXED, SCROLL, LOCAL))); /** The Constant BACKGROUND_POSITION_VALUES. */ - public static final Set BACKGROUND_POSITION_VALUES = new HashSet<>( - Arrays.asList(LEFT, CENTER, BOTTOM, TOP, RIGHT)); + public static final Set BACKGROUND_POSITION_VALUES = Collections.unmodifiableSet(new HashSet<>( + Arrays.asList(LEFT, CENTER, BOTTOM, TOP, RIGHT))); /** The Constant BORDER_WIDTH_VALUES. */ public static final Set BORDER_WIDTH_VALUES = Collections.unmodifiableSet(new HashSet<>( diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassNthSelectorItem.java b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassNthSelectorItem.java index 41d695dd73..5b4608d5a7 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassNthSelectorItem.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/selector/item/CssPseudoClassNthSelectorItem.java @@ -46,7 +46,7 @@ protected void getNthArguments() { int indexOfN = arguments.indexOf('n'); if (indexOfN == -1) { this.nthA = 0; - this.nthB = Integer.valueOf(arguments); + this.nthB = Integer.parseInt(arguments); } else { String aParticle = arguments.substring(0, indexOfN).trim(); if (aParticle.isEmpty()) @@ -54,10 +54,10 @@ protected void getNthArguments() { else if (aParticle.length() == 1 && !Character.isDigit(aParticle.charAt(0))) this.nthA = aParticle.equals("+") ? 1 : -1; else - this.nthA = Integer.valueOf(aParticle); + this.nthA = Integer.parseInt(aParticle); String bParticle = arguments.substring(indexOfN + 1).trim(); if (!bParticle.isEmpty()) - this.nthB = Integer.valueOf(bParticle.charAt(0) + bParticle.substring(1).trim()); + this.nthB = Integer.parseInt(bParticle.charAt(0) + bParticle.substring(1).trim()); else this.nthB = 0; } From 49d65fac414456341be5b2ee26e3a48310c26748 Mon Sep 17 00:00:00 2001 From: Samuel Huylebroeck Date: Mon, 25 Jun 2018 16:58:35 +0200 Subject: [PATCH 18/23] Move display and inline block RND-880 --- .../com/itextpdf/styledxmlparser/css/CommonCssConstants.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/CommonCssConstants.java b/src/main/java/com/itextpdf/styledxmlparser/css/CommonCssConstants.java index a7401dc46e..71008792ba 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/CommonCssConstants.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/CommonCssConstants.java @@ -181,6 +181,9 @@ public class CommonCssConstants { /** The Constant DIRECTION. */ public static final String DIRECTION = "direction"; + /** The Constant DISPLAY. */ + public static final String DISPLAY = "display"; + /** The Constant EMPTY_CELLS. */ public static final String EMPTY_CELLS = "empty-cells"; @@ -246,6 +249,8 @@ public class CommonCssConstants { /** The Constant HYPHENS. */ public static final String HYPHENS = "hyphens"; + /** The Constant INLINE-BLOCK*/ + public static final String INLINE_BLOCK ="inline-block"; /** The Constant LETTER_SPACING. */ public static final String LETTER_SPACING = "letter-spacing"; From e68e3f1ccb1ad2966e87c5d38cfe5d3b408996ca Mon Sep 17 00:00:00 2001 From: Samuel Huylebroeck Date: Mon, 25 Jun 2018 16:58:35 +0200 Subject: [PATCH 19/23] Move display and inline block RND-880 RND-883 remove vulnerabilities --- .../com/itextpdf/styledxmlparser/css/page/CssMarginRule.java | 4 ++-- .../com/itextpdf/styledxmlparser/css/resolve/CssQuotes.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/page/CssMarginRule.java b/src/main/java/com/itextpdf/styledxmlparser/css/page/CssMarginRule.java index 223bee62fd..9b81f9916c 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/page/CssMarginRule.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/page/CssMarginRule.java @@ -47,6 +47,7 @@ This file is part of the iText (R) project. import com.itextpdf.styledxmlparser.css.selector.CssPageMarginBoxSelector; import com.itextpdf.styledxmlparser.css.selector.ICssSelector; +import java.util.ArrayList; import java.util.List; /** @@ -83,7 +84,6 @@ public void addBodyCssDeclarations(List cssDeclarations) { * @param pageSelectors the new page selectors */ void setPageSelectors(List pageSelectors) { - this.pageSelectors = pageSelectors; + this.pageSelectors = new ArrayList<>(pageSelectors); } - } diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssQuotes.java b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssQuotes.java index 3ee3ec196b..d4b680df66 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssQuotes.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/resolve/CssQuotes.java @@ -77,8 +77,8 @@ public class CssQuotes { * @param closeQuotes the close quotes */ private CssQuotes(ArrayList openQuotes, ArrayList closeQuotes) { - this.openQuotes = openQuotes; - this.closeQuotes = closeQuotes; + this.openQuotes = new ArrayList<>(openQuotes); + this.closeQuotes = new ArrayList<>(closeQuotes); } /** From e470e23836c54f7e2f63964a022f3cbd03fe4ae3 Mon Sep 17 00:00:00 2001 From: Pavel Alay Date: Fri, 13 Jul 2018 17:32:44 +0300 Subject: [PATCH 20/23] Remove collectCssDeclarations form ICssResolver interface RND-1056 --- .../itextpdf/styledxmlparser/css/ICssResolver.java | 12 ------------ .../resolver/resource/ResourceResolver.java | 1 + .../resolver/resource/UriResolver.java | 1 + 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/ICssResolver.java b/src/main/java/com/itextpdf/styledxmlparser/css/ICssResolver.java index d9f204fd96..151bca967a 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/ICssResolver.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/ICssResolver.java @@ -45,7 +45,6 @@ This file is part of the iText (R) project. import com.itextpdf.styledxmlparser.css.resolve.AbstractCssContext; import com.itextpdf.styledxmlparser.node.INode; -import com.itextpdf.styledxmlparser.resolver.resource.ResourceResolver; import java.util.Map; @@ -53,16 +52,6 @@ This file is part of the iText (R) project. * Interface for CSS resolvers. */ public interface ICssResolver { - - /** - * Collect all CSS declarations from the provided INode tree. - * - * @param rootNode tree from which to collect CSS - * @param resourceResolver ResourceResolver used to resolve resources - * @param context the CSS context (RootFontSize, etc.) - */ - void collectCssDeclarations(INode rootNode, ResourceResolver resourceResolver, AbstractCssContext context); - /** * Resolves the styles of a node given the passed context. * @@ -71,5 +60,4 @@ public interface ICssResolver { * @return the map containing the resolved styles */ Map resolveStyles(INode node, AbstractCssContext context); - } diff --git a/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolver.java b/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolver.java index 9e59a0a601..22cdc861c2 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolver.java +++ b/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/ResourceResolver.java @@ -93,6 +93,7 @@ public class ResourceResolver { * @param baseUri base URI against which all relative resource URIs will be resolved. */ public ResourceResolver(String baseUri) { + if (baseUri == null) baseUri = ""; this.uriResolver = new UriResolver(baseUri); this.imageCache = new SimpleImageCache(); } diff --git a/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolver.java b/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolver.java index 251f968523..44e4c4b12d 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolver.java +++ b/src/main/java/com/itextpdf/styledxmlparser/resolver/resource/UriResolver.java @@ -72,6 +72,7 @@ public class UriResolver { * @param baseUri the base URI */ public UriResolver(String baseUri) { + if (baseUri == null) throw new IllegalArgumentException("baseUri"); resolveBaseUrlOrPath(baseUri); } From 9f306ab5995f6c43f9ffcdbb72f2a77e000a6ba0 Mon Sep 17 00:00:00 2001 From: Vladimir Osipchuk Date: Tue, 10 Jul 2018 13:13:07 +0300 Subject: [PATCH 21/23] Add util methods for parsing unicode range strings. Add a test. DEVSIX-1998 --- .../styledxmlparser/css/util/CssUtils.java | 72 +++++++++++++++---- .../styledxmlparser/css/util/CssUtilTest.java | 19 ++++- 2 files changed, 77 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/itextpdf/styledxmlparser/css/util/CssUtils.java b/src/main/java/com/itextpdf/styledxmlparser/css/util/CssUtils.java index 0bd34ba972..f45560e56e 100644 --- a/src/main/java/com/itextpdf/styledxmlparser/css/util/CssUtils.java +++ b/src/main/java/com/itextpdf/styledxmlparser/css/util/CssUtils.java @@ -44,11 +44,12 @@ This file is part of the iText (R) project. import com.itextpdf.io.util.MessageFormatUtil; import com.itextpdf.kernel.colors.WebColors; +import com.itextpdf.layout.font.Range; +import com.itextpdf.layout.font.RangeBuilder; import com.itextpdf.layout.property.UnitValue; import com.itextpdf.styledxmlparser.LogMessageConstant; import com.itextpdf.styledxmlparser.css.CommonCssConstants; import com.itextpdf.styledxmlparser.exceptions.StyledXMLParserException; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -57,8 +58,8 @@ This file is part of the iText (R) project. */ public class CssUtils { - private static final String[] METRIC_MEASUREMENTS = new String[] {CommonCssConstants.PX, CommonCssConstants.IN, CommonCssConstants.CM, CommonCssConstants.MM, CommonCssConstants.PC, CommonCssConstants.PT}; - private static final String[] RELATIVE_MEASUREMENTS = new String[] {CommonCssConstants.PERCENTAGE, CommonCssConstants.EM, CommonCssConstants.EX, CommonCssConstants.REM}; + private static final String[] METRIC_MEASUREMENTS = new String[]{CommonCssConstants.PX, CommonCssConstants.IN, CommonCssConstants.CM, CommonCssConstants.MM, CommonCssConstants.PC, CommonCssConstants.PT}; + private static final String[] RELATIVE_MEASUREMENTS = new String[]{CommonCssConstants.PERCENTAGE, CommonCssConstants.EM, CommonCssConstants.EX, CommonCssConstants.REM}; private static final float EPSILON = 0.000000000000001f; /** @@ -163,7 +164,7 @@ public static float parseAbsoluteLength(String length, String defaultMetric) { int pos = determinePositionBetweenValueAndUnit(length); if (pos == 0) { - if ( length == null ) { + if (length == null) { length = "null"; } throw new StyledXMLParserException(MessageFormatUtil.format(LogMessageConstant.NAN, length)); @@ -242,13 +243,13 @@ public static float parseRelativeValue(final String relativeValue, final float b /** * Convenience method for parsing a value to pt. Possible values are:
    - *
  • a numeric value in pixels (e.g. 123, 1.23, .123),
  • - *
  • a value with a metric unit (px, in, cm, mm, pc or pt) attached to it,
  • - *
  • or a value with a relative value (%, em, ex).
  • + *
  • a numeric value in pixels (e.g. 123, 1.23, .123),
  • + *
  • a value with a metric unit (px, in, cm, mm, pc or pt) attached to it,
  • + *
  • or a value with a relative value (%, em, ex).
  • *
* - * @param value the value - * @param emValue the em value + * @param value the value + * @param emValue the em value * @param remValue the root em value * @return the unit value */ @@ -269,8 +270,8 @@ public static UnitValue parseLengthValueToPt(final String value, final float emV * Parses the border radius of specific corner. * * @param specificBorderRadius string that defines the border radius of specific corner. - * @param emValue the em value - * @param remValue the root em value + * @param emValue the em value + * @param remValue the root em value * @return an array of {@link UnitValue UnitValues} that define horizontal and vertical border radius values */ public static UnitValue[] parseSpecificCornerBorderRadius(String specificBorderRadius, final float emValue, final float remValue) { @@ -425,8 +426,8 @@ public static boolean isBase64Data(String data) { /** * Find the next unescaped character. * - * @param source a source - * @param ch the character to look for + * @param source a source + * @param ch the character to look for * @param startIndex where to start looking * @return the position of the next unescaped character */ @@ -455,11 +456,13 @@ public static boolean isColorProperty(String value) { /** * Helper method for comparing floating point numbers + * * @return true if both floating point numbers are close enough to be considered equal */ public static boolean compareFloats(double f1, double f2) { return (Math.abs(f1 - f2) < EPSILON); } + /** * Parses the RGBA color. * @@ -476,4 +479,47 @@ public static float[] parseRgbaColor(String colorValue) { return rgbaColor; } + /** + * Parses the unicode range. + * + * @param unicodeRange the string which stores the unicode range + * @return the unicode range as a {@link Range} object + */ + public static Range parseUnicodeRange(String unicodeRange) { + String[] ranges = unicodeRange.split(","); + RangeBuilder builder = new RangeBuilder(); + for (String range : ranges) { + if (!addRange(builder, range)) { + return null; + } + } + return builder.create(); + } + + private static boolean addRange(RangeBuilder builder, String range) { + range = range.trim(); + if (range.matches("[uU]\\+[0-9a-fA-F?]{1,6}(-[0-9a-fA-F]{1,6})?")) { + String[] parts = range.substring(2, range.length()).split("-"); + if (1 == parts.length) { + if (parts[0].contains("?")) { + return addRange(builder, parts[0].replace('?', '0'), parts[0].replace('?', 'F')); + } else { + return addRange(builder, parts[0], parts[0]); + } + } else { + return addRange(builder, parts[0], parts[1]); + } + } + return false; + } + + private static boolean addRange(RangeBuilder builder, String left, String right) { + int l = Integer.parseInt(left, 16); + int r = Integer.parseInt(right, 16); + if (l > r || r > 1114111) { // Although Firefox follows the spec (and therefore the second condition), it seems it's ignored in Chrome or Edge + return false; + } + builder.addRange(l, r); + return true; + } } diff --git a/src/test/java/com/itextpdf/styledxmlparser/css/util/CssUtilTest.java b/src/test/java/com/itextpdf/styledxmlparser/css/util/CssUtilTest.java index a7d196196f..fab3ce86a6 100644 --- a/src/test/java/com/itextpdf/styledxmlparser/css/util/CssUtilTest.java +++ b/src/test/java/com/itextpdf/styledxmlparser/css/util/CssUtilTest.java @@ -49,6 +49,7 @@ This file is part of the iText (R) project. import org.junit.experimental.categories.Category; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; @Category(UnitTest.class) public class CssUtilTest extends ExtendedITextTest { @@ -62,7 +63,7 @@ public void validateMetricValue() { assertEquals(true, CssUtils.isMetricValue("1pc")); assertEquals(false, CssUtils.isMetricValue("1em")); assertEquals(false, CssUtils.isMetricValue("1rem")); - assertEquals(false,CssUtils.isMetricValue("1ex")); + assertEquals(false, CssUtils.isMetricValue("1ex")); assertEquals(true, CssUtils.isMetricValue("1pt")); assertEquals(false, CssUtils.isMetricValue("1inch")); assertEquals(false, CssUtils.isMetricValue("+1m")); @@ -106,4 +107,20 @@ public void normalizeUrlTest() { assertEquals("url('quoted Url')", CssUtils.normalizeCssProperty(" url( 'quoted Url')")); assertEquals("url(haveEscapedEndBracket\\))", CssUtils.normalizeCssProperty("url( haveEscapedEndBracket\\) )")); } + + @Test + public void parseUnicodeRangeTest() { + assertEquals("[(0; 1048575)]", CssUtils.parseUnicodeRange("U+?????").toString()); + assertEquals("[(38; 38)]", CssUtils.parseUnicodeRange("U+26").toString()); + assertEquals("[(0; 127)]", CssUtils.parseUnicodeRange(" U+0-7F").toString()); + assertEquals("[(37; 255)]", CssUtils.parseUnicodeRange("U+0025-00FF").toString()); + assertEquals("[(1024; 1279)]", CssUtils.parseUnicodeRange("U+4??").toString()); + assertEquals("[(262224; 327519)]", CssUtils.parseUnicodeRange("U+4??5?").toString()); + assertEquals("[(37; 255), (1024; 1279)]", CssUtils.parseUnicodeRange("U+0025-00FF, U+4??").toString()); + + assertNull(CssUtils.parseUnicodeRange("U+??????")); // more than 5 question marks are not allowed + assertNull(CssUtils.parseUnicodeRange("UU+7-10")); // wrong syntax + assertNull(CssUtils.parseUnicodeRange("U+7?-9?")); // wrong syntax + assertNull(CssUtils.parseUnicodeRange("U+7-")); // wrong syntax + } } From 1e50abbb5ae8f4117bc557b020606d953b35371b Mon Sep 17 00:00:00 2001 From: Vladimir Osipchuk Date: Thu, 19 Jul 2018 16:52:07 +0300 Subject: [PATCH 22/23] Merge CssUtilsTest and CssUtilTest. DEVSIX-1998 DEVSIX-2053 --- .../styledxmlparser/css/util/CssUtilTest.java | 75 +++++++++++ .../css/util/CssUtilsTest.java | 125 ------------------ 2 files changed, 75 insertions(+), 125 deletions(-) delete mode 100644 src/test/java/com/itextpdf/styledxmlparser/css/util/CssUtilsTest.java diff --git a/src/test/java/com/itextpdf/styledxmlparser/css/util/CssUtilTest.java b/src/test/java/com/itextpdf/styledxmlparser/css/util/CssUtilTest.java index fab3ce86a6..7298e57b8d 100644 --- a/src/test/java/com/itextpdf/styledxmlparser/css/util/CssUtilTest.java +++ b/src/test/java/com/itextpdf/styledxmlparser/css/util/CssUtilTest.java @@ -42,11 +42,19 @@ This file is part of the iText (R) project. */ package com.itextpdf.styledxmlparser.css.util; +import com.itextpdf.io.util.MessageFormatUtil; +import com.itextpdf.styledxmlparser.LogMessageConstant; import com.itextpdf.styledxmlparser.css.CommonCssConstants; +import com.itextpdf.styledxmlparser.exceptions.StyledXMLParserException; 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.Assert; +import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.junit.rules.ExpectedException; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -54,6 +62,73 @@ This file is part of the iText (R) project. @Category(UnitTest.class) public class CssUtilTest extends ExtendedITextTest { + @Rule + public ExpectedException junitExpectedException = ExpectedException.none(); + + @Test + public void parseAbsoluteLengthFromNAN() { + junitExpectedException.expect(StyledXMLParserException.class); + junitExpectedException.expectMessage(MessageFormatUtil.format(LogMessageConstant.NAN, "Definitely not a number")); + + String value = "Definitely not a number"; + CssUtils.parseAbsoluteLength(value); + } + + @Test + public void parseAbsoluteLengthFromNull() { + junitExpectedException.expect(StyledXMLParserException.class); + junitExpectedException.expectMessage(MessageFormatUtil.format(LogMessageConstant.NAN, "null")); + + String value = null; + CssUtils.parseAbsoluteLength(value); + } + + @Test + public void parseAbsoluteLengthFrom10px() { + String value = "10px"; + float actual = CssUtils.parseAbsoluteLength(value, CommonCssConstants.PX); + float expected = 7.5f; + + Assert.assertEquals(expected, actual, 0); + } + + @Test + public void parseAbsoluteLengthFrom10cm() { + String value = "10cm"; + float actual = CssUtils.parseAbsoluteLength(value, CommonCssConstants.CM); + float expected = 283.46457f; + + Assert.assertEquals(expected, actual, 0); + } + + @Test + public void parseAbsoluteLengthFrom10in() { + String value = "10in"; + float actual = CssUtils.parseAbsoluteLength(value, CommonCssConstants.IN); + float expected = 720.0f; + + Assert.assertEquals(expected, actual, 0); + } + + @Test + public void parseAbsoluteLengthFrom10pt() { + String value = "10pt"; + float actual = CssUtils.parseAbsoluteLength(value, CommonCssConstants.PT); + float expected = 10.0f; + + Assert.assertEquals(expected, actual, 0); + } + + @Test + @LogMessages(messages = {@LogMessage(messageTemplate = LogMessageConstant.UNKNOWN_ABSOLUTE_METRIC_LENGTH_PARSED, count = 1)}) + public void parseAbsoluteLengthFromUnknownType() { + String value = "10pateekes"; + float actual = CssUtils.parseAbsoluteLength(value, "pateekes"); + float expected = 10.0f; + + Assert.assertEquals(expected, actual, 0); + } + @Test public void validateMetricValue() { assertEquals(true, CssUtils.isMetricValue("1px")); diff --git a/src/test/java/com/itextpdf/styledxmlparser/css/util/CssUtilsTest.java b/src/test/java/com/itextpdf/styledxmlparser/css/util/CssUtilsTest.java deleted file mode 100644 index ec74243853..0000000000 --- a/src/test/java/com/itextpdf/styledxmlparser/css/util/CssUtilsTest.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - This file is part of the iText (R) project. - Copyright (c) 1998-2018 iText Group NV - Authors: iText Software. - - 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.styledxmlparser.css.util; - -import com.itextpdf.io.util.MessageFormatUtil; -import com.itextpdf.styledxmlparser.LogMessageConstant; -import com.itextpdf.styledxmlparser.css.CommonCssConstants; -import com.itextpdf.styledxmlparser.exceptions.StyledXMLParserException; -import com.itextpdf.test.annotations.type.UnitTest; - -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; - -@Category(UnitTest.class) -public class CssUtilsTest { - - @Rule - public ExpectedException junitExpectedException = ExpectedException.none(); - - @Test - public void parseAbsoluteLengthFromNAN() { - junitExpectedException.expect(StyledXMLParserException.class); - junitExpectedException.expectMessage(MessageFormatUtil.format(LogMessageConstant.NAN, "Definitely not a number")); - - String value = "Definitely not a number"; - CssUtils.parseAbsoluteLength(value); - } - - @Test - public void parseAbsoluteLengthFromNull() { - junitExpectedException.expect(StyledXMLParserException.class); - junitExpectedException.expectMessage(MessageFormatUtil.format(LogMessageConstant.NAN, "null")); - - String value = null; - CssUtils.parseAbsoluteLength(value); - } - - @Test - public void parseAbsoluteLengthFrom10px() { - String value = "10px"; - float actual = CssUtils.parseAbsoluteLength(value, CommonCssConstants.PX); - float expected = 7.5f; - - Assert.assertEquals(expected, actual, 0); - } - - @Test - public void parseAbsoluteLengthFrom10cm() { - String value = "10cm"; - float actual = CssUtils.parseAbsoluteLength(value, CommonCssConstants.CM); - float expected = 283.46457f; - - Assert.assertEquals(expected, actual, 0); - } - - @Test - public void parseAbsoluteLengthFrom10in() { - String value = "10in"; - float actual = CssUtils.parseAbsoluteLength(value, CommonCssConstants.IN); - float expected = 720.0f; - - Assert.assertEquals(expected, actual, 0); - } - - @Test - public void parseAbsoluteLengthFrom10pt() { - String value = "10pt"; - float actual = CssUtils.parseAbsoluteLength(value, CommonCssConstants.PT); - float expected = 10.0f; - - Assert.assertEquals(expected, actual, 0); - } - - @Test - public void parseAbsoluteLengthFromUnknownType() { - String value = "10pateekes"; - float actual = CssUtils.parseAbsoluteLength(value, "pateekes"); - float expected = 10.0f; - - Assert.assertEquals(expected, actual, 0); - } -} \ No newline at end of file From c515f92bac238d71576cba7d126f774f8eb22c12 Mon Sep 17 00:00:00 2001 From: iText Software Date: Fri, 27 Jul 2018 16:21:39 +0200 Subject: [PATCH 23/23] [RELEASE] 7.1.3-SNAPSHOT -> 7.1.3 --- pom.xml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index 82ba8d69c1..4dc9e8ee45 100644 --- a/pom.xml +++ b/pom.xml @@ -1,25 +1,20 @@ 4.0.0 - com.itextpdf root - 7.1.3-SNAPSHOT - + 7.1.3 + - styled-xml-parser - iText 7 - Styled XML Parser Styled XML parser is used by iText7 modules to parse HTML and XML http://itextpdf.com/ - ${project.parent.version} 2.10.4 - com.itextpdf @@ -43,7 +38,6 @@ test -