first commit
This commit is contained in:
commit
4d332ef662
27586 changed files with 3281783 additions and 0 deletions
87
rus/WEB-INF/lib/xmlworker-5.5.10_src/META-INF/MANIFEST.MF
Normal file
87
rus/WEB-INF/lib/xmlworker-5.5.10_src/META-INF/MANIFEST.MF
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
Manifest-Version: 1.0
|
||||
Archiver-Version: Plexus Archiver
|
||||
Created-By: Apache Maven Bundle Plugin
|
||||
Built-By: jenkins
|
||||
Build-Jdk: 1.8.0_66
|
||||
Implementation-Title: iText XML Worker
|
||||
Implementation-Version: 5.5.10
|
||||
Implementation-Vendor-Id: com.itextpdf.tool
|
||||
Implementation-Build: ${buildNumber}
|
||||
Bundle-Description: Parses XML to PDF, with CSS support, using iText
|
||||
Bundle-License: http://www.fsf.org/licensing/licenses/agpl-3.0.html
|
||||
Bundle-SymbolicName: com.itextpdf.tool.xmlworker
|
||||
Bundle-ManifestVersion: 2
|
||||
Bnd-LastModified: 1475839836251
|
||||
Import-Package: com.itextpdf.text;resolution:=optional,com.itextpdf.te
|
||||
xt.api;resolution:=optional,com.itextpdf.text.html;resolution:=option
|
||||
al,com.itextpdf.text.log;resolution:=optional,com.itextpdf.text.pdf;r
|
||||
esolution:=optional,com.itextpdf.text.pdf.draw;resolution:=optional,c
|
||||
om.itextpdf.text.xml;resolution:=optional,com.itextpdf.text.xml.simpl
|
||||
eparser;resolution:=optional
|
||||
Tool: Bnd-1.15.0
|
||||
Export-Package: com.itextpdf.tool.xml.pipeline;uses:="com.itextpdf.too
|
||||
l.xml,com.itextpdf.tool.xml.exceptions,com.itextpdf.text",com.itextpd
|
||||
f.tool.xml.pipeline.end;uses:="com.itextpdf.tool.xml.pipeline,com.ite
|
||||
xtpdf.tool.xml,com.itextpdf.text.log,com.itextpdf.tool.xml.pipeline.c
|
||||
tx,com.itextpdf.text,com.itextpdf.tool.xml.exceptions,com.itextpdf.te
|
||||
xt.pdf",com.itextpdf.tool.xml.net.exc;uses:="com.itextpdf.tool.xml.ex
|
||||
ceptions",com.itextpdf.tool.xml.css;uses:="com.itextpdf.text,com.itex
|
||||
tpdf.tool.xml,com.itextpdf.tool.xml.css.parser,com.itextpdf.tool.xml.
|
||||
net,com.itextpdf.tool.xml.css.apply,com.itextpdf.text.html,com.itextp
|
||||
df.tool.xml.exceptions,com.itextpdf.tool.xml.html,com.itextpdf.tool.x
|
||||
ml.pipeline.css",com.itextpdf.tool.xml.parser;uses:="com.itextpdf.too
|
||||
l.xml.parser.state,com.itextpdf.text.xml,com.itextpdf.text.xml.simple
|
||||
parser,com.itextpdf.tool.xml.parser.io",com.itextpdf.tool.xml.pipelin
|
||||
e.css;uses:="com.itextpdf.tool.xml.css,com.itextpdf.tool.xml.net,com.
|
||||
itextpdf.tool.xml,com.itextpdf.tool.xml.exceptions,com.itextpdf.tool.
|
||||
xml.pipeline,com.itextpdf.tool.xml.pipeline.ctx",com.itextpdf.tool.xm
|
||||
l.net;uses:="com.itextpdf.text.log,com.itextpdf.tool.xml.exceptions,c
|
||||
om.itextpdf.tool.xml.net.exc,com.itextpdf.tool.xml.pipeline.html,com.
|
||||
itextpdf.text",com.itextpdf.tool.xml.parser.state;uses:="com.itextpdf
|
||||
.tool.xml.parser,com.itextpdf.tool.xml.html,com.itextpdf.text.xml.sim
|
||||
pleparser",com.itextpdf.tool.xml.html.head;uses:="com.itextpdf.text.l
|
||||
og,com.itextpdf.tool.xml.pipeline.css,com.itextpdf.tool.xml,com.itext
|
||||
pdf.text,com.itextpdf.tool.xml.html,com.itextpdf.tool.xml.exceptions,
|
||||
com.itextpdf.tool.xml.pipeline.html,com.itextpdf.text.pdf",com.itextp
|
||||
df.tool.xml;uses:="com.itextpdf.tool.xml.pipeline,com.itextpdf.tool.x
|
||||
ml.exceptions,com.itextpdf.tool.xml.pipeline.ctx,com.itextpdf.tool.xm
|
||||
l.parser,com.itextpdf.text,com.itextpdf.text.pdf,com.itextpdf.tool.xm
|
||||
l.pipeline.end,com.itextpdf.tool.xml.css,com.itextpdf.tool.xml.pipeli
|
||||
ne.css,com.itextpdf.tool.xml.pipeline.html,com.itextpdf.tool.xml.html
|
||||
",com.itextpdf.tool.xml.parser.io;uses:="com.itextpdf.tool.xml.parser
|
||||
",com.itextpdf.tool.xml.exceptions,com.itextpdf.tool.xml.css.apply;us
|
||||
es:="com.itextpdf.tool.xml.css,com.itextpdf.tool.xml.pipeline.html,co
|
||||
m.itextpdf.text.html,com.itextpdf.tool.xml,com.itextpdf.text,com.itex
|
||||
tpdf.text.pdf,com.itextpdf.tool.xml.html,com.itextpdf.tool.xml.net.ex
|
||||
c,com.itextpdf.tool.xml.net,com.itextpdf.tool.xml.exceptions,com.itex
|
||||
tpdf.text.log,com.itextpdf.tool.xml.html.table,com.itextpdf.tool.xml.
|
||||
html.pdfelement,com.itextpdf.text.pdf.draw",com.itextpdf.tool.xml.htm
|
||||
l.table;uses:="com.itextpdf.text,com.itextpdf.text.pdf,com.itextpdf.t
|
||||
ool.xml.css,com.itextpdf.tool.xml,com.itextpdf.tool.xml.exceptions,co
|
||||
m.itextpdf.tool.xml.css.apply,com.itextpdf.text.log,com.itextpdf.tool
|
||||
.xml.html.pdfelement,com.itextpdf.tool.xml.pipeline.html,com.itextpdf
|
||||
.text.html,com.itextpdf.tool.xml.html,com.itextpdf.text.pdf.draw",com
|
||||
.itextpdf.tool.xml.css.parser.state;uses:="com.itextpdf.tool.xml.css.
|
||||
parser",com.itextpdf.tool.xml.pipeline.ctx;uses:="com.itextpdf.tool.x
|
||||
ml",com.itextpdf.tool.xml.util;uses:="com.itextpdf.tool.xml,com.itext
|
||||
pdf.tool.xml.html",com.itextpdf.tool.xml.html.pdfelement;uses:="com.i
|
||||
textpdf.tool.xml.html.table,com.itextpdf.text.pdf,com.itextpdf.text.a
|
||||
pi,com.itextpdf.text,com.itextpdf.text.pdf.draw",com.itextpdf.tool.xm
|
||||
l.pipeline.html;uses:="com.itextpdf.text,com.itextpdf.tool.xml.pipeli
|
||||
ne,com.itextpdf.tool.xml.pipeline.end,com.itextpdf.tool.xml.css,com.i
|
||||
textpdf.tool.xml.pipeline.ctx,com.itextpdf.tool.xml,com.itextpdf.text
|
||||
.pdf,com.itextpdf.tool.xml.exceptions,com.itextpdf.tool.xml.html,com.
|
||||
itextpdf.tool.xml.css.apply",com.itextpdf.tool.xml.css.parser;uses:="
|
||||
com.itextpdf.tool.xml.css,com.itextpdf.tool.xml,com.itextpdf.tool.xml
|
||||
.css.parser.state",com.itextpdf.tool.xml.html;uses:="com.itextpdf.too
|
||||
l.xml.css,com.itextpdf.text.api,com.itextpdf.tool.xml.pipeline.css,co
|
||||
m.itextpdf.tool.xml,com.itextpdf.text.pdf.draw,com.itextpdf.text,com.
|
||||
itextpdf.tool.xml.exceptions,com.itextpdf.text.pdf,com.itextpdf.tool.
|
||||
xml.pipeline.ctx,com.itextpdf.tool.xml.util,com.itextpdf.tool.xml.htm
|
||||
l.pdfelement,com.itextpdf.tool.xml.pipeline.html,com.itextpdf.text.lo
|
||||
g,com.itextpdf.tool.xml.pipeline.end,com.itextpdf.tool.xml.css.apply,
|
||||
com.itextpdf.text.html,com.itextpdf.tool.xml.net.exc,com.itextpdf.tex
|
||||
t.xml,com.itextpdf.tool.xml.net"
|
||||
Bundle-Version: 5.5.10
|
||||
Bundle-Name: iText XML Worker
|
||||
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
#Generated by Maven
|
||||
#Fri Oct 07 13:30:36 CEST 2016
|
||||
version=5.5.10
|
||||
groupId=com.itextpdf.tool
|
||||
artifactId=xmlworker
|
||||
|
|
@ -0,0 +1,271 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.itextpdf</groupId>
|
||||
<artifactId>itext-parent</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<relativePath />
|
||||
</parent>
|
||||
|
||||
<groupId>com.itextpdf.tool</groupId>
|
||||
<artifactId>xmlworker</artifactId>
|
||||
<version>5.5.10</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>iText XML Worker</name>
|
||||
<description>Parses XML to PDF, with CSS support, using iText</description>
|
||||
<url>http://www.itextpdf.com/</url>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>GNU Affero General Public License v3</name>
|
||||
<url>http://www.fsf.org/licensing/licenses/agpl-3.0.html</url>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<developers>
|
||||
</developers>
|
||||
|
||||
<mailingLists>
|
||||
<mailingList>
|
||||
<name>iText on StackOverflow</name>
|
||||
<subscribe>
|
||||
http://stackoverflow.com/questions/tagged/itext
|
||||
</subscribe>
|
||||
<archive>
|
||||
http://stackoverflow.com/questions/tagged/itext
|
||||
</archive>
|
||||
<otherArchives>
|
||||
<otherArchive>http://news.gmane.org/gmane.comp.java.lib.itext.general</otherArchive>
|
||||
<otherArchive>http://itext-general.2136553.n4.nabble.com/</otherArchive>
|
||||
<otherArchive>http://www.junlu.com/2.html</otherArchive>
|
||||
<otherArchive>http://sourceforge.net/mailarchive/forum.php?forum_id=3273</otherArchive>
|
||||
<otherArchive>http://www.mail-archive.com/itext-questions%40lists.sourceforge.net/</otherArchive>
|
||||
</otherArchives>
|
||||
</mailingList>
|
||||
</mailingLists>
|
||||
|
||||
<scm>
|
||||
<connection>scm:git:git@github.com:itext/itextpdf.git</connection>
|
||||
<url>https://github.com/itext/itextpdf</url>
|
||||
</scm>
|
||||
|
||||
<issueManagement>
|
||||
<system>jira</system>
|
||||
<url>https://jira.itextsupport.com/</url>
|
||||
</issueManagement>
|
||||
|
||||
<ciManagement>
|
||||
<system>jenkins-ci</system>
|
||||
<url>http://ci.itextsupport.com/</url>
|
||||
</ciManagement>
|
||||
|
||||
<properties>
|
||||
<java.version>1.5</java.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<sonar.language>java</sonar.language>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.itextpdf</groupId>
|
||||
<artifactId>itextpdf</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.8.2</version>
|
||||
<type>jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.0.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.3</version>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>buildnumber-maven-plugin</artifactId>
|
||||
<version>1.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>validate</phase>
|
||||
<goals>
|
||||
<goal>create</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<doCheck>false</doCheck>
|
||||
<doUpdate>false</doUpdate>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<!-- Add osgi meta data to manifest file -->
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<version>2.3.4</version>
|
||||
<extensions>true</extensions>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>bundle-manifest</id>
|
||||
<phase>process-classes</phase>
|
||||
<!-- bind the manifest.mf generation after the 'compile' phase -->
|
||||
<goals>
|
||||
<goal>manifest</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<unpackBundle>true</unpackBundle>
|
||||
<instructions>
|
||||
<Export-Package>com.itextpdf.tool.xml.*</Export-Package>
|
||||
<Import-Package>com.itextpdf.text.*</Import-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.3.1</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
|
||||
<manifest>
|
||||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
||||
</manifest>
|
||||
<manifestEntries>
|
||||
<Implementation-Build>${buildNumber}</Implementation-Build>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.9</version>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>**/*.java</include>
|
||||
</includes>
|
||||
<excludes>
|
||||
<exclude>examples/*.java</exclude>
|
||||
<exclude>com/itextpdf/tool/xml/examples/*.java</exclude>
|
||||
<exclude>com/itextpdf/tool/xml/BugRunnerTest.java</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>external.atlassian.jgitflow</groupId>
|
||||
<artifactId>jgitflow-maven-plugin</artifactId>
|
||||
<version>1.0-m5.1</version>
|
||||
<configuration>
|
||||
<flowInitContext>
|
||||
<masterBranchName>master</masterBranchName>
|
||||
<developBranchName>develop</developBranchName>
|
||||
<featureBranchPrefix>feature/</featureBranchPrefix>
|
||||
<releaseBranchPrefix>release/</releaseBranchPrefix>
|
||||
<hotfixBranchPrefix>hotfix/</hotfixBranchPrefix>
|
||||
<versionTagPrefix />
|
||||
</flowInitContext>
|
||||
<allowUntracked>true</allowUntracked>
|
||||
<autoVersionSubmodules>true</autoVersionSubmodules>
|
||||
<updateDependencies>true</updateDependencies>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
|
||||
<profile>
|
||||
<id>all</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.10.3</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<links>
|
||||
<link>http://developers.itextpdf.com/reference/classes</link>
|
||||
</links>
|
||||
<footer><![CDATA[
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-11854164-1', 'itextpdf.com');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
]]></footer>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>snapshot</id>
|
||||
<build>
|
||||
<finalName>${project.artifactId}-${project.version}-rev${buildNumber}</finalName>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>doclint-java8-disable</id>
|
||||
<activation>
|
||||
<jdk>[1.8,)</jdk>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.10.3</version>
|
||||
<configuration>
|
||||
<additionalparam>-Xdoclint:none</additionalparam>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
</profiles>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
package com.itextpdf.tool.xml;
|
||||
|
||||
public interface CustomContext {}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package com.itextpdf.tool.xml;
|
||||
|
||||
public interface ElementHandler {
|
||||
void add(Writable paramWritable);
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.itextpdf.tool.xml;
|
||||
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.tool.xml.pipeline.WritableElement;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ElementList extends ArrayList<Element> implements ElementHandler {
|
||||
private static final long serialVersionUID = -3943194552607332537L;
|
||||
|
||||
public void add(Writable w) {
|
||||
if (w instanceof WritableElement)
|
||||
addAll(((WritableElement)w).elements());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.itextpdf.tool.xml;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Inherited
|
||||
public @interface Experimental {
|
||||
String value() default "";
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.itextpdf.tool.xml;
|
||||
|
||||
public class NoCustomContextException extends Exception {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public NoCustomContextException() {}
|
||||
|
||||
public NoCustomContextException(String arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
|
||||
public NoCustomContextException(Throwable arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
|
||||
public NoCustomContextException(String arg0, Throwable arg1) {
|
||||
super(arg0, arg1);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.itextpdf.tool.xml;
|
||||
|
||||
public interface Pipeline<T extends CustomContext> {
|
||||
Pipeline<?> init(WorkerContext paramWorkerContext) throws PipelineException;
|
||||
|
||||
Pipeline<?> open(WorkerContext paramWorkerContext, Tag paramTag, ProcessObject paramProcessObject) throws PipelineException;
|
||||
|
||||
Pipeline<?> content(WorkerContext paramWorkerContext, Tag paramTag, String paramString, ProcessObject paramProcessObject) throws PipelineException;
|
||||
|
||||
Pipeline<?> close(WorkerContext paramWorkerContext, Tag paramTag, ProcessObject paramProcessObject) throws PipelineException;
|
||||
|
||||
Pipeline<?> getNext();
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.itextpdf.tool.xml;
|
||||
|
||||
public class PipelineException extends Exception {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public PipelineException(Exception e) {
|
||||
super(e);
|
||||
}
|
||||
|
||||
public PipelineException(String msg, Exception e) {
|
||||
super(msg, e);
|
||||
}
|
||||
|
||||
public PipelineException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.itextpdf.tool.xml;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
|
||||
public class ProcessObject {
|
||||
private final Queue<Writable> queue = new LinkedList<Writable>();
|
||||
|
||||
public boolean containsWritable() {
|
||||
return !this.queue.isEmpty();
|
||||
}
|
||||
|
||||
public Writable poll() {
|
||||
return this.queue.poll();
|
||||
}
|
||||
|
||||
public void add(Writable writable) {
|
||||
this.queue.add(writable);
|
||||
}
|
||||
|
||||
public void addAll(List<Writable> elems) {
|
||||
this.queue.addAll(elems);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
package com.itextpdf.tool.xml;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class Tag implements Iterable<Tag> {
|
||||
private Tag parent;
|
||||
|
||||
private final String tag;
|
||||
|
||||
private final Map<String, String> attributes;
|
||||
|
||||
private Map<String, String> css;
|
||||
|
||||
private final List<Tag> children;
|
||||
|
||||
private final String ns;
|
||||
|
||||
private Object lastMarginBottom = null;
|
||||
|
||||
public Tag(String tag, Map<String, String> attr) {
|
||||
this(tag, attr, new LinkedHashMap<String, String>(0), "");
|
||||
}
|
||||
|
||||
public Tag(String tag) {
|
||||
this(tag, new LinkedHashMap<String, String>(0), new LinkedHashMap<String, String>(0), "");
|
||||
}
|
||||
|
||||
public Tag(String tag, Map<String, String> attr, Map<String, String> css, String ns) {
|
||||
this.tag = tag;
|
||||
this.attributes = attr;
|
||||
this.css = css;
|
||||
this.children = new LinkedList<Tag>();
|
||||
if (ns == null)
|
||||
throw new NullPointerException("NS cannot be null");
|
||||
this.ns = ns;
|
||||
}
|
||||
|
||||
public Tag(String tag, Map<String, String> attr, String ns) {
|
||||
this(tag, attr, new LinkedHashMap<String, String>(0), ns);
|
||||
}
|
||||
|
||||
public Tag(String tag, String ns) {
|
||||
this(tag, new LinkedHashMap<String, String>(0), new LinkedHashMap<String, String>(0), ns);
|
||||
}
|
||||
|
||||
public void setParent(Tag parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public Tag getParent() {
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public String getTag() {
|
||||
return this.tag;
|
||||
}
|
||||
|
||||
public Map<String, String> getCSS() {
|
||||
return this.css;
|
||||
}
|
||||
|
||||
public void setCSS(Map<String, String> css) {
|
||||
if (null != css) {
|
||||
this.css = css;
|
||||
} else {
|
||||
this.css.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, String> getAttributes() {
|
||||
return this.attributes;
|
||||
}
|
||||
|
||||
public void addChild(Tag t) {
|
||||
t.setParent(this);
|
||||
this.children.add(t);
|
||||
}
|
||||
|
||||
public List<Tag> getChildren() {
|
||||
return this.children;
|
||||
}
|
||||
|
||||
public List<Tag> getChildren(String name) {
|
||||
List<Tag> named = new LinkedList<Tag>();
|
||||
for (Tag child : this.children) {
|
||||
if (child.getName().equals(name))
|
||||
named.add(child);
|
||||
}
|
||||
return named;
|
||||
}
|
||||
|
||||
public String getNameSpace() {
|
||||
return this.ns;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if ("".equalsIgnoreCase(this.ns))
|
||||
return String.format("%s", this.tag);
|
||||
return String.format("%s:%s", this.ns, this.tag);
|
||||
}
|
||||
|
||||
public boolean compareTag(Tag t) {
|
||||
if (this == t)
|
||||
return true;
|
||||
if (t == null)
|
||||
return false;
|
||||
Tag other = t;
|
||||
if (this.ns == null) {
|
||||
if (other.ns != null)
|
||||
return false;
|
||||
} else if (!this.ns.equals(other.ns)) {
|
||||
return false;
|
||||
}
|
||||
if (this.tag == null) {
|
||||
if (other.tag != null)
|
||||
return false;
|
||||
} else if (!this.tag.equals(other.tag)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public Iterator<Tag> iterator() {
|
||||
return this.children.iterator();
|
||||
}
|
||||
|
||||
public Tag getChild(String name, String ns) {
|
||||
return getChild(name, ns, false);
|
||||
}
|
||||
|
||||
public Tag getChild(String name, String ns, boolean recursive) {
|
||||
return recursiveGetChild(this, name, ns, recursive);
|
||||
}
|
||||
|
||||
public boolean hasChildren() {
|
||||
return (getChildren().size() != 0);
|
||||
}
|
||||
|
||||
public boolean hasParent() {
|
||||
return (getParent() != null);
|
||||
}
|
||||
|
||||
public boolean hasChild(String name, String ns) {
|
||||
return hasChild(name, ns, false);
|
||||
}
|
||||
|
||||
public boolean hasChild(String name, String ns, boolean recursive) {
|
||||
if (recursive)
|
||||
return recursiveHasChild(this, name, ns, true);
|
||||
return recursiveHasChild(this, name, ns, false);
|
||||
}
|
||||
|
||||
private boolean recursiveHasChild(Tag tag, String name, String ns, boolean recursive) {
|
||||
for (Tag t : (Iterable<Tag>)tag) {
|
||||
if (t.tag.equals(name) && t.ns.equals(ns))
|
||||
return true;
|
||||
if (recursive)
|
||||
if (recursiveHasChild(t, name, ns, recursive))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Tag recursiveGetChild(Tag tag, String name, String ns, boolean recursive) {
|
||||
for (Tag t : (Iterable<Tag>)tag) {
|
||||
if (t.tag.equals(name) && t.ns.equals(ns))
|
||||
return t;
|
||||
Tag rT = null;
|
||||
if (recursive && null != (rT = recursiveGetChild(t, name, ns, recursive)))
|
||||
return rT;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.tag;
|
||||
}
|
||||
|
||||
public Object getLastMarginBottom() {
|
||||
return this.lastMarginBottom;
|
||||
}
|
||||
|
||||
public void setLastMarginBottom(Object lastMarginBottom) {
|
||||
this.lastMarginBottom = lastMarginBottom;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.itextpdf.tool.xml;
|
||||
|
||||
import com.itextpdf.tool.xml.exceptions.LocaleMessages;
|
||||
import com.itextpdf.tool.xml.exceptions.NoSiblingException;
|
||||
import java.util.List;
|
||||
|
||||
public class TagUtils {
|
||||
private static final TagUtils myself = new TagUtils();
|
||||
|
||||
public Tag getSibling(Tag t, int i) throws NoSiblingException {
|
||||
Tag sibling = null;
|
||||
try {
|
||||
List<Tag> siblings = t.getParent().getChildren();
|
||||
sibling = siblings.get(siblings.indexOf(t) + i);
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
throw new NoSiblingException(String.format(LocaleMessages.getInstance().getMessage("tag.nosibling"), t.getName(), i), e);
|
||||
}
|
||||
return sibling;
|
||||
}
|
||||
|
||||
public static TagUtils getInstance() {
|
||||
return myself;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.itextpdf.tool.xml;
|
||||
|
||||
public interface WorkerContext {
|
||||
CustomContext get(String paramString) throws NoCustomContextException;
|
||||
|
||||
void put(String paramString, CustomContext paramCustomContext);
|
||||
|
||||
void setCurrentTag(Tag paramTag);
|
||||
|
||||
Tag getCurrentTag();
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
package com.itextpdf.tool.xml;
|
||||
|
||||
public interface Writable {}
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
package com.itextpdf.tool.xml;
|
||||
|
||||
import com.itextpdf.tool.xml.exceptions.LocaleMessages;
|
||||
import com.itextpdf.tool.xml.exceptions.RuntimeWorkerException;
|
||||
import com.itextpdf.tool.xml.parser.XMLParserListener;
|
||||
import com.itextpdf.tool.xml.pipeline.ctx.WorkerContextImpl;
|
||||
import java.util.Map;
|
||||
|
||||
public class XMLWorker implements XMLParserListener {
|
||||
protected final Pipeline<?> rootpPipe;
|
||||
|
||||
private static ThreadLocal<WorkerContextImpl> context = new ThreadLocal<WorkerContextImpl>() {
|
||||
protected WorkerContextImpl initialValue() {
|
||||
return new WorkerContextImpl();
|
||||
}
|
||||
};
|
||||
|
||||
protected final boolean parseHtml;
|
||||
|
||||
public XMLWorker(Pipeline<?> pipeline, boolean parseHtml) {
|
||||
this.parseHtml = parseHtml;
|
||||
this.rootpPipe = pipeline;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
Pipeline<?> p = this.rootpPipe;
|
||||
while (true) {
|
||||
try {
|
||||
if ((p = p.init(getLocalWC())) != null)
|
||||
continue;
|
||||
} catch (PipelineException e) {
|
||||
throw new RuntimeWorkerException(e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void startElement(String tag, Map<String, String> attr, String ns) {
|
||||
Tag t = createTag(tag, attr, ns);
|
||||
WorkerContext ctx = getLocalWC();
|
||||
if (null != ctx.getCurrentTag())
|
||||
ctx.getCurrentTag().addChild(t);
|
||||
ctx.setCurrentTag(t);
|
||||
Pipeline<?> wp = this.rootpPipe;
|
||||
ProcessObject po = new ProcessObject();
|
||||
while (true) {
|
||||
try {
|
||||
if (null != (wp = wp.open(ctx, t, po)))
|
||||
continue;
|
||||
} catch (PipelineException e) {
|
||||
throw new RuntimeWorkerException(e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected Tag createTag(String tag, Map<String, String> attr, String ns) {
|
||||
if (this.parseHtml)
|
||||
tag = tag.toLowerCase();
|
||||
Tag t = new Tag(tag, attr, ns);
|
||||
return t;
|
||||
}
|
||||
|
||||
public void endElement(String tag, String ns) {
|
||||
String thetag = null;
|
||||
if (this.parseHtml) {
|
||||
thetag = tag.toLowerCase();
|
||||
} else {
|
||||
thetag = tag;
|
||||
}
|
||||
WorkerContext ctx = getLocalWC();
|
||||
if (null != ctx.getCurrentTag() && !thetag.equals(ctx.getCurrentTag().getName()))
|
||||
throw new RuntimeWorkerException(String.format(
|
||||
LocaleMessages.getInstance().getMessage("tag.invalidnesting"), thetag,
|
||||
ctx.getCurrentTag().getName()));
|
||||
Pipeline<?> wp = this.rootpPipe;
|
||||
ProcessObject po = new ProcessObject();
|
||||
while (true) {
|
||||
try {
|
||||
if (null != (wp = wp.close(ctx, ctx.getCurrentTag(), po)))
|
||||
continue;
|
||||
} catch (PipelineException e) {
|
||||
throw new RuntimeWorkerException(e);
|
||||
} finally {
|
||||
if (null != ctx.getCurrentTag())
|
||||
ctx.setCurrentTag(ctx.getCurrentTag().getParent());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void text(String text) {
|
||||
if (text.startsWith("<![CDATA[") && text.endsWith("]]>")) {
|
||||
if (ignoreCdata())
|
||||
return;
|
||||
text = text.substring(9, text.length() - 3);
|
||||
}
|
||||
WorkerContext ctx = getLocalWC();
|
||||
if (null != ctx.getCurrentTag() &&
|
||||
text.length() > 0) {
|
||||
Pipeline<?> wp = this.rootpPipe;
|
||||
ProcessObject po = new ProcessObject();
|
||||
while (true) {
|
||||
try {
|
||||
if (null != (wp = wp.content(ctx, ctx.getCurrentTag(), text, po)))
|
||||
continue;
|
||||
} catch (PipelineException e) {
|
||||
throw new RuntimeWorkerException(e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void unknownText(String text) {}
|
||||
|
||||
public void comment(String comment) {}
|
||||
|
||||
public void close() {
|
||||
closeLocalWC();
|
||||
}
|
||||
|
||||
protected Tag getCurrentTag() {
|
||||
return getLocalWC().getCurrentTag();
|
||||
}
|
||||
|
||||
protected static WorkerContext getLocalWC() {
|
||||
return context.get();
|
||||
}
|
||||
|
||||
protected static void closeLocalWC() {
|
||||
context.remove();
|
||||
}
|
||||
|
||||
protected boolean ignoreCdata() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
package com.itextpdf.tool.xml;
|
||||
|
||||
import com.itextpdf.text.BaseColor;
|
||||
import com.itextpdf.text.Font;
|
||||
import com.itextpdf.text.FontFactoryImp;
|
||||
import com.itextpdf.text.pdf.BaseFont;
|
||||
import java.nio.charset.UnsupportedCharsetException;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class XMLWorkerFontProvider extends FontFactoryImp {
|
||||
public static final String DONTLOOKFORFONTS = "";
|
||||
|
||||
protected HashMap<String, String> fontSubstitutionMap = new HashMap<String, String>();
|
||||
|
||||
protected boolean useUnicode = true;
|
||||
|
||||
public XMLWorkerFontProvider() {
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
public XMLWorkerFontProvider(String fontsPath) {
|
||||
this(fontsPath, null);
|
||||
}
|
||||
|
||||
public XMLWorkerFontProvider(String fontsPath, HashMap<String, String> fontSubstitutionMap) {
|
||||
if (fontsPath == null || fontsPath.length() == 0) {
|
||||
registerDirectories();
|
||||
} else if (!fontsPath.equals("")) {
|
||||
registerDirectory(fontsPath, true);
|
||||
}
|
||||
if (fontSubstitutionMap != null)
|
||||
this.fontSubstitutionMap = fontSubstitutionMap;
|
||||
}
|
||||
|
||||
public void addFontSubstitute(String font, String substitute) {
|
||||
this.fontSubstitutionMap.put(font, substitute);
|
||||
}
|
||||
|
||||
public void setUseUnicode(boolean useUnicode) {
|
||||
this.useUnicode = useUnicode;
|
||||
}
|
||||
|
||||
public Font getFont(String fontname, String encoding, boolean embedded, float size, int style, BaseColor color) {
|
||||
Font font = getFont(fontname, encoding, size, style);
|
||||
font.setColor(color);
|
||||
return font;
|
||||
}
|
||||
|
||||
public Font getFont(String fontname, String encoding, float size, int style) {
|
||||
if (fontname == null)
|
||||
return new Font(Font.FontFamily.UNDEFINED, size, style);
|
||||
Font unicodeFont = getUnicodeFont(fontname, encoding, size, style);
|
||||
return unicodeFont;
|
||||
}
|
||||
|
||||
private Font getUnicodeFont(String fontName, String encoding, float size, int style) {
|
||||
Font font = null;
|
||||
try {
|
||||
BaseFont baseFont = null;
|
||||
font = super.getFont(fontName, this.useUnicode ? "Identity-H" : encoding, true, size, style, null);
|
||||
if (font != null)
|
||||
baseFont = font.getBaseFont();
|
||||
if (baseFont == null) {
|
||||
String substFontName = this.fontSubstitutionMap.get(fontName);
|
||||
if (substFontName != null && substFontName.length() > 0)
|
||||
font = super.getFont(substFontName, this.useUnicode ? "Identity-H" : encoding, true, size, style, null);
|
||||
}
|
||||
} catch (UnsupportedCharsetException uce) {
|
||||
BaseFont baseFont = null;
|
||||
font = super.getFont(fontName, encoding, true, size, style, null);
|
||||
if (font != null)
|
||||
baseFont = font.getBaseFont();
|
||||
if (baseFont == null) {
|
||||
String substFontName = this.fontSubstitutionMap.get(fontName);
|
||||
if (substFontName != null && substFontName.length() > 0)
|
||||
font = super.getFont(substFontName, encoding, true, size, style, null);
|
||||
}
|
||||
}
|
||||
return font;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
package com.itextpdf.tool.xml;
|
||||
|
||||
import com.itextpdf.text.Document;
|
||||
import com.itextpdf.text.FontFactory;
|
||||
import com.itextpdf.text.FontProvider;
|
||||
import com.itextpdf.text.pdf.PdfWriter;
|
||||
import com.itextpdf.tool.xml.css.CSSFileWrapper;
|
||||
import com.itextpdf.tool.xml.css.CssFile;
|
||||
import com.itextpdf.tool.xml.css.CssFileProcessor;
|
||||
import com.itextpdf.tool.xml.css.CssFilesImpl;
|
||||
import com.itextpdf.tool.xml.css.StyleAttrCSSResolver;
|
||||
import com.itextpdf.tool.xml.exceptions.RuntimeWorkerException;
|
||||
import com.itextpdf.tool.xml.html.CssAppliers;
|
||||
import com.itextpdf.tool.xml.html.CssAppliersImpl;
|
||||
import com.itextpdf.tool.xml.html.TagProcessorFactory;
|
||||
import com.itextpdf.tool.xml.html.Tags;
|
||||
import com.itextpdf.tool.xml.parser.XMLParser;
|
||||
import com.itextpdf.tool.xml.pipeline.css.CSSResolver;
|
||||
import com.itextpdf.tool.xml.pipeline.css.CssResolverPipeline;
|
||||
import com.itextpdf.tool.xml.pipeline.end.ElementHandlerPipeline;
|
||||
import com.itextpdf.tool.xml.pipeline.end.PdfWriterPipeline;
|
||||
import com.itextpdf.tool.xml.pipeline.html.HtmlPipeline;
|
||||
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
public class XMLWorkerHelper {
|
||||
private static XMLWorkerHelper myself = new XMLWorkerHelper();
|
||||
|
||||
private TagProcessorFactory tpf;
|
||||
|
||||
private CssFile defaultCssFile;
|
||||
|
||||
public static synchronized XMLWorkerHelper getInstance() {
|
||||
return myself;
|
||||
}
|
||||
|
||||
public static synchronized CssFile getCSS(InputStream in) {
|
||||
CssFile cssFile = null;
|
||||
if (null != in) {
|
||||
CssFileProcessor cssFileProcessor = new CssFileProcessor();
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(in));
|
||||
try {
|
||||
char[] buffer = new char[8192];
|
||||
int length;
|
||||
while ((length = br.read(buffer)) > 0) {
|
||||
for (int i = 0; i < length; i++)
|
||||
cssFileProcessor.process(buffer[i]);
|
||||
}
|
||||
cssFile = new CSSFileWrapper(cssFileProcessor.getCss(), true);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeWorkerException(e);
|
||||
} finally {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeWorkerException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return cssFile;
|
||||
}
|
||||
|
||||
public synchronized CssFile getDefaultCSS() {
|
||||
if (null == this.defaultCssFile)
|
||||
this.defaultCssFile = getCSS(XMLWorkerHelper.class.getResourceAsStream("/default.css"));
|
||||
return this.defaultCssFile;
|
||||
}
|
||||
|
||||
public void parseXHtml(ElementHandler d, Reader in) throws IOException {
|
||||
CssFilesImpl cssFiles = new CssFilesImpl();
|
||||
cssFiles.add(getDefaultCSS());
|
||||
StyleAttrCSSResolver cssResolver = new StyleAttrCSSResolver(cssFiles);
|
||||
HtmlPipelineContext hpc = new HtmlPipelineContext(null);
|
||||
hpc.setAcceptUnknown(true).autoBookmark(true).setTagFactory(getDefaultTagProcessorFactory());
|
||||
Pipeline<?> pipeline = new CssResolverPipeline(cssResolver, new HtmlPipeline(hpc, new ElementHandlerPipeline(d, null)));
|
||||
XMLWorker worker = new XMLWorker(pipeline, true);
|
||||
XMLParser p = new XMLParser();
|
||||
p.addListener(worker);
|
||||
p.parse(in);
|
||||
}
|
||||
|
||||
public void parseXHtml(PdfWriter writer, Document doc, Reader in) throws IOException {
|
||||
CssFilesImpl cssFiles = new CssFilesImpl();
|
||||
cssFiles.add(getDefaultCSS());
|
||||
StyleAttrCSSResolver cssResolver = new StyleAttrCSSResolver(cssFiles);
|
||||
HtmlPipelineContext hpc = new HtmlPipelineContext(null);
|
||||
hpc.setAcceptUnknown(true).autoBookmark(true).setTagFactory(getDefaultTagProcessorFactory());
|
||||
Pipeline<?> pipeline = new CssResolverPipeline(cssResolver, new HtmlPipeline(hpc, new PdfWriterPipeline(doc, writer)));
|
||||
XMLWorker worker = new XMLWorker(pipeline, true);
|
||||
XMLParser p = new XMLParser();
|
||||
p.addListener(worker);
|
||||
p.parse(in);
|
||||
}
|
||||
|
||||
public void parseXHtml(PdfWriter writer, Document doc, InputStream in) throws IOException {
|
||||
parseXHtml(writer, doc, in, XMLWorkerHelper.class.getResourceAsStream("/default.css"), null, new XMLWorkerFontProvider());
|
||||
}
|
||||
|
||||
public void parseXHtml(PdfWriter writer, Document doc, InputStream in, Charset charset, FontProvider fontProvider) throws IOException {
|
||||
parseXHtml(writer, doc, in, XMLWorkerHelper.class.getResourceAsStream("/default.css"), charset, fontProvider);
|
||||
}
|
||||
|
||||
public void parseXHtml(PdfWriter writer, Document doc, InputStream in, Charset charset) throws IOException {
|
||||
parseXHtml(writer, doc, in, XMLWorkerHelper.class.getResourceAsStream("/default.css"), charset);
|
||||
}
|
||||
|
||||
public void parseXHtml(PdfWriter writer, Document doc, InputStream in, InputStream inCssFile, Charset charset, FontProvider fontProvider) throws IOException {
|
||||
parseXHtml(writer, doc, in, inCssFile, charset, fontProvider, null);
|
||||
}
|
||||
|
||||
public void parseXHtml(PdfWriter writer, Document doc, InputStream in, InputStream inCssFile, Charset charset, FontProvider fontProvider, String resourcesRootPath) throws IOException {
|
||||
CssFilesImpl cssFiles = new CssFilesImpl();
|
||||
if (inCssFile != null) {
|
||||
cssFiles.add(getCSS(inCssFile));
|
||||
} else {
|
||||
cssFiles.add(getDefaultCSS());
|
||||
}
|
||||
StyleAttrCSSResolver cssResolver = new StyleAttrCSSResolver(cssFiles);
|
||||
HtmlPipelineContext hpc = new HtmlPipelineContext(new CssAppliersImpl(fontProvider));
|
||||
hpc.setAcceptUnknown(true).autoBookmark(true).setTagFactory(getDefaultTagProcessorFactory()).setResourcesRootPath(resourcesRootPath);
|
||||
HtmlPipeline htmlPipeline = new HtmlPipeline(hpc, new PdfWriterPipeline(doc, writer));
|
||||
Pipeline<?> pipeline = new CssResolverPipeline(cssResolver, htmlPipeline);
|
||||
XMLWorker worker = new XMLWorker(pipeline, true);
|
||||
XMLParser p = new XMLParser(true, worker, charset);
|
||||
if (charset != null) {
|
||||
p.parse(in, charset);
|
||||
} else {
|
||||
p.parse(in);
|
||||
}
|
||||
}
|
||||
|
||||
public void parseXHtml(PdfWriter writer, Document doc, InputStream in, InputStream inCssFile) throws IOException {
|
||||
parseXHtml(writer, doc, in, inCssFile, null, new XMLWorkerFontProvider());
|
||||
}
|
||||
|
||||
public void parseXHtml(PdfWriter writer, Document doc, InputStream in, InputStream inCssFile, FontProvider fontProvider) throws IOException {
|
||||
parseXHtml(writer, doc, in, inCssFile, null, fontProvider);
|
||||
}
|
||||
|
||||
public void parseXHtml(PdfWriter writer, Document doc, InputStream in, InputStream inCssFile, Charset charset) throws IOException {
|
||||
parseXHtml(writer, doc, in, inCssFile, charset, new XMLWorkerFontProvider());
|
||||
}
|
||||
|
||||
public void parseXHtml(ElementHandler d, InputStream in, Charset charset) throws IOException {
|
||||
CssFilesImpl cssFiles = new CssFilesImpl();
|
||||
cssFiles.add(getDefaultCSS());
|
||||
StyleAttrCSSResolver cssResolver = new StyleAttrCSSResolver(cssFiles);
|
||||
HtmlPipelineContext hpc = new HtmlPipelineContext(null);
|
||||
hpc.setAcceptUnknown(true).autoBookmark(true).setTagFactory(getDefaultTagProcessorFactory());
|
||||
Pipeline<?> pipeline = new CssResolverPipeline(cssResolver, new HtmlPipeline(hpc, new ElementHandlerPipeline(d, null)));
|
||||
XMLWorker worker = new XMLWorker(pipeline, true);
|
||||
XMLParser p = new XMLParser(true, worker, charset);
|
||||
if (charset != null) {
|
||||
p.parse(in, charset);
|
||||
} else {
|
||||
p.parse(in);
|
||||
}
|
||||
}
|
||||
|
||||
public CSSResolver getDefaultCssResolver(boolean addDefaultCss) {
|
||||
CSSResolver resolver = new StyleAttrCSSResolver();
|
||||
if (addDefaultCss)
|
||||
resolver.addCss(getDefaultCSS());
|
||||
return resolver;
|
||||
}
|
||||
|
||||
protected synchronized TagProcessorFactory getDefaultTagProcessorFactory() {
|
||||
if (null == this.tpf)
|
||||
this.tpf = Tags.getHtmlTagProcessorFactory();
|
||||
return this.tpf;
|
||||
}
|
||||
|
||||
public static ElementList parseToElementList(String html, String css) throws IOException {
|
||||
CSSResolver cssResolver = new StyleAttrCSSResolver();
|
||||
if (css != null) {
|
||||
CssFile cssFile = getCSS(new ByteArrayInputStream(css.getBytes()));
|
||||
cssResolver.addCss(cssFile);
|
||||
}
|
||||
CssAppliers cssAppliers = new CssAppliersImpl((FontProvider)FontFactory.getFontImp());
|
||||
HtmlPipelineContext htmlContext = new HtmlPipelineContext(cssAppliers);
|
||||
htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());
|
||||
htmlContext.autoBookmark(false);
|
||||
ElementList elements = new ElementList();
|
||||
ElementHandlerPipeline end = new ElementHandlerPipeline(elements, null);
|
||||
HtmlPipeline htmlPipeline = new HtmlPipeline(htmlContext, end);
|
||||
CssResolverPipeline cssPipeline = new CssResolverPipeline(cssResolver, htmlPipeline);
|
||||
XMLWorker worker = new XMLWorker(cssPipeline, true);
|
||||
XMLParser p = new XMLParser(worker);
|
||||
p.parse(new ByteArrayInputStream(html.getBytes()));
|
||||
return elements;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,389 @@
|
|||
package com.itextpdf.tool.xml.css;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public final class CSS {
|
||||
public static final class Property {
|
||||
public static final String BACKGROUND = "background";
|
||||
|
||||
public static final String BACKGROUND_IMAGE = "background-image";
|
||||
|
||||
public static final String BACKGROUND_REPEAT = "background-repeat";
|
||||
|
||||
public static final String BACKGROUND_ATTACHMENT = "background-attachment";
|
||||
|
||||
public static final String BACKGROUND_POSITION = "background-position";
|
||||
|
||||
public static final String BACKGROUND_COLOR = "background-color";
|
||||
|
||||
public static final String LIST_STYLE = "list-style";
|
||||
|
||||
public static final String LIST_STYLE_TYPE = "list-style-type";
|
||||
|
||||
public static final String LIST_STYLE_POSITION = "list-style-position";
|
||||
|
||||
public static final String LIST_STYLE_IMAGE = "list-style-image";
|
||||
|
||||
public static final String MARGIN = "margin";
|
||||
|
||||
public static final String TOP = "top";
|
||||
|
||||
public static final String MARGIN_LEFT = "margin-left";
|
||||
|
||||
public static final String MARGIN_RIGHT = "margin-right";
|
||||
|
||||
public static final String MARGIN_TOP = "margin-top";
|
||||
|
||||
public static final String MARGIN_BOTTOM = "margin-bottom";
|
||||
|
||||
public static final String BORDER = "border";
|
||||
|
||||
public static final String BORDER_LEFT = "border-left";
|
||||
|
||||
public static final String BORDER_TOP = "border-top";
|
||||
|
||||
public static final String BORDER_RIGHT = "border-right";
|
||||
|
||||
public static final String BORDER_BOTTOM = "border-bottom";
|
||||
|
||||
public static final String BORDER_WIDTH = "border-width";
|
||||
|
||||
public static final String BORDER_STYLE = "border-style";
|
||||
|
||||
public static final String BORDER_COLOR = "border-color";
|
||||
|
||||
public static final String BORDER_COLLAPSE = "border-collapse";
|
||||
|
||||
public static final String BORDER_SPACING = "border-spacing";
|
||||
|
||||
public static final String BORDER_TOP_WIDTH = "border-top-width";
|
||||
|
||||
public static final String BORDER_BOTTOM_WIDTH = "border-bottom-width";
|
||||
|
||||
public static final String BORDER_LEFT_WIDTH = "border-left-width";
|
||||
|
||||
public static final String BORDER_RIGHT_WIDTH = "border-right-width";
|
||||
|
||||
public static final String BORDER_TOP_COLOR = "border-top-color";
|
||||
|
||||
public static final String BORDER_BOTTOM_COLOR = "border-bottom-color";
|
||||
|
||||
public static final String BORDER_LEFT_COLOR = "border-left-color";
|
||||
|
||||
public static final String BORDER_RIGHT_COLOR = "border-right-color";
|
||||
|
||||
public static final String BORDER_TOP_STYLE = "border-top-style";
|
||||
|
||||
public static final String BORDER_BOTTOM_STYLE = "border-bottom-style";
|
||||
|
||||
public static final String BORDER_LEFT_STYLE = "border-left-style";
|
||||
|
||||
public static final String BORDER_RIGHT_STYLE = "border-right-style";
|
||||
|
||||
public static final String PADDING = "padding";
|
||||
|
||||
public static final String PADDING_TOP = "padding-top";
|
||||
|
||||
public static final String PADDING_BOTTOM = "padding-bottom";
|
||||
|
||||
public static final String PADDING_LEFT = "padding-left";
|
||||
|
||||
public static final String PADDING_RIGHT = "padding-right";
|
||||
|
||||
public static final String FONT = "font";
|
||||
|
||||
public static final String FONT_WEIGHT = "font-weight";
|
||||
|
||||
public static final String FONT_SIZE = "font-size";
|
||||
|
||||
public static final String FONT_STYLE = "font-style";
|
||||
|
||||
public static final String FONT_FAMILY = "font-family";
|
||||
|
||||
public static final String TEXT_DECORATION = "text-decoration";
|
||||
|
||||
public static final String COLOR = "color";
|
||||
|
||||
public static final String TAB_INTERVAL = "tab-interval";
|
||||
|
||||
public static final String XFA_TAB_COUNT = "xfa-tab-count";
|
||||
|
||||
public static final String XFA_FONT_HORIZONTAL_SCALE = "xfa-font-horizontal-scale";
|
||||
|
||||
public static final String XFA_FONT_VERTICAL_SCALE = "xfa-font-vertical-scale";
|
||||
|
||||
public static final String BEFORE = "before";
|
||||
|
||||
public static final String AFTER = "after";
|
||||
|
||||
public static final String HEIGHT = "height";
|
||||
|
||||
public static final String WIDTH = "width";
|
||||
|
||||
public static final String LETTER_SPACING = "letter-spacing";
|
||||
|
||||
public static final String VERTICAL_ALIGN = "vertical-align";
|
||||
|
||||
public static final String LINE_HEIGHT = "line-height";
|
||||
|
||||
public static final String TEXT_ALIGN = "text-align";
|
||||
|
||||
public static final String TEXT_VALIGN = "text-valign";
|
||||
|
||||
public static final String TEXT_INDENT = "text-indent";
|
||||
|
||||
public static final String POSITION = "position";
|
||||
|
||||
public static final String EMPTY_CELLS = "empty-cells";
|
||||
|
||||
public static final String CELLPADDING = "cellpadding";
|
||||
|
||||
public static final String CELLPADDING_LEFT = "cellpadding-left";
|
||||
|
||||
public static final String CELLPADDING_TOP = "cellpadding-top";
|
||||
|
||||
public static final String CELLPADDING_RIGHT = "cellpadding-right";
|
||||
|
||||
public static final String CELLPADDING_BOTTOM = "cellpadding-bottom";
|
||||
|
||||
public static final String CAPTION_SIDE = "caption-side";
|
||||
|
||||
public static final String TAB_STOPS = "tab-stops";
|
||||
|
||||
public static final String XFA_TAB_STOPS = "xfa-tab-stops";
|
||||
|
||||
public static final String PAGE_BREAK_BEFORE = "page-break-before";
|
||||
|
||||
public static final String PAGE_BREAK_INSIDE = "page-break-inside";
|
||||
|
||||
public static final String PAGE_BREAK_AFTER = "page-break-after";
|
||||
|
||||
public static final String REPEAT_HEADER = "repeat-header";
|
||||
|
||||
public static final String REPEAT_FOOTER = "repeat-footer";
|
||||
|
||||
public static final String LEFT = "left";
|
||||
|
||||
public static final String DISPLAY = "display";
|
||||
|
||||
public static final String MIN_WIDTH = "min-width";
|
||||
|
||||
public static final String MAX_WIDTH = "max-width";
|
||||
|
||||
public static final String MIN_HEIGHT = "min-height";
|
||||
|
||||
public static final String MAX_HEIGHT = "max-height";
|
||||
|
||||
public static final String RIGHT = "right";
|
||||
|
||||
public static final String BOTTOM = "bottom";
|
||||
|
||||
public static final String FLOAT = "float";
|
||||
|
||||
public static final String DIRECTION = "direction";
|
||||
}
|
||||
|
||||
public static final class Value {
|
||||
public static final String THIN = "thin";
|
||||
|
||||
public static final String MEDIUM = "medium";
|
||||
|
||||
public static final String THICK = "thick";
|
||||
|
||||
public static final String NONE = "none";
|
||||
|
||||
public static final String HIDDEN = "hidden";
|
||||
|
||||
public static final String DOTTED = "dotted";
|
||||
|
||||
public static final String DASHED = "dashed";
|
||||
|
||||
public static final String SOLID = "solid";
|
||||
|
||||
public static final String DOUBLE = "double";
|
||||
|
||||
public static final String GROOVE = "groove";
|
||||
|
||||
public static final String RIDGE = "ridge";
|
||||
|
||||
public static final String INSET = "inset";
|
||||
|
||||
public static final String OUTSET = "outset";
|
||||
|
||||
public static final String LEFT = "left";
|
||||
|
||||
public static final String CENTER = "center";
|
||||
|
||||
public static final String JUSTIFY = "justify";
|
||||
|
||||
public static final String BOTTOM = "bottom";
|
||||
|
||||
public static final String TOP = "top";
|
||||
|
||||
public static final String RIGHT = "right";
|
||||
|
||||
public static final String REPEAT = "repeat";
|
||||
|
||||
public static final String NO_REPEAT = "no-repeat";
|
||||
|
||||
public static final String REPEAT_X = "repeat-x";
|
||||
|
||||
public static final String REPEAT_Y = "repeat-y";
|
||||
|
||||
public static final String FIXED = "fixed";
|
||||
|
||||
public static final String SCROLL = "scroll";
|
||||
|
||||
public static final String DISC = "disc";
|
||||
|
||||
public static final String SQUARE = "square";
|
||||
|
||||
public static final String CIRCLE = "circle";
|
||||
|
||||
public static final String DECIMAL = "decimal";
|
||||
|
||||
public static final String LOWER_ROMAN = "lower-roman";
|
||||
|
||||
public static final String UPPER_ROMAN = "upper-roman";
|
||||
|
||||
public static final String LOWER_GREEK = "lower-greek";
|
||||
|
||||
public static final String UPPER_GREEK = "upper-greek";
|
||||
|
||||
public static final String LOWER_ALPHA = "lower-alpha";
|
||||
|
||||
public static final String UPPER_ALPHA = "upper-alpha";
|
||||
|
||||
public static final String LOWER_LATIN = "lower-latin";
|
||||
|
||||
public static final String UPPER_LATIN = "upper-latin";
|
||||
|
||||
public static final String INSIDE = "inside";
|
||||
|
||||
public static final String OUTSIDE = "outside";
|
||||
|
||||
public static final String INHERIT = "inherit";
|
||||
|
||||
public static final String UNDERLINE = "underline";
|
||||
|
||||
public static final String BOLD = "bold";
|
||||
|
||||
public static final String ITALIC = "italic";
|
||||
|
||||
public static final String OBLIQUE = "oblique";
|
||||
|
||||
public static final String SUPER = "super";
|
||||
|
||||
public static final String SUB = "sub";
|
||||
|
||||
public static final String TEXT_TOP = "text-top";
|
||||
|
||||
public static final String TEXT_BOTTOM = "text-bottom";
|
||||
|
||||
public static final String LINE_THROUGH = "line-through";
|
||||
|
||||
public static final String RELATIVE = "relative";
|
||||
|
||||
public static final String HIDE = "hide";
|
||||
|
||||
public static final String XX_SMALL = "xx-small";
|
||||
|
||||
public static final String X_SMALL = "x-small";
|
||||
|
||||
public static final String SMALL = "small";
|
||||
|
||||
public static final String LARGE = "large";
|
||||
|
||||
public static final String X_LARGE = "x-large";
|
||||
|
||||
public static final String XX_LARGE = "xx-large";
|
||||
|
||||
public static final String SMALLER = "smaller";
|
||||
|
||||
public static final String LARGER = "larger";
|
||||
|
||||
public static final String PX = "px";
|
||||
|
||||
public static final String IN = "in";
|
||||
|
||||
public static final String CM = "cm";
|
||||
|
||||
public static final String MM = "mm";
|
||||
|
||||
public static final String PT = "pt";
|
||||
|
||||
public static final String PC = "pc";
|
||||
|
||||
public static final String PERCENTAGE = "%";
|
||||
|
||||
public static final String EM = "em";
|
||||
|
||||
public static final String EX = "ex";
|
||||
|
||||
public static final String ALWAYS = "always";
|
||||
|
||||
public static final String AVOID = "avoid";
|
||||
|
||||
public static final String ABSOLUTE = "absolute";
|
||||
|
||||
public static final String AUTO = "auto";
|
||||
|
||||
public static final String INLINE = "inline";
|
||||
|
||||
public static final String BLOCK = "block";
|
||||
|
||||
public static final String SEPARATE = "separate";
|
||||
|
||||
public static final String COLLAPSE = "collapse";
|
||||
|
||||
public static final String RTL = "rtl";
|
||||
|
||||
public static final String LTR = "ltr";
|
||||
|
||||
public static final String INLINE_BLOCK = "inline-block";
|
||||
|
||||
public static final String INLINE_TABLE = "inline-table";
|
||||
|
||||
public static final String LIST_ITEM = "list-item";
|
||||
|
||||
public static final String RUN_IN = "run-in";
|
||||
|
||||
public static final String TABLE = "table";
|
||||
|
||||
public static final String TABLE_CAPTION = "table-caption";
|
||||
|
||||
public static final String TABLE_CELL = "table-cell";
|
||||
|
||||
public static final String TABLE_COLUMN_GROUP = "table-column-group";
|
||||
|
||||
public static final String TABLE_COLUMN = "table-column";
|
||||
|
||||
public static final String TABLE_FOOTER_GROUP = "table-footer-group";
|
||||
|
||||
public static final String TABLE_HEADER_GROUP = "table-header-group";
|
||||
|
||||
public static final String TABLE_ROW = "table-row";
|
||||
|
||||
public static final String TABLE_ROW_GROUP = "table-row-group";
|
||||
}
|
||||
|
||||
private static final Map<String, Integer> cssAlignMap = new HashMap<String, Integer>();
|
||||
|
||||
private static final String DEFAULT = "default";
|
||||
|
||||
static {
|
||||
cssAlignMap.put("left".toLowerCase(), Integer.valueOf(0));
|
||||
cssAlignMap.put("center".toLowerCase(), Integer.valueOf(1));
|
||||
cssAlignMap.put("right".toLowerCase(), Integer.valueOf(2));
|
||||
cssAlignMap.put("justify".toLowerCase(), Integer.valueOf(3));
|
||||
cssAlignMap.put("default".toLowerCase(), Integer.valueOf(-1));
|
||||
}
|
||||
|
||||
public static final int getElementAlignment(String cssAlignment) {
|
||||
String lower = cssAlignment.toLowerCase();
|
||||
if (cssAlignMap.containsKey(lower))
|
||||
return cssAlignMap.get(lower);
|
||||
return cssAlignMap.get("default");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package com.itextpdf.tool.xml.css;
|
||||
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class CSSFileWrapper implements CssFile {
|
||||
private final boolean persistent;
|
||||
|
||||
private final CssFile css;
|
||||
|
||||
public CSSFileWrapper(CssFile css, boolean b) {
|
||||
this.css = css;
|
||||
this.persistent = b;
|
||||
}
|
||||
|
||||
public boolean add(String selector, Map<String, String> props) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public List<CssRule> get(Tag t) {
|
||||
return this.css.get(t);
|
||||
}
|
||||
|
||||
public boolean isPersistent() {
|
||||
return this.persistent;
|
||||
}
|
||||
|
||||
public void isPersistent(boolean b) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.itextpdf.tool.xml.css;
|
||||
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface CssFile {
|
||||
boolean add(String paramString, Map<String, String> paramMap);
|
||||
|
||||
List<CssRule> get(Tag paramTag);
|
||||
|
||||
boolean isPersistent();
|
||||
|
||||
void isPersistent(boolean paramBoolean);
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.itextpdf.tool.xml.css;
|
||||
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.css.parser.CssSelectorParser;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class CssFileImpl implements CssFile {
|
||||
private boolean persistent = false;
|
||||
|
||||
private final List<CssRule> rules = new ArrayList<CssRule>();
|
||||
|
||||
public boolean add(String selector, Map<String, String> props) {
|
||||
List<CssSelectorItem> selectorItems = CssSelectorParser.createCssSelector(selector);
|
||||
if (selectorItems != null) {
|
||||
this.rules.add(new CssRule(selectorItems, props));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<CssRule> get(Tag t) {
|
||||
List<CssRule> result = new ArrayList<CssRule>();
|
||||
for (CssRule rule : this.rules) {
|
||||
if (rule.getSelector().matches(t))
|
||||
result.add(rule);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean isPersistent() {
|
||||
return this.persistent;
|
||||
}
|
||||
|
||||
public void isPersistent(boolean isPeristent) {
|
||||
this.persistent = isPeristent;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.itextpdf.tool.xml.css;
|
||||
|
||||
import com.itextpdf.tool.xml.css.parser.CssStateController;
|
||||
import com.itextpdf.tool.xml.net.ReadingProcessor;
|
||||
|
||||
public class CssFileProcessor implements ReadingProcessor {
|
||||
private final CssFile css = new CssFileImpl();
|
||||
|
||||
private final CssStateController controller = new CssStateController(this.css);
|
||||
|
||||
public void process(int i) {
|
||||
this.controller.process((char)i);
|
||||
}
|
||||
|
||||
public CssFile getCss() {
|
||||
return this.css;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.itextpdf.tool.xml.css;
|
||||
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import java.util.Map;
|
||||
|
||||
public interface CssFiles {
|
||||
boolean hasFiles();
|
||||
|
||||
Map<String, String> getCSS(Tag paramTag);
|
||||
|
||||
void add(CssFile paramCssFile);
|
||||
|
||||
void clear();
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
package com.itextpdf.tool.xml.css;
|
||||
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class CssFilesImpl implements CssFiles {
|
||||
private final List<CssFile> files = new ArrayList<CssFile>();
|
||||
|
||||
private final CssUtils utils = CssUtils.getInstance();
|
||||
|
||||
public CssFilesImpl() {}
|
||||
|
||||
public CssFilesImpl(CssFile css) {
|
||||
this();
|
||||
add(css);
|
||||
}
|
||||
|
||||
public boolean hasFiles() {
|
||||
return !this.files.isEmpty();
|
||||
}
|
||||
|
||||
public Map<String, String> getCSS(Tag t) {
|
||||
Map<String, String> aggregatedProps = new LinkedHashMap<String, String>();
|
||||
populateCss(t, aggregatedProps);
|
||||
return aggregatedProps;
|
||||
}
|
||||
|
||||
public void populateCss(Tag t, Map<String, String> aggregatedProps) {
|
||||
List<CssRule> rules = new ArrayList<CssRule>();
|
||||
for (CssFile cssFile : this.files)
|
||||
rules.addAll(cssFile.get(t));
|
||||
Collections.<CssRule>sort(rules);
|
||||
for (CssRule rule : rules)
|
||||
populateOneCss(aggregatedProps, rule.getNormalDeclarations());
|
||||
for (CssRule rule : rules)
|
||||
populateOneCss(aggregatedProps, rule.getImportantDeclarations());
|
||||
}
|
||||
|
||||
public void populateOneCss(Map<String, String> aggregatedProps, Map<String, String> cssDeclaration) {
|
||||
Map<String, String> css = new LinkedHashMap<String, String>();
|
||||
for (Map.Entry<String, String> e : cssDeclaration.entrySet()) {
|
||||
String key = this.utils.stripDoubleSpacesTrimAndToLowerCase(e.getKey());
|
||||
String value = this.utils.stripDoubleSpacesAndTrim(e.getValue());
|
||||
if ("border".equalsIgnoreCase(key)) {
|
||||
css.putAll(this.utils.parseBorder(value));
|
||||
continue;
|
||||
}
|
||||
if ("border-top".equalsIgnoreCase(key)) {
|
||||
css.putAll(this.utils.parseBorder(value, "border-top"));
|
||||
continue;
|
||||
}
|
||||
if ("border-bottom".equalsIgnoreCase(key)) {
|
||||
css.putAll(this.utils.parseBorder(value, "border-bottom"));
|
||||
continue;
|
||||
}
|
||||
if ("border-left".equalsIgnoreCase(key)) {
|
||||
css.putAll(this.utils.parseBorder(value, "border-left"));
|
||||
continue;
|
||||
}
|
||||
if ("border-right".equalsIgnoreCase(key)) {
|
||||
css.putAll(this.utils.parseBorder(value, "border-right"));
|
||||
continue;
|
||||
}
|
||||
if ("margin".equalsIgnoreCase(key)) {
|
||||
Map<String, String> margins = this.utils.parseBoxValues(value, "margin-", "");
|
||||
for (String marginKey : margins.keySet()) {
|
||||
if (!css.containsKey(marginKey))
|
||||
css.put(marginKey, margins.get(marginKey));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ("border-width".equalsIgnoreCase(key)) {
|
||||
css.putAll(this.utils.parseBoxValues(value, "border-", "-width"));
|
||||
continue;
|
||||
}
|
||||
if ("border-style".equalsIgnoreCase(key)) {
|
||||
css.putAll(this.utils.parseBoxValues(value, "border-", "-style"));
|
||||
continue;
|
||||
}
|
||||
if ("border-color".equalsIgnoreCase(key)) {
|
||||
css.putAll(this.utils.parseBoxValues(value, "border-", "-color"));
|
||||
continue;
|
||||
}
|
||||
if ("padding".equalsIgnoreCase(key)) {
|
||||
Map<String, String> paddings = this.utils.parseBoxValues(value, "padding-", "");
|
||||
for (String paddingKey : paddings.keySet()) {
|
||||
if (!css.containsKey(paddingKey))
|
||||
css.put(paddingKey, paddings.get(paddingKey));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ("font".equalsIgnoreCase(key)) {
|
||||
css.putAll(this.utils.processFont(value));
|
||||
continue;
|
||||
}
|
||||
if ("list-style".equalsIgnoreCase(key)) {
|
||||
css.putAll(this.utils.processListStyle(value));
|
||||
continue;
|
||||
}
|
||||
if (key.toLowerCase().contains("background")) {
|
||||
Map<String, String> backgroundStyles = this.utils.processBackground(value);
|
||||
for (String backgroundKey : backgroundStyles.keySet()) {
|
||||
if (!css.containsKey(backgroundKey))
|
||||
css.put(backgroundKey, backgroundStyles.get(backgroundKey));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
css.put(key, value);
|
||||
}
|
||||
aggregatedProps.putAll(css);
|
||||
}
|
||||
|
||||
public void add(CssFile css) {
|
||||
if (css != null)
|
||||
this.files.add(css);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
Iterator<CssFile> iterator = this.files.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
CssFile next = iterator.next();
|
||||
if (!next.isPersistent())
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.itextpdf.tool.xml.css;
|
||||
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
|
||||
public interface CssInheritanceRules {
|
||||
boolean inheritCssTag(String paramString);
|
||||
|
||||
boolean inheritCssSelector(Tag paramTag, String paramString);
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package com.itextpdf.tool.xml.css;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class CssRule implements Comparable<CssRule> {
|
||||
private CssSelector selector;
|
||||
|
||||
private Map<String, String> normalDeclarations;
|
||||
|
||||
private Map<String, String> importantDeclarations;
|
||||
|
||||
private static final Pattern importantMatcher = Pattern.compile(".*!\\s*important$");
|
||||
|
||||
public CssRule(List<CssSelectorItem> selector, Map<String, String> declarations) {
|
||||
this.selector = new CssSelector(selector);
|
||||
this.normalDeclarations = declarations;
|
||||
this.importantDeclarations = new LinkedHashMap<String, String>();
|
||||
for (Map.Entry<String, String> declaration : this.normalDeclarations.entrySet()) {
|
||||
int exclIndex = declaration.getValue().indexOf('!');
|
||||
if (exclIndex > 0 && importantMatcher.matcher(declaration.getValue()).matches())
|
||||
this.importantDeclarations.put(declaration.getKey(), declaration.getValue().substring(0, exclIndex).trim());
|
||||
}
|
||||
for (String key : this.importantDeclarations.keySet())
|
||||
this.normalDeclarations.remove(key);
|
||||
}
|
||||
|
||||
public CssSelector getSelector() {
|
||||
return this.selector;
|
||||
}
|
||||
|
||||
public Map<String, String> getNormalDeclarations() {
|
||||
return this.normalDeclarations;
|
||||
}
|
||||
|
||||
public Map<String, String> getImportantDeclarations() {
|
||||
return this.importantDeclarations;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.format("%s { count: %d } #spec:%d",
|
||||
this.selector.toString(), this.normalDeclarations.size() + this.importantDeclarations.size(), this.selector.calculateSpecifity());
|
||||
}
|
||||
|
||||
public int compareTo(CssRule o) {
|
||||
return this.selector.calculateSpecifity() - o.selector.calculateSpecifity();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
package com.itextpdf.tool.xml.css;
|
||||
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class CssSelector {
|
||||
private List<CssSelectorItem> selectorItems;
|
||||
|
||||
public CssSelector(List<CssSelectorItem> selector) {
|
||||
this.selectorItems = selector;
|
||||
}
|
||||
|
||||
public boolean matches(Tag t) {
|
||||
return matches(t, this.selectorItems.size() - 1);
|
||||
}
|
||||
|
||||
private boolean matches(Tag t, int index) {
|
||||
int precededIndex;
|
||||
if (t == null)
|
||||
return false;
|
||||
Stack<CssSelectorItem> currentSelector = new Stack<CssSelectorItem>();
|
||||
for (; index >= 0 &&
|
||||
this.selectorItems.get(index).getSeparator() == '\000'; index--)
|
||||
currentSelector.push(this.selectorItems.get(index));
|
||||
while (!currentSelector.empty()) {
|
||||
if (!currentSelector.pop().matches(t))
|
||||
return false;
|
||||
}
|
||||
if (index == -1)
|
||||
return true;
|
||||
char separator = this.selectorItems.get(index).getSeparator();
|
||||
if (separator == '\000')
|
||||
return false;
|
||||
index--;
|
||||
switch (separator) {
|
||||
case '>':
|
||||
return matches(t.getParent(), index);
|
||||
case ' ':
|
||||
while (t != null) {
|
||||
if (matches(t.getParent(), index))
|
||||
return true;
|
||||
t = t.getParent();
|
||||
}
|
||||
return false;
|
||||
case '~':
|
||||
if (!t.hasParent())
|
||||
return false;
|
||||
precededIndex = t.getParent().getChildren().indexOf(t) - 1;
|
||||
while (precededIndex >= 0) {
|
||||
if (matches(t.getParent().getChildren().get(precededIndex), index))
|
||||
return true;
|
||||
precededIndex--;
|
||||
}
|
||||
return false;
|
||||
case '+':
|
||||
if (!t.hasParent())
|
||||
return false;
|
||||
precededIndex = t.getParent().getChildren().indexOf(t) - 1;
|
||||
return (precededIndex >= 0 && matches(t.getParent().getChildren().get(precededIndex), index));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int calculateSpecifity() {
|
||||
int specifity = 0;
|
||||
for (CssSelectorItem item : this.selectorItems)
|
||||
specifity += item.getSpecificity();
|
||||
return specifity;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (CssSelectorItem item : this.selectorItems)
|
||||
buf.append(item.toString());
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.itextpdf.tool.xml.css;
|
||||
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
|
||||
public interface CssSelectorItem {
|
||||
boolean matches(Tag paramTag);
|
||||
|
||||
char getSeparator();
|
||||
|
||||
int getSpecificity();
|
||||
}
|
||||
|
|
@ -0,0 +1,402 @@
|
|||
package com.itextpdf.tool.xml.css;
|
||||
|
||||
import com.itextpdf.text.html.WebColors;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.css.apply.MarginMemory;
|
||||
import com.itextpdf.tool.xml.exceptions.NoDataException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class CssUtils {
|
||||
private static final String COLOR = "-color";
|
||||
|
||||
private static final String STYLE = "-style";
|
||||
|
||||
private static final String WIDTH = "-width";
|
||||
|
||||
private static final String BORDER2 = "border-";
|
||||
|
||||
private static final String _0_LEFT_1 = "{0}left{1}";
|
||||
|
||||
private static final String _0_RIGHT_1 = "{0}right{1}";
|
||||
|
||||
private static final String _0_BOTTOM_1 = "{0}bottom{1}";
|
||||
|
||||
private static final String _0_TOP_1 = "{0}top{1}";
|
||||
|
||||
private static CssUtils instance = new CssUtils();
|
||||
|
||||
public static final int DEFAULT_FONT_SIZE_PT = 12;
|
||||
|
||||
public static CssUtils getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public Map<String, String> parseBoxValues(String box, String pre, String post) {
|
||||
return parseBoxValues(box, pre, post, null);
|
||||
}
|
||||
|
||||
public Map<String, String> parseBoxValues(String box, String pre, String post, String preKey) {
|
||||
String[] props = box.split(" ");
|
||||
int length = props.length;
|
||||
Map<String, String> map = new LinkedHashMap<String, String>(4);
|
||||
if (length == 1) {
|
||||
String value = props[0];
|
||||
if (preKey == null) {
|
||||
map.put(MessageFormat.format("{0}top{1}", pre, post), value);
|
||||
map.put(MessageFormat.format("{0}bottom{1}", pre, post), value);
|
||||
map.put(MessageFormat.format("{0}right{1}", pre, post), value);
|
||||
map.put(MessageFormat.format("{0}left{1}", pre, post), value);
|
||||
} else {
|
||||
map.put(MessageFormat.format(preKey + "{0}", post), value);
|
||||
}
|
||||
} else if (length == 2) {
|
||||
if (preKey == null) {
|
||||
map.put(MessageFormat.format("{0}top{1}", pre, post), props[0]);
|
||||
map.put(MessageFormat.format("{0}bottom{1}", pre, post), props[0]);
|
||||
map.put(MessageFormat.format("{0}right{1}", pre, post), props[1]);
|
||||
map.put(MessageFormat.format("{0}left{1}", pre, post), props[1]);
|
||||
} else {
|
||||
map.put(MessageFormat.format(preKey + "{0}", post), props[0]);
|
||||
}
|
||||
} else if (length == 3) {
|
||||
if (preKey == null) {
|
||||
map.put(MessageFormat.format("{0}top{1}", pre, post), props[0]);
|
||||
map.put(MessageFormat.format("{0}bottom{1}", pre, post), props[2]);
|
||||
map.put(MessageFormat.format("{0}right{1}", pre, post), props[1]);
|
||||
map.put(MessageFormat.format("{0}left{1}", pre, post), props[1]);
|
||||
} else {
|
||||
map.put(MessageFormat.format(preKey + "{0}", post), props[0]);
|
||||
}
|
||||
} else if (length == 4) {
|
||||
if (preKey == null) {
|
||||
map.put(MessageFormat.format("{0}top{1}", pre, post), props[0]);
|
||||
map.put(MessageFormat.format("{0}bottom{1}", pre, post), props[2]);
|
||||
map.put(MessageFormat.format("{0}right{1}", pre, post), props[1]);
|
||||
map.put(MessageFormat.format("{0}left{1}", pre, post), props[3]);
|
||||
} else {
|
||||
map.put(MessageFormat.format(preKey + "{0}", post), props[0]);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private static final Set<String> borderwidth = new HashSet<String>(
|
||||
Arrays.<String>asList("thin", "medium", "thick"));
|
||||
|
||||
private static final Set<String> borderstyle = new HashSet<String>(
|
||||
Arrays.<String>asList("none", "hidden", "dotted", "dashed", "solid", "double", "groove", "ridge", "inset", "outset"));
|
||||
|
||||
public Map<String, String> parseBorder(String border) {
|
||||
return parseBorder(border, null);
|
||||
}
|
||||
|
||||
public Map<String, String> parseBorder(String border, String borderKey) {
|
||||
HashMap<String, String> map = new HashMap<String, String>(0);
|
||||
String[] split = splitComplexCssStyle(border);
|
||||
int length = split.length;
|
||||
if (length == 1) {
|
||||
if (borderwidth.contains(split[0]) || isNumericValue(split[0]) || isMetricValue(split[0])) {
|
||||
map.putAll(parseBoxValues(split[0], "border-", "-width", borderKey));
|
||||
} else {
|
||||
map.putAll(parseBoxValues(split[0], "border-", "-style", borderKey));
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < length; i++) {
|
||||
String value = split[i];
|
||||
if (borderwidth.contains(value) || isNumericValue(value) || isMetricValue(value)) {
|
||||
map.putAll(parseBoxValues(value, "border-", "-width", borderKey));
|
||||
} else if (borderstyle.contains(value)) {
|
||||
map.putAll(parseBoxValues(value, "border-", "-style", borderKey));
|
||||
} else if (value.contains("rgb(") || value.contains("#") || WebColors.NAMES.containsKey(value.toLowerCase())) {
|
||||
map.putAll(parseBoxValues(value, "border-", "-color", borderKey));
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public String stripDoubleSpacesAndTrim(String str) {
|
||||
char[] charArray = str.toCharArray();
|
||||
if (str.contains(" ")) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < charArray.length; i++) {
|
||||
char c = charArray[i];
|
||||
if (c != ' ') {
|
||||
builder.append(c);
|
||||
} else if (i + 1 < charArray.length && charArray[i + 1] != ' ') {
|
||||
builder.append(' ');
|
||||
}
|
||||
}
|
||||
return builder.toString().trim();
|
||||
}
|
||||
return String.valueOf(charArray).trim();
|
||||
}
|
||||
|
||||
public String stripDoubleSpacesTrimAndToLowerCase(String str) {
|
||||
return stripDoubleSpacesAndTrim(str).toLowerCase();
|
||||
}
|
||||
|
||||
private static final Set<String> backgroundPositions = new HashSet<String>(
|
||||
Arrays.<String>asList("left", "center", "bottom", "top", "right"));
|
||||
|
||||
public Map<String, String> processBackground(String background) {
|
||||
Map<String, String> rules = new HashMap<String, String>();
|
||||
String[] styles = splitComplexCssStyle(background);
|
||||
for (String style : styles) {
|
||||
if (style.contains("url(")) {
|
||||
rules.put("background-image", style);
|
||||
} else if (style.equalsIgnoreCase("repeat") ||
|
||||
style.equalsIgnoreCase("no-repeat") ||
|
||||
style.equalsIgnoreCase("repeat-x") ||
|
||||
style.equalsIgnoreCase("repeat-y")) {
|
||||
rules.put("background-repeat", style);
|
||||
} else if (style.equalsIgnoreCase("fixed") || style.equalsIgnoreCase("scroll")) {
|
||||
rules.put("background-attachment", style);
|
||||
} else if (backgroundPositions.contains(style)) {
|
||||
if (rules.get("background-position") == null) {
|
||||
rules.put("background-position", style);
|
||||
} else {
|
||||
style = style.concat(" " + (String)rules.get("background-position"));
|
||||
rules.put("background-position", style);
|
||||
}
|
||||
} else if (isNumericValue(style) || isMetricValue(style) || isRelativeValue(style)) {
|
||||
if (rules.get("background-position") == null) {
|
||||
rules.put("background-position", style);
|
||||
} else {
|
||||
style = style.concat(" " + (String)rules.get("background-position"));
|
||||
rules.put("background-position", style);
|
||||
}
|
||||
} else if (style.contains("rgb(") || style.contains("rgba(") || style.contains("#") || WebColors.NAMES.containsKey(style.toLowerCase())) {
|
||||
rules.put("background-color", style);
|
||||
}
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
|
||||
public Map<String, String> processListStyle(String listStyle) {
|
||||
Map<String, String> rules = new HashMap<String, String>();
|
||||
String[] styles = splitComplexCssStyle(listStyle);
|
||||
for (String style : styles) {
|
||||
if (style.equalsIgnoreCase("disc") ||
|
||||
style.equalsIgnoreCase("square") ||
|
||||
style.equalsIgnoreCase("circle") ||
|
||||
style.equalsIgnoreCase("lower-roman") ||
|
||||
style.equalsIgnoreCase("upper-roman") ||
|
||||
style.equalsIgnoreCase("lower-greek") ||
|
||||
style.equalsIgnoreCase("upper-greek") ||
|
||||
style.equalsIgnoreCase("lower-alpha") ||
|
||||
style.equalsIgnoreCase("upper-alpha") ||
|
||||
style.equalsIgnoreCase("lower-latin") ||
|
||||
style.equalsIgnoreCase("upper-latin")) {
|
||||
rules.put("list-style-type", style);
|
||||
} else if (style.equalsIgnoreCase("inside") || style.equalsIgnoreCase("outside")) {
|
||||
rules.put("list-style-position", style);
|
||||
} else if (style.contains("url(")) {
|
||||
rules.put("list-style-image", style);
|
||||
}
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
|
||||
public Map<String, String> processFont(String font) {
|
||||
Map<String, String> rules = new HashMap<String, String>();
|
||||
String[] styleAndRest = font.split("\\s");
|
||||
for (int i = 0; i < styleAndRest.length; i++) {
|
||||
String style = styleAndRest[i];
|
||||
if (style.equalsIgnoreCase("italic") || style.equalsIgnoreCase("oblique")) {
|
||||
rules.put("font-style", style);
|
||||
} else if (style.equalsIgnoreCase("small-caps")) {
|
||||
rules.put("font-variant", style);
|
||||
} else if (style.equalsIgnoreCase("bold")) {
|
||||
rules.put("font-weight", style);
|
||||
} else if (isMetricValue(style) || isNumericValue(style)) {
|
||||
if (style.contains("/")) {
|
||||
String[] sizeAndLineHeight = style.split("/");
|
||||
style = sizeAndLineHeight[0];
|
||||
rules.put("line-height", sizeAndLineHeight[1]);
|
||||
}
|
||||
rules.put("font-size", style);
|
||||
if (i != styleAndRest.length - 1) {
|
||||
String rest = styleAndRest[i + 1];
|
||||
rest = rest.replaceAll("\"", "");
|
||||
rest = rest.replaceAll("'", "");
|
||||
rules.put("font-family", rest);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
|
||||
public float checkMetricStyle(Tag t, String style) {
|
||||
Float metricValue = checkMetricStyle(t.getCSS(), style);
|
||||
if (metricValue != null)
|
||||
return metricValue;
|
||||
return 0.0F;
|
||||
}
|
||||
|
||||
public Float checkMetricStyle(Map<String, String> css, String style) {
|
||||
String value = css.get(style);
|
||||
if (value != null && (isMetricValue(value) || isNumericValue(value)))
|
||||
return parsePxInCmMmPcToPt(value);
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isMetricValue(String value) {
|
||||
return (value.contains("px") || value.contains("in") || value.contains("cm") ||
|
||||
value.contains("mm") || value.contains("pc") || value.contains("pt"));
|
||||
}
|
||||
|
||||
public boolean isRelativeValue(String value) {
|
||||
return (value.contains("%") || value.contains("em") || value.contains("ex"));
|
||||
}
|
||||
|
||||
public boolean isNumericValue(String value) {
|
||||
return (value.matches("^-?\\d\\d*\\.\\d*$") || value.matches("^-?\\d\\d*$") || value.matches("^-?\\.\\d\\d*$"));
|
||||
}
|
||||
|
||||
public float parseValueToPt(String value, float baseValue) {
|
||||
float parsedValue = 0.0F;
|
||||
if (isMetricValue(value) || isNumericValue(value)) {
|
||||
parsedValue = parsePxInCmMmPcToPt(value);
|
||||
} else if (isRelativeValue(value)) {
|
||||
parsedValue = parseRelativeValue(value, baseValue);
|
||||
}
|
||||
return parsedValue;
|
||||
}
|
||||
|
||||
public float parseRelativeValue(String relativeValue, float baseValue) {
|
||||
int pos = determinePositionBetweenValueAndUnit(relativeValue);
|
||||
if (pos == 0)
|
||||
return 0.0F;
|
||||
float f = Float.parseFloat(relativeValue.substring(0, pos) + "f");
|
||||
String unit = relativeValue.substring(pos);
|
||||
if (unit.startsWith("%")) {
|
||||
f = baseValue * f / 100.0F;
|
||||
} else if (unit.startsWith("em")) {
|
||||
f = baseValue * f;
|
||||
} else if (unit.contains("ex")) {
|
||||
f = baseValue * f / 2.0F;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
public float parsePxInCmMmPcToPt(String length, String defaultMetric) {
|
||||
int pos = determinePositionBetweenValueAndUnit(length);
|
||||
if (pos == 0)
|
||||
return 0.0F;
|
||||
float f = Float.parseFloat(length.substring(0, pos) + "f");
|
||||
String unit = length.substring(pos);
|
||||
if (unit.startsWith("in") || (unit.equals("") && defaultMetric.equals("in"))) {
|
||||
f *= 72.0F;
|
||||
} else if (unit.startsWith("cm") || (unit.equals("") && defaultMetric.equals("cm"))) {
|
||||
f = f / 2.54F * 72.0F;
|
||||
} else if (unit.startsWith("mm") || (unit.equals("") && defaultMetric.equals("mm"))) {
|
||||
f = f / 25.4F * 72.0F;
|
||||
} else if (unit.startsWith("pc") || (unit.equals("") && defaultMetric.equals("pc"))) {
|
||||
f *= 12.0F;
|
||||
} else if (unit.startsWith("px") || (unit.equals("") && defaultMetric.equals("px"))) {
|
||||
f *= 0.75F;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
public float parsePxInCmMmPcToPt(String length) {
|
||||
return parsePxInCmMmPcToPt(length, "px");
|
||||
}
|
||||
|
||||
public int determinePositionBetweenValueAndUnit(String string) {
|
||||
if (string == null)
|
||||
return 0;
|
||||
int pos = 0;
|
||||
boolean ok = true;
|
||||
while (ok && pos < string.length()) {
|
||||
switch (string.charAt(pos)) {
|
||||
case '+':
|
||||
case '-':
|
||||
case '.':
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
ok = false;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
public float getLeftAndRightMargin(Tag t, float pageWidth) {
|
||||
float horizontalMargin = 0.0F;
|
||||
String value = t.getCSS().get("margin-left");
|
||||
if (value != null)
|
||||
horizontalMargin += parseValueToPt(value, pageWidth);
|
||||
value = t.getCSS().get("margin-right");
|
||||
if (value != null)
|
||||
horizontalMargin += parseValueToPt(value, pageWidth);
|
||||
return horizontalMargin;
|
||||
}
|
||||
|
||||
public String extractUrl(String url) {
|
||||
String str = null;
|
||||
if (url.startsWith("url")) {
|
||||
String urlString = url.substring(3).trim().replace("(", "").replace(")", "").trim();
|
||||
if (urlString.startsWith("'") && urlString.endsWith("'")) {
|
||||
str = urlString.substring(urlString.indexOf("'") + 1, urlString.lastIndexOf("'"));
|
||||
} else if (urlString.startsWith("\"") && urlString.endsWith("\"")) {
|
||||
str = urlString.substring(urlString.indexOf('"') + 1, urlString.lastIndexOf('"'));
|
||||
} else {
|
||||
str = urlString;
|
||||
}
|
||||
} else {
|
||||
str = url;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public float validateTextHeight(Map<String, String> css, float textHeight) {
|
||||
if (null != css.get("min-height") && textHeight < new CssUtils().parsePxInCmMmPcToPt(css.get("min-height"))) {
|
||||
textHeight = new CssUtils().parsePxInCmMmPcToPt(css.get("min-height"));
|
||||
} else if (null != css.get("max-height") && textHeight > new CssUtils().parsePxInCmMmPcToPt(css.get("max-height"))) {
|
||||
textHeight = new CssUtils().parsePxInCmMmPcToPt(css.get("max-height"));
|
||||
}
|
||||
return textHeight;
|
||||
}
|
||||
|
||||
public float calculateMarginTop(String value, float largestFont, MarginMemory configuration) {
|
||||
return calculateMarginTop(parseValueToPt(value, largestFont), configuration);
|
||||
}
|
||||
|
||||
public float calculateMarginTop(float value, MarginMemory configuration) {
|
||||
float marginTop = value;
|
||||
try {
|
||||
float marginBottom = configuration.getLastMarginBottom();
|
||||
marginTop = (marginTop > marginBottom) ? (marginTop - marginBottom) : 0.0F;
|
||||
} catch (NoDataException e) {}
|
||||
return marginTop;
|
||||
}
|
||||
|
||||
public String trimAndRemoveQuoutes(String s) {
|
||||
s = s.trim();
|
||||
if (((s.startsWith("\"") || s.startsWith("'")) && s.endsWith("\"")) || s.endsWith("'"))
|
||||
s = s.substring(1, s.length() - 1);
|
||||
return s;
|
||||
}
|
||||
|
||||
public String[] splitComplexCssStyle(String s) {
|
||||
s = s.replaceAll("\\s*,\\s*", ",");
|
||||
return s.split("\\s");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package com.itextpdf.tool.xml.css;
|
||||
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class DefaultCssInheritanceRules implements CssInheritanceRules {
|
||||
public boolean inheritCssTag(String tag) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static final List<String> GLOBAL = Arrays.<String>asList("width", "height", "min-width", "max-width", "min-height", "max-height", "margin", "margin-left", "margin-right", "margin-top", "margin-bottom", "padding", "padding-left", "padding-right", "padding-top", "padding-bottom", "border-top-width", "border-top-style", "border-top-color", "border-bottom-width", "border-bottom-style", "border-bottom-color", "border-left-width", "border-left-style", "border-left-color", "border-right-width", "border-right-style", "border-right-color", "page-break-before", "page-break-after", "left", "top", "right", "bottom", "position");
|
||||
|
||||
private static final List<String> PARENT_TO_TABLE = Arrays.<String>asList("line-height", "font-size", "font-style", "font-weight", "text-indent", "cellpadding", "cellpadding-left", "cellpadding-top", "cellpadding-right", "cellpadding-bottom", "direction");
|
||||
|
||||
private static final List<String> TABLE_IN_ROW = Arrays.<String>asList("background-color", "direction");
|
||||
|
||||
private static final List<String> DIV_TO_CONTENT = Arrays.<String>asList("background", "background-color", "float");
|
||||
|
||||
private static final List<String> TD_TO_CONTENT = Arrays.<String>asList("vertical-align");
|
||||
|
||||
public boolean inheritCssSelector(Tag tag, String key) {
|
||||
if (GLOBAL.contains(key))
|
||||
return false;
|
||||
if ("table".equals(tag.getName()))
|
||||
return !PARENT_TO_TABLE.contains(key);
|
||||
if ("table".equals(tag.getParent().getName()))
|
||||
return !TABLE_IN_ROW.contains(key);
|
||||
if ("td".equalsIgnoreCase(tag.getParent().getName()))
|
||||
return !TD_TO_CONTENT.contains(key);
|
||||
if ("div".equalsIgnoreCase(tag.getParent().getName()))
|
||||
return !DIV_TO_CONTENT.contains(key);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
package com.itextpdf.tool.xml.css;
|
||||
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
|
||||
public class FontSizeTranslator {
|
||||
public static final float DEFAULT_FONT_SIZE = 12.0F;
|
||||
|
||||
private static CssUtils utils = CssUtils.getInstance();
|
||||
|
||||
private static FontSizeTranslator myself;
|
||||
|
||||
public static synchronized FontSizeTranslator getInstance() {
|
||||
if (null == myself)
|
||||
myself = new FontSizeTranslator();
|
||||
return myself;
|
||||
}
|
||||
|
||||
public float translateFontSize(Tag tag) {
|
||||
float size = -1.0F;
|
||||
if (tag.getCSS().get("font-size") != null) {
|
||||
String value = tag.getCSS().get("font-size");
|
||||
if (value.equalsIgnoreCase("xx-small")) {
|
||||
size = 6.75F;
|
||||
} else if (value.equalsIgnoreCase("x-small")) {
|
||||
size = 7.5F;
|
||||
} else if (value.equalsIgnoreCase("small")) {
|
||||
size = 9.75F;
|
||||
} else if (value.equalsIgnoreCase("medium")) {
|
||||
size = 12.0F;
|
||||
} else if (value.equalsIgnoreCase("large")) {
|
||||
size = 13.5F;
|
||||
} else if (value.equalsIgnoreCase("x-large")) {
|
||||
size = 18.0F;
|
||||
} else if (value.equalsIgnoreCase("xx-large")) {
|
||||
size = 24.0F;
|
||||
} else if (value.equalsIgnoreCase("smaller")) {
|
||||
if (tag.getParent() != null) {
|
||||
float parentSize = getFontSize(tag.getParent());
|
||||
if (parentSize == -1.0F) {
|
||||
size = 9.75F;
|
||||
} else if (parentSize <= 6.75F) {
|
||||
size = parentSize - 1.0F;
|
||||
} else if (parentSize == 7.5F) {
|
||||
size = 6.75F;
|
||||
} else if (parentSize == 9.75F) {
|
||||
size = 7.5F;
|
||||
} else if (parentSize == 12.0F) {
|
||||
size = 9.75F;
|
||||
} else if (parentSize == 13.5F) {
|
||||
size = 12.0F;
|
||||
} else if (parentSize == 18.0F) {
|
||||
size = 13.5F;
|
||||
} else if (parentSize == 24.0F) {
|
||||
size = 18.0F;
|
||||
} else if (parentSize < 24.0F) {
|
||||
size = parentSize * 0.85F;
|
||||
} else if (parentSize >= 24.0F) {
|
||||
size = parentSize * 2.0F / 3.0F;
|
||||
}
|
||||
} else {
|
||||
size = 9.75F;
|
||||
}
|
||||
} else if (value.equalsIgnoreCase("larger")) {
|
||||
if (tag.getParent() != null) {
|
||||
float parentSize = getFontSize(tag.getParent());
|
||||
if (parentSize == -1.0F) {
|
||||
size = 13.5F;
|
||||
} else if (parentSize == 6.75F) {
|
||||
size = 7.5F;
|
||||
} else if (parentSize == 7.5F) {
|
||||
size = 9.75F;
|
||||
} else if (parentSize == 9.75F) {
|
||||
size = 12.0F;
|
||||
} else if (parentSize == 12.0F) {
|
||||
size = 13.5F;
|
||||
} else if (parentSize == 13.5F) {
|
||||
size = 18.0F;
|
||||
} else if (parentSize == 18.0F) {
|
||||
size = 24.0F;
|
||||
} else {
|
||||
size = parentSize * 1.5F;
|
||||
}
|
||||
} else {
|
||||
size = 13.5F;
|
||||
}
|
||||
} else if (utils.isMetricValue(value) || utils.isNumericValue(value)) {
|
||||
size = utils.parsePxInCmMmPcToPt(value);
|
||||
} else if (utils.isRelativeValue(value)) {
|
||||
float baseValue = -1.0F;
|
||||
if (tag.getParent() != null)
|
||||
baseValue = getFontSize(tag.getParent());
|
||||
if (baseValue == -1.0F)
|
||||
baseValue = 12.0F;
|
||||
size = utils.parseRelativeValue(value, baseValue);
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public float getFontSize(Tag tag) {
|
||||
String str = tag.getCSS().get("font-size");
|
||||
if (null != str)
|
||||
return Float.parseFloat(str.replace("pt", ""));
|
||||
return -1.0F;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package com.itextpdf.tool.xml.css;
|
||||
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
|
||||
public class HeightCalculator {
|
||||
private final CssUtils utils = CssUtils.getInstance();
|
||||
|
||||
public Float getHeight(Tag tag, float pageHeight) {
|
||||
Float height = null;
|
||||
String heightValue = tag.getCSS().get("height");
|
||||
if (heightValue == null)
|
||||
heightValue = tag.getAttributes().get("height");
|
||||
if (heightValue != null)
|
||||
if (this.utils.isNumericValue(heightValue) || this.utils.isMetricValue(heightValue)) {
|
||||
height = this.utils.parsePxInCmMmPcToPt(heightValue);
|
||||
} else if (this.utils.isRelativeValue(heightValue)) {
|
||||
Tag ancestor = tag;
|
||||
Float firstAncestorsWidth = null;
|
||||
while (firstAncestorsWidth == null && ancestor.getParent() != null) {
|
||||
ancestor = ancestor.getParent();
|
||||
firstAncestorsWidth = getHeight(ancestor, pageHeight);
|
||||
}
|
||||
if (firstAncestorsWidth == null) {
|
||||
height = this.utils.parseRelativeValue(heightValue, pageHeight);
|
||||
} else {
|
||||
height = this.utils.parseRelativeValue(heightValue, firstAncestorsWidth.floatValue());
|
||||
}
|
||||
}
|
||||
return height;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,289 @@
|
|||
package com.itextpdf.tool.xml.css;
|
||||
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.exceptions.CssResolverException;
|
||||
import com.itextpdf.tool.xml.net.FileRetrieve;
|
||||
import com.itextpdf.tool.xml.net.FileRetrieveImpl;
|
||||
import com.itextpdf.tool.xml.pipeline.css.CSSResolver;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeSet;
|
||||
|
||||
public class StyleAttrCSSResolver implements CSSResolver {
|
||||
public static final String STYLE = "style";
|
||||
|
||||
private final CssUtils utils;
|
||||
|
||||
private CssInheritanceRules inherit;
|
||||
|
||||
private final CssFiles cssFiles;
|
||||
|
||||
private FileRetrieve retrieve;
|
||||
|
||||
public StyleAttrCSSResolver() {
|
||||
this(new CssFilesImpl(), CssUtils.getInstance());
|
||||
}
|
||||
|
||||
public StyleAttrCSSResolver(CssFiles cssFiles) {
|
||||
this(cssFiles, CssUtils.getInstance());
|
||||
}
|
||||
|
||||
public StyleAttrCSSResolver(CssFiles cssFiles, CssUtils utils) {
|
||||
this(new DefaultCssInheritanceRules(), cssFiles, utils);
|
||||
}
|
||||
|
||||
public StyleAttrCSSResolver(CssInheritanceRules rules, CssFiles cssFiles, CssUtils utils) {
|
||||
this(rules, cssFiles, utils, new FileRetrieveImpl());
|
||||
}
|
||||
|
||||
public StyleAttrCSSResolver(CssInheritanceRules rules, CssFiles cssFiles, CssUtils utils, FileRetrieve fileRetrieve) {
|
||||
this.utils = utils;
|
||||
this.cssFiles = cssFiles;
|
||||
this.inherit = rules;
|
||||
this.retrieve = fileRetrieve;
|
||||
}
|
||||
|
||||
public StyleAttrCSSResolver(CssFiles cssFiles, FileRetrieve r) {
|
||||
this(new DefaultCssInheritanceRules(), cssFiles, CssUtils.getInstance(), r);
|
||||
}
|
||||
|
||||
public void resolveStyles(Tag t) {
|
||||
Map<String, String> tagCss = new LinkedHashMap<String, String>();
|
||||
Map<String, String> listCss = null;
|
||||
if (null != this.cssFiles && this.cssFiles.hasFiles()) {
|
||||
tagCss = this.cssFiles.getCSS(t);
|
||||
if (t.getName().equalsIgnoreCase("p") || t.getName().equalsIgnoreCase("td"))
|
||||
listCss = this.cssFiles.getCSS(new Tag("ul"));
|
||||
}
|
||||
if (null != t.getAttributes() && !t.getAttributes().isEmpty()) {
|
||||
if (t.getAttributes().get("cellpadding") != null)
|
||||
tagCss.putAll(this.utils.parseBoxValues(t.getAttributes().get("cellpadding"), "cellpadding-", ""));
|
||||
if (t.getAttributes().get("cellspacing") != null)
|
||||
tagCss.putAll(this.utils.parseBoxValues(t.getAttributes().get("cellspacing"), "cellspacing-", ""));
|
||||
String styleAtt = t.getAttributes().get("style");
|
||||
if (null != styleAtt && styleAtt.length() > 0) {
|
||||
Map<String, String> tagAttrCss = new LinkedHashMap<String, String>();
|
||||
String[] styles = styleAtt.split(";");
|
||||
for (String s : styles) {
|
||||
String[] part = s.split(":", 2);
|
||||
if (part.length == 2) {
|
||||
String key = this.utils.stripDoubleSpacesTrimAndToLowerCase(part[0]);
|
||||
String value = this.utils.stripDoubleSpacesAndTrim(part[1]);
|
||||
splitRules(tagAttrCss, key, value);
|
||||
}
|
||||
}
|
||||
for (Map.Entry<String, String> e : tagAttrCss.entrySet())
|
||||
tagCss.put(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
Map<String, String> css = t.getCSS();
|
||||
if (t.getName() != null)
|
||||
if (t.getName().equalsIgnoreCase("i") || t.getName().equalsIgnoreCase("cite") ||
|
||||
t.getName().equalsIgnoreCase("em") || t.getName().equalsIgnoreCase("var") ||
|
||||
t.getName().equalsIgnoreCase("dfn") || t.getName().equalsIgnoreCase("address")) {
|
||||
tagCss.put("font-style", "italic");
|
||||
} else if (t.getName().equalsIgnoreCase("b") || t.getName().equalsIgnoreCase("strong")) {
|
||||
tagCss.put("font-weight", "bold");
|
||||
} else if (t.getName().equalsIgnoreCase("u") || t.getName().equalsIgnoreCase("ins")) {
|
||||
tagCss.put("text-decoration", "underline");
|
||||
} else if (t.getName().equalsIgnoreCase("s") || t.getName().equalsIgnoreCase("strike") ||
|
||||
t.getName().equalsIgnoreCase("del")) {
|
||||
tagCss.put("text-decoration", "line-through");
|
||||
} else if (t.getName().equalsIgnoreCase("big")) {
|
||||
tagCss.put("font-size", "larger");
|
||||
} else if (t.getName().equalsIgnoreCase("small")) {
|
||||
tagCss.put("font-size", "smaller");
|
||||
}
|
||||
if (listCss != null && listCss.containsKey("list-style-type"))
|
||||
css.put("list-style-type", listCss.get("list-style-type"));
|
||||
if (mustInherit(t.getName()) && null != t.getParent() && null != t.getParent().getCSS())
|
||||
if (null != this.inherit) {
|
||||
for (Map.Entry<String, String> entry : t.getParent().getCSS().entrySet()) {
|
||||
String key = entry.getKey();
|
||||
if ((tagCss.containsKey(key) && "inherit".equals(tagCss.get(key))) || canInherite(t, key)) {
|
||||
if (key.contains("cellpadding") && ("td"
|
||||
.equals(t.getName()) || "th".equals(t.getName()))) {
|
||||
String paddingKey = key.replace("cellpadding", "padding");
|
||||
tagCss.put(paddingKey, entry.getValue());
|
||||
continue;
|
||||
}
|
||||
css.put(key, entry.getValue());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
css.putAll(t.getParent().getCSS());
|
||||
}
|
||||
if (t.getName() != null)
|
||||
if (t.getName().equals("font")) {
|
||||
String font_family = t.getAttributes().get("face");
|
||||
if (font_family != null)
|
||||
css.put("font-family", font_family);
|
||||
String color = t.getAttributes().get("color");
|
||||
if (color != null)
|
||||
css.put("color", color);
|
||||
String size = t.getAttributes().get("size");
|
||||
if (size != null)
|
||||
if (size.equals("1")) {
|
||||
css.put("font-size", "xx-small");
|
||||
} else if (size.equals("2")) {
|
||||
css.put("font-size", "x-small");
|
||||
} else if (size.equals("3")) {
|
||||
css.put("font-size", "small");
|
||||
} else if (size.equals("4")) {
|
||||
css.put("font-size", "medium");
|
||||
} else if (size.equals("5")) {
|
||||
css.put("font-size", "large");
|
||||
} else if (size.equals("6")) {
|
||||
css.put("font-size", "x-large");
|
||||
} else if (size.equals("7")) {
|
||||
css.put("font-size", "xx-large");
|
||||
}
|
||||
} else if (t.getName().equals("a")) {
|
||||
css.put("text-decoration", "underline");
|
||||
css.put("color", "blue");
|
||||
}
|
||||
for (Map.Entry<String, String> e : tagCss.entrySet()) {
|
||||
if (!"inherit".equalsIgnoreCase(e.getValue())) {
|
||||
if (e.getKey().equals("text-decoration")) {
|
||||
String oldValue = css.get(e.getKey());
|
||||
css.put(e.getKey(), mergeTextDecorationRules(oldValue, e.getValue()));
|
||||
continue;
|
||||
}
|
||||
css.put(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String mergeTextDecorationRules(String oldRule, String newRule) {
|
||||
if ("none".equals(newRule))
|
||||
return newRule;
|
||||
TreeSet<String> attrSet = new TreeSet<String>();
|
||||
if (oldRule != null)
|
||||
Collections.<String>addAll(attrSet, oldRule.split("\\s+"));
|
||||
if (newRule != null)
|
||||
Collections.<String>addAll(attrSet, newRule.split("\\s+"));
|
||||
StringBuilder resultantStr = new StringBuilder();
|
||||
for (String attr : attrSet) {
|
||||
if (attr.equals("none") || attr.equals("inherit"))
|
||||
continue;
|
||||
if (resultantStr.length() > 0)
|
||||
resultantStr.append(' ');
|
||||
resultantStr.append(attr);
|
||||
}
|
||||
return (resultantStr.length() == 0) ? null : resultantStr.toString();
|
||||
}
|
||||
|
||||
private void splitRules(Map<String, String> css, String key, String value) {
|
||||
if ("border".equalsIgnoreCase(key)) {
|
||||
css.putAll(this.utils.parseBorder(value));
|
||||
} else if ("border-top".equalsIgnoreCase(key)) {
|
||||
css.putAll(this.utils.parseBorder(value, "border-top"));
|
||||
} else if ("border-bottom".equalsIgnoreCase(key)) {
|
||||
css.putAll(this.utils.parseBorder(value, "border-bottom"));
|
||||
} else if ("border-left".equalsIgnoreCase(key)) {
|
||||
css.putAll(this.utils.parseBorder(value, "border-left"));
|
||||
} else if ("border-right".equalsIgnoreCase(key)) {
|
||||
css.putAll(this.utils.parseBorder(value, "border-right"));
|
||||
} else if ("margin".equalsIgnoreCase(key)) {
|
||||
css.putAll(this.utils.parseBoxValues(value, "margin-", ""));
|
||||
} else if ("border-width".equalsIgnoreCase(key)) {
|
||||
css.putAll(this.utils.parseBoxValues(value, "border-", "-width"));
|
||||
} else if ("border-style".equalsIgnoreCase(key)) {
|
||||
css.putAll(this.utils.parseBoxValues(value, "border-", "-style"));
|
||||
} else if ("border-color".equalsIgnoreCase(key)) {
|
||||
css.putAll(this.utils.parseBoxValues(value, "border-", "-color"));
|
||||
} else if ("padding".equalsIgnoreCase(key)) {
|
||||
css.putAll(this.utils.parseBoxValues(value, "padding-", ""));
|
||||
} else if ("font".equalsIgnoreCase(key)) {
|
||||
css.putAll(this.utils.processFont(value));
|
||||
} else if ("list-style".equalsIgnoreCase(key)) {
|
||||
css.putAll(this.utils.processListStyle(value));
|
||||
} else if (key.toLowerCase().contains("background")) {
|
||||
Map<String, String> backgroundStyles = this.utils.processBackground(value);
|
||||
for (String backgroundKey : backgroundStyles.keySet()) {
|
||||
if (!css.containsKey(backgroundKey))
|
||||
css.put(backgroundKey, backgroundStyles.get(backgroundKey));
|
||||
}
|
||||
} else {
|
||||
css.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void setCssInheritance(CssInheritanceRules cssInheritanceRules) {
|
||||
this.inherit = cssInheritanceRules;
|
||||
}
|
||||
|
||||
private boolean canInherite(Tag t, String property) {
|
||||
if (null != this.inherit)
|
||||
return this.inherit.inheritCssSelector(t, property);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean mustInherit(String tag) {
|
||||
if (null != this.inherit)
|
||||
return this.inherit.inheritCssTag(tag);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void addCss(String content, String charSet, boolean isPersistent) throws CssResolverException {
|
||||
CssFileProcessor proc = new CssFileProcessor();
|
||||
try {
|
||||
this.retrieve.processFromStream(new ByteArrayInputStream(content.getBytes(charSet)), proc);
|
||||
CssFile css = proc.getCss();
|
||||
css.isPersistent(isPersistent);
|
||||
this.cssFiles.add(css);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new CssResolverException(e);
|
||||
} catch (IOException e) {
|
||||
throw new CssResolverException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void addCssFile(String href, boolean isPersistent) throws CssResolverException {
|
||||
CssFileProcessor cssFileProcessor = new CssFileProcessor();
|
||||
try {
|
||||
this.retrieve.processFromHref(href, cssFileProcessor);
|
||||
} catch (IOException e) {
|
||||
throw new CssResolverException(e);
|
||||
}
|
||||
CssFile css = cssFileProcessor.getCss();
|
||||
css.isPersistent(isPersistent);
|
||||
this.cssFiles.add(css);
|
||||
}
|
||||
|
||||
public void addCss(CssFile file) {
|
||||
this.cssFiles.add(file);
|
||||
}
|
||||
|
||||
public void addCss(String content, boolean isPersistent) throws CssResolverException {
|
||||
CssFileProcessor proc = new CssFileProcessor();
|
||||
FileRetrieve retrieve = new FileRetrieveImpl();
|
||||
try {
|
||||
retrieve.processFromStream(new ByteArrayInputStream(content.getBytes()), proc);
|
||||
CssFile css = proc.getCss();
|
||||
css.isPersistent(isPersistent);
|
||||
this.cssFiles.add(css);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new CssResolverException(e);
|
||||
} catch (IOException e) {
|
||||
throw new CssResolverException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void setCssInheritanceRules(CssInheritanceRules inherit) {
|
||||
this.inherit = inherit;
|
||||
}
|
||||
|
||||
public void setFileRetrieve(FileRetrieve retrieve) {
|
||||
this.retrieve = retrieve;
|
||||
}
|
||||
|
||||
public CSSResolver clear() throws CssResolverException {
|
||||
this.cssFiles.clear();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package com.itextpdf.tool.xml.css;
|
||||
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import java.util.List;
|
||||
|
||||
public class WidthCalculator {
|
||||
private final CssUtils utils = CssUtils.getInstance();
|
||||
|
||||
public float getWidth(Tag tag, List<String> roottags, float pagewidth) {
|
||||
return getWidth(tag, roottags, pagewidth, -1.0F);
|
||||
}
|
||||
|
||||
public float getWidth(Tag tag, List<String> roottags, float pagewidth, float initialTotalWidth) {
|
||||
float width = 0.0F;
|
||||
String widthValue = tag.getCSS().get("width");
|
||||
if (widthValue == null)
|
||||
widthValue = tag.getAttributes().get("width");
|
||||
if (widthValue != null) {
|
||||
if (this.utils.isNumericValue(widthValue) || this.utils.isMetricValue(widthValue)) {
|
||||
width = this.utils.parsePxInCmMmPcToPt(widthValue);
|
||||
} else if (this.utils.isRelativeValue(widthValue)) {
|
||||
Tag ancestor = tag;
|
||||
float firstAncestorsWidth = 0.0F;
|
||||
while (firstAncestorsWidth == 0.0F && ancestor.getParent() != null) {
|
||||
ancestor = ancestor.getParent();
|
||||
firstAncestorsWidth = getWidth(ancestor, roottags, pagewidth, initialTotalWidth);
|
||||
}
|
||||
if (firstAncestorsWidth == 0.0F) {
|
||||
width = this.utils.parseRelativeValue(widthValue, pagewidth);
|
||||
} else {
|
||||
width = this.utils.parseRelativeValue(widthValue, firstAncestorsWidth);
|
||||
}
|
||||
}
|
||||
} else if (roottags.contains(tag.getName())) {
|
||||
if (Float.compare(initialTotalWidth, -1.0F) == 0) {
|
||||
width = pagewidth;
|
||||
} else {
|
||||
width = initialTotalWidth;
|
||||
}
|
||||
}
|
||||
return width;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,219 @@
|
|||
package com.itextpdf.tool.xml.css.apply;
|
||||
|
||||
import com.itextpdf.text.BaseColor;
|
||||
import com.itextpdf.text.Chunk;
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.text.Font;
|
||||
import com.itextpdf.text.FontFactoryImp;
|
||||
import com.itextpdf.text.FontProvider;
|
||||
import com.itextpdf.text.html.HtmlUtilities;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.css.CssUtils;
|
||||
import com.itextpdf.tool.xml.css.FontSizeTranslator;
|
||||
import com.itextpdf.tool.xml.html.CssApplier;
|
||||
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ChunkCssApplier implements CssApplier<Chunk> {
|
||||
public static final List<String> BOLD = Arrays.<String>asList("bold", "bolder", "600", "700", "800", "900");
|
||||
|
||||
protected final CssUtils utils = CssUtils.getInstance();
|
||||
|
||||
protected FontProvider fontProvider;
|
||||
|
||||
public ChunkCssApplier() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public ChunkCssApplier(FontProvider fontProvider) {
|
||||
if (fontProvider != null) {
|
||||
this.fontProvider = fontProvider;
|
||||
} else {
|
||||
this.fontProvider = new FontFactoryImp();
|
||||
}
|
||||
}
|
||||
|
||||
public Chunk apply(Chunk c, Tag t) {
|
||||
return apply(c, t, null, null, null);
|
||||
}
|
||||
|
||||
public Chunk apply(Chunk c, Tag t, MarginMemory mm, PageSizeContainable psc, HtmlPipelineContext ctx) {
|
||||
Font f = applyFontStyles(t);
|
||||
float size = f.getSize();
|
||||
Map<String, String> rules = t.getCSS();
|
||||
for (Map.Entry<String, String> entry : rules.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
if ("font-style".equalsIgnoreCase(key)) {
|
||||
if (value.equalsIgnoreCase("oblique"))
|
||||
c.setSkew(0.0F, 12.0F);
|
||||
continue;
|
||||
}
|
||||
if ("letter-spacing".equalsIgnoreCase(key)) {
|
||||
String letterSpacing = rules.get("letter-spacing");
|
||||
float letterSpacingValue = 0.0F;
|
||||
if (this.utils.isRelativeValue(value)) {
|
||||
letterSpacingValue = this.utils.parseRelativeValue(letterSpacing, f.getSize());
|
||||
} else if (this.utils.isMetricValue(value)) {
|
||||
letterSpacingValue = this.utils.parsePxInCmMmPcToPt(letterSpacing);
|
||||
}
|
||||
c.setCharacterSpacing(letterSpacingValue);
|
||||
continue;
|
||||
}
|
||||
if (null != rules.get("xfa-font-horizontal-scale"))
|
||||
c.setHorizontalScaling(Float.parseFloat(rules.get("xfa-font-horizontal-scale").replace("%", "")) / 100.0F);
|
||||
}
|
||||
if (null != rules.get("vertical-align")) {
|
||||
String value = rules.get("vertical-align");
|
||||
if (value.equalsIgnoreCase("super") || value.equalsIgnoreCase("top") || value.equalsIgnoreCase("text-top")) {
|
||||
c.setTextRise((float)((double)(size / 2.0F) + 0.5D));
|
||||
} else if (value.equalsIgnoreCase("sub") || value.equalsIgnoreCase("bottom") || value.equalsIgnoreCase("text-bottom")) {
|
||||
c.setTextRise(-size / 2.0F);
|
||||
} else {
|
||||
c.setTextRise(this.utils.parsePxInCmMmPcToPt(value));
|
||||
}
|
||||
}
|
||||
String xfaVertScale = rules.get("xfa-font-vertical-scale");
|
||||
if (null != xfaVertScale &&
|
||||
xfaVertScale.contains("%")) {
|
||||
size *= Float.parseFloat(xfaVertScale.replace("%", "")) / 100.0F;
|
||||
c.setHorizontalScaling(100.0F / Float.parseFloat(xfaVertScale.replace("%", "")));
|
||||
}
|
||||
if (null != rules.get("text-decoration")) {
|
||||
String[] splitValues = rules.get("text-decoration").split("\\s+");
|
||||
for (String value : splitValues) {
|
||||
if ("underline".equalsIgnoreCase(value))
|
||||
c.setUnderline(null, 0.75F, 0.0F, 0.0F, -0.125F, 0);
|
||||
if ("line-through".equalsIgnoreCase(value))
|
||||
c.setUnderline(null, 0.75F, 0.0F, 0.0F, 0.25F, 0);
|
||||
}
|
||||
}
|
||||
if (null != rules.get("background-color"))
|
||||
c.setBackground(HtmlUtilities.decodeColor(rules.get("background-color")));
|
||||
f.setSize(size);
|
||||
c.setFont(f);
|
||||
Float leading = null;
|
||||
if (rules.get("line-height") != null) {
|
||||
String value = rules.get("line-height");
|
||||
if (this.utils.isNumericValue(value)) {
|
||||
leading = Float.parseFloat(value) * c.getFont().getSize();
|
||||
} else if (this.utils.isRelativeValue(value)) {
|
||||
leading = this.utils.parseRelativeValue(value, c.getFont().getSize());
|
||||
} else if (this.utils.isMetricValue(value)) {
|
||||
leading = this.utils.parsePxInCmMmPcToPt(value);
|
||||
}
|
||||
}
|
||||
if (leading != null)
|
||||
c.setLineHeight(leading.floatValue());
|
||||
return c;
|
||||
}
|
||||
|
||||
public Font applyFontStyles(Tag t) {
|
||||
String fontName = null;
|
||||
String encoding = "Cp1252";
|
||||
float size = FontSizeTranslator.getInstance().getFontSize(t);
|
||||
if (size == -1.0F)
|
||||
size = 12.0F;
|
||||
int style = -1;
|
||||
BaseColor color = null;
|
||||
Map<String, String> rules = t.getCSS();
|
||||
for (Map.Entry<String, String> entry : rules.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
if ("font-weight".equalsIgnoreCase(key)) {
|
||||
if (isBoldValue(value)) {
|
||||
if (style == 2) {
|
||||
style = 3;
|
||||
continue;
|
||||
}
|
||||
style = 1;
|
||||
continue;
|
||||
}
|
||||
if (style == 3) {
|
||||
style = 2;
|
||||
continue;
|
||||
}
|
||||
if (style == 1)
|
||||
style = 0;
|
||||
continue;
|
||||
}
|
||||
if ("font-style".equalsIgnoreCase(key)) {
|
||||
if (value.equalsIgnoreCase("italic")) {
|
||||
if (style == 1) {
|
||||
style = 3;
|
||||
continue;
|
||||
}
|
||||
style = 2;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ("font-family".equalsIgnoreCase(key)) {
|
||||
fontName = value;
|
||||
continue;
|
||||
}
|
||||
if ("color".equalsIgnoreCase(key))
|
||||
color = HtmlUtilities.decodeColor(value);
|
||||
}
|
||||
if (fontName != null)
|
||||
if (fontName.contains(",")) {
|
||||
String[] fonts = fontName.split(",");
|
||||
Font firstFont = null;
|
||||
for (String s : fonts) {
|
||||
s = this.utils.trimAndRemoveQuoutes(s);
|
||||
if (this.fontProvider.isRegistered(s)) {
|
||||
Font f = this.fontProvider.getFont(s, encoding, true, size, style, color);
|
||||
if (f != null && (style == 0 || style == -1 || (f.getStyle() & style) == 0))
|
||||
return f;
|
||||
if (firstFont == null)
|
||||
firstFont = f;
|
||||
}
|
||||
}
|
||||
if (firstFont != null)
|
||||
return firstFont;
|
||||
if (fonts.length > 0) {
|
||||
fontName = this.utils.trimAndRemoveQuoutes(fontName.split(",")[0]);
|
||||
} else {
|
||||
fontName = null;
|
||||
}
|
||||
} else {
|
||||
fontName = this.utils.trimAndRemoveQuoutes(fontName);
|
||||
}
|
||||
return this.fontProvider.getFont(fontName, encoding, true, size, style, color);
|
||||
}
|
||||
|
||||
public float getWidestWord(Chunk c) {
|
||||
String[] words = c.getContent().split("\\s");
|
||||
float widestWord = 0.0F;
|
||||
for (int i = 0; i < words.length; i++) {
|
||||
Chunk word = new Chunk(words[i]);
|
||||
copyChunkStyles(c, word);
|
||||
if (word.getWidthPoint() > widestWord)
|
||||
widestWord = word.getWidthPoint();
|
||||
}
|
||||
return widestWord;
|
||||
}
|
||||
|
||||
public void copyChunkStyles(Chunk source, Chunk target) {
|
||||
target.setFont(source.getFont());
|
||||
target.setAttributes(source.getAttributes());
|
||||
target.setCharacterSpacing(source.getCharacterSpacing());
|
||||
target.setHorizontalScaling(source.getHorizontalScaling());
|
||||
target.setHorizontalScaling(source.getHorizontalScaling());
|
||||
}
|
||||
|
||||
public FontProvider getFontProvider() {
|
||||
return this.fontProvider;
|
||||
}
|
||||
|
||||
public void setFontProvider(FontProvider fontProvider) {
|
||||
this.fontProvider = fontProvider;
|
||||
}
|
||||
|
||||
protected boolean isBoldValue(String value) {
|
||||
value = value.trim();
|
||||
return ("bold".contains(value) || (
|
||||
value.length() == 3 && value.endsWith("00") && value.charAt(0) >= '6' && value.charAt(0) <= '9'));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,255 @@
|
|||
package com.itextpdf.tool.xml.css.apply;
|
||||
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.text.Image;
|
||||
import com.itextpdf.text.html.HtmlUtilities;
|
||||
import com.itextpdf.text.log.Level;
|
||||
import com.itextpdf.text.log.Logger;
|
||||
import com.itextpdf.text.log.LoggerFactory;
|
||||
import com.itextpdf.text.pdf.PdfDiv;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.css.CSS;
|
||||
import com.itextpdf.tool.xml.css.CssUtils;
|
||||
import com.itextpdf.tool.xml.css.FontSizeTranslator;
|
||||
import com.itextpdf.tool.xml.exceptions.LocaleMessages;
|
||||
import com.itextpdf.tool.xml.html.CssApplier;
|
||||
import com.itextpdf.tool.xml.net.ImageRetrieve;
|
||||
import com.itextpdf.tool.xml.net.exc.NoImageException;
|
||||
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
|
||||
import java.util.Map;
|
||||
|
||||
public class DivCssApplier implements CssApplier<PdfDiv> {
|
||||
private final CssUtils utils = CssUtils.getInstance();
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ListStyleTypeCssApplier.class);
|
||||
|
||||
public PdfDiv apply(PdfDiv div, Tag t, MarginMemory memory, PageSizeContainable psc, HtmlPipelineContext context) {
|
||||
Map<String, String> css = t.getCSS();
|
||||
float fontSize = FontSizeTranslator.getInstance().translateFontSize(t);
|
||||
if (fontSize == -1.0F)
|
||||
fontSize = 12.0F;
|
||||
String align = null;
|
||||
if (t.getAttributes().containsKey("align")) {
|
||||
align = t.getAttributes().get("align");
|
||||
} else if (css.containsKey("text-align")) {
|
||||
align = css.get("text-align");
|
||||
}
|
||||
if (align != null)
|
||||
div.setTextAlignment(CSS.getElementAlignment(align));
|
||||
String widthValue = css.get("width");
|
||||
if (widthValue == null)
|
||||
widthValue = t.getAttributes().get("width");
|
||||
if (widthValue != null) {
|
||||
float pageWidth = psc.getPageSize().getWidth();
|
||||
if (this.utils.isNumericValue(widthValue) || this.utils.isMetricValue(widthValue)) {
|
||||
div.setWidth(Float.valueOf(Math.min(pageWidth, this.utils.parsePxInCmMmPcToPt(widthValue))));
|
||||
} else if (this.utils.isRelativeValue(widthValue)) {
|
||||
if (widthValue.contains("%")) {
|
||||
div.setPercentageWidth(Float.valueOf(this.utils.parseRelativeValue(widthValue, 1.0F)));
|
||||
} else {
|
||||
div.setWidth(Float.valueOf(Math.min(pageWidth, this.utils.parseRelativeValue(widthValue, fontSize))));
|
||||
}
|
||||
}
|
||||
}
|
||||
String heightValue = css.get("height");
|
||||
if (heightValue == null)
|
||||
heightValue = t.getAttributes().get("height");
|
||||
if (heightValue != null)
|
||||
if (this.utils.isNumericValue(heightValue) || this.utils.isMetricValue(heightValue)) {
|
||||
div.setHeight(Float.valueOf(this.utils.parsePxInCmMmPcToPt(heightValue)));
|
||||
} else if (this.utils.isRelativeValue(heightValue)) {
|
||||
if (heightValue.contains("%")) {
|
||||
div.setPercentageHeight(Float.valueOf(this.utils.parseRelativeValue(heightValue, 1.0F)));
|
||||
} else {
|
||||
div.setHeight(Float.valueOf(this.utils.parseRelativeValue(heightValue, fontSize)));
|
||||
}
|
||||
}
|
||||
Float marginTop = null;
|
||||
Float marginBottom = null;
|
||||
for (Map.Entry<String, String> entry : css.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
if (key.equalsIgnoreCase("left")) {
|
||||
div.setLeft(Float.valueOf(this.utils.parseValueToPt(value, fontSize)));
|
||||
continue;
|
||||
}
|
||||
if (key.equalsIgnoreCase("right")) {
|
||||
if (div.getWidth() == null || div.getLeft() == null)
|
||||
div.setRight(Float.valueOf(this.utils.parseValueToPt(value, fontSize)));
|
||||
continue;
|
||||
}
|
||||
if (key.equalsIgnoreCase("top")) {
|
||||
div.setTop(Float.valueOf(this.utils.parseValueToPt(value, fontSize)));
|
||||
continue;
|
||||
}
|
||||
if (key.equalsIgnoreCase("bottom")) {
|
||||
if (div.getHeight() == null || div.getTop() == null)
|
||||
div.setBottom(Float.valueOf(this.utils.parseValueToPt(value, fontSize)));
|
||||
continue;
|
||||
}
|
||||
if (key.equalsIgnoreCase("background-color")) {
|
||||
div.setBackgroundColor(HtmlUtilities.decodeColor(value));
|
||||
continue;
|
||||
}
|
||||
if (key.equalsIgnoreCase("background-image")) {
|
||||
String url = this.utils.extractUrl(value);
|
||||
try {
|
||||
Image img = new ImageRetrieve(context.getResourcesRootPath(), context.getImageProvider()).retrieveImage(url);
|
||||
div.setBackgroundImage(img);
|
||||
} catch (NoImageException e) {
|
||||
if (LOG.isLogging(Level.ERROR))
|
||||
LOG.error(String.format(LocaleMessages.getInstance().getMessage("html.tag.img.failed"), url), e);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (key.equalsIgnoreCase("padding-left")) {
|
||||
div.setPaddingLeft(this.utils.parseValueToPt(value, fontSize));
|
||||
continue;
|
||||
}
|
||||
if (key.equalsIgnoreCase("padding-right")) {
|
||||
div.setPaddingRight(this.utils.parseValueToPt(value, fontSize));
|
||||
continue;
|
||||
}
|
||||
if (key.equalsIgnoreCase("padding-top")) {
|
||||
div.setPaddingTop(this.utils.parseValueToPt(value, fontSize));
|
||||
continue;
|
||||
}
|
||||
if (key.equalsIgnoreCase("padding-bottom")) {
|
||||
div.setPaddingBottom(this.utils.parseValueToPt(value, fontSize));
|
||||
continue;
|
||||
}
|
||||
if (key.equalsIgnoreCase("margin-top")) {
|
||||
marginTop = this.utils.calculateMarginTop(value, fontSize, memory);
|
||||
continue;
|
||||
}
|
||||
if (key.equalsIgnoreCase("margin-bottom")) {
|
||||
marginBottom = this.utils.parseValueToPt(value, fontSize);
|
||||
continue;
|
||||
}
|
||||
if (key.equalsIgnoreCase("float")) {
|
||||
if (value.equalsIgnoreCase("left")) {
|
||||
div.setFloatType(PdfDiv.FloatType.LEFT);
|
||||
continue;
|
||||
}
|
||||
if (value.equalsIgnoreCase("right"))
|
||||
div.setFloatType(PdfDiv.FloatType.RIGHT);
|
||||
continue;
|
||||
}
|
||||
if (key.equalsIgnoreCase("position")) {
|
||||
if (value.equalsIgnoreCase("absolute")) {
|
||||
div.setPosition(PdfDiv.PositionType.ABSOLUTE);
|
||||
continue;
|
||||
}
|
||||
if (value.equalsIgnoreCase("fixed")) {
|
||||
div.setPosition(PdfDiv.PositionType.FIXED);
|
||||
continue;
|
||||
}
|
||||
if (value.equalsIgnoreCase("relative"))
|
||||
div.setPosition(PdfDiv.PositionType.RELATIVE);
|
||||
continue;
|
||||
}
|
||||
if (key.equalsIgnoreCase("display")) {
|
||||
if (value.equalsIgnoreCase("block")) {
|
||||
div.setDisplay(PdfDiv.DisplayType.BLOCK);
|
||||
continue;
|
||||
}
|
||||
if (value.equalsIgnoreCase("inline")) {
|
||||
div.setDisplay(PdfDiv.DisplayType.INLINE);
|
||||
continue;
|
||||
}
|
||||
if (value.equalsIgnoreCase("inline-block")) {
|
||||
div.setDisplay(PdfDiv.DisplayType.INLINE_BLOCK);
|
||||
continue;
|
||||
}
|
||||
if (value.equalsIgnoreCase("inline-table")) {
|
||||
div.setDisplay(PdfDiv.DisplayType.INLINE_TABLE);
|
||||
continue;
|
||||
}
|
||||
if (value.equalsIgnoreCase("list-item")) {
|
||||
div.setDisplay(PdfDiv.DisplayType.LIST_ITEM);
|
||||
continue;
|
||||
}
|
||||
if (value.equalsIgnoreCase("none")) {
|
||||
div.setDisplay(PdfDiv.DisplayType.NONE);
|
||||
continue;
|
||||
}
|
||||
if (value.equalsIgnoreCase("run-in")) {
|
||||
div.setDisplay(PdfDiv.DisplayType.RUN_IN);
|
||||
continue;
|
||||
}
|
||||
if (value.equalsIgnoreCase("table")) {
|
||||
div.setDisplay(PdfDiv.DisplayType.TABLE);
|
||||
continue;
|
||||
}
|
||||
if (value.equalsIgnoreCase("table-caption")) {
|
||||
div.setDisplay(PdfDiv.DisplayType.TABLE_CAPTION);
|
||||
continue;
|
||||
}
|
||||
if (value.equalsIgnoreCase("table-cell")) {
|
||||
div.setDisplay(PdfDiv.DisplayType.TABLE_CELL);
|
||||
continue;
|
||||
}
|
||||
if (value.equalsIgnoreCase("table-column-group")) {
|
||||
div.setDisplay(PdfDiv.DisplayType.TABLE_COLUMN_GROUP);
|
||||
continue;
|
||||
}
|
||||
if (value.equalsIgnoreCase("table-column")) {
|
||||
div.setDisplay(PdfDiv.DisplayType.TABLE_COLUMN);
|
||||
continue;
|
||||
}
|
||||
if (value.equalsIgnoreCase("table-footer-group")) {
|
||||
div.setDisplay(PdfDiv.DisplayType.TABLE_FOOTER_GROUP);
|
||||
continue;
|
||||
}
|
||||
if (value.equalsIgnoreCase("table-header-group")) {
|
||||
div.setDisplay(PdfDiv.DisplayType.TABLE_HEADER_GROUP);
|
||||
continue;
|
||||
}
|
||||
if (value.equalsIgnoreCase("table-row")) {
|
||||
div.setDisplay(PdfDiv.DisplayType.TABLE_ROW);
|
||||
continue;
|
||||
}
|
||||
if (value.equalsIgnoreCase("table-row-group"))
|
||||
div.setDisplay(PdfDiv.DisplayType.TABLE_ROW_GROUP);
|
||||
continue;
|
||||
}
|
||||
if (key.equalsIgnoreCase("border-top-style")) {
|
||||
if (value.equalsIgnoreCase("dotted")) {
|
||||
div.setBorderTopStyle(PdfDiv.BorderTopStyle.DOTTED);
|
||||
continue;
|
||||
}
|
||||
if (value.equalsIgnoreCase("dashed")) {
|
||||
div.setBorderTopStyle(PdfDiv.BorderTopStyle.DASHED);
|
||||
continue;
|
||||
}
|
||||
if (value.equalsIgnoreCase("solid")) {
|
||||
div.setBorderTopStyle(PdfDiv.BorderTopStyle.SOLID);
|
||||
continue;
|
||||
}
|
||||
if (value.equalsIgnoreCase("double")) {
|
||||
div.setBorderTopStyle(PdfDiv.BorderTopStyle.DOUBLE);
|
||||
continue;
|
||||
}
|
||||
if (value.equalsIgnoreCase("groove")) {
|
||||
div.setBorderTopStyle(PdfDiv.BorderTopStyle.GROOVE);
|
||||
continue;
|
||||
}
|
||||
if (value.equalsIgnoreCase("ridge")) {
|
||||
div.setBorderTopStyle(PdfDiv.BorderTopStyle.RIDGE);
|
||||
continue;
|
||||
}
|
||||
if (value.equalsIgnoreCase("inset")) {
|
||||
div.setBorderTopStyle(PdfDiv.BorderTopStyle.INSET);
|
||||
continue;
|
||||
}
|
||||
if (value.equalsIgnoreCase("outset"))
|
||||
div.setBorderTopStyle(PdfDiv.BorderTopStyle.OUTSET);
|
||||
continue;
|
||||
}
|
||||
if (key.equalsIgnoreCase("page-break-inside") &&
|
||||
value.equalsIgnoreCase("avoid"))
|
||||
div.setKeepTogether(true);
|
||||
}
|
||||
return div;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,205 @@
|
|||
package com.itextpdf.tool.xml.css.apply;
|
||||
|
||||
import com.itextpdf.text.BaseColor;
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.text.html.HtmlUtilities;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.css.CSS;
|
||||
import com.itextpdf.tool.xml.css.CssUtils;
|
||||
import com.itextpdf.tool.xml.css.HeightCalculator;
|
||||
import com.itextpdf.tool.xml.css.WidthCalculator;
|
||||
import com.itextpdf.tool.xml.html.CssApplier;
|
||||
import com.itextpdf.tool.xml.html.pdfelement.HtmlCell;
|
||||
import com.itextpdf.tool.xml.html.table.CellSpacingEvent;
|
||||
import com.itextpdf.tool.xml.html.table.Table;
|
||||
import com.itextpdf.tool.xml.html.table.TableStyleValues;
|
||||
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
|
||||
import java.util.Map;
|
||||
|
||||
public class HtmlCellCssApplier implements CssApplier<HtmlCell> {
|
||||
private final CssUtils utils = CssUtils.getInstance();
|
||||
|
||||
public HtmlCell apply(HtmlCell cell, Tag t, MarginMemory memory, PageSizeContainable psc) {
|
||||
return apply(cell, t, memory, psc, null);
|
||||
}
|
||||
|
||||
public HtmlCell apply(HtmlCell cell, Tag t, MarginMemory memory, PageSizeContainable psc, HtmlPipelineContext ctx) {
|
||||
Tag row = t.getParent();
|
||||
while (row != null && !row.getName().equals("tr"))
|
||||
row = row.getParent();
|
||||
Tag table = t.getParent();
|
||||
while (table != null && !table.getName().equals("table"))
|
||||
table = table.getParent();
|
||||
TableStyleValues values = Table.setBorderAttributeForCell(table);
|
||||
Map<String, String> css = t.getCSS();
|
||||
String emptyCells = css.get("empty-cells");
|
||||
if (null != emptyCells && "hide".equalsIgnoreCase(emptyCells) && cell.getCompositeElements() == null) {
|
||||
cell.setBorder(0);
|
||||
} else {
|
||||
cell.setVerticalAlignment(5);
|
||||
String vAlign = null;
|
||||
if (t.getAttributes().containsKey("valign")) {
|
||||
vAlign = t.getAttributes().get("valign");
|
||||
} else if (css.containsKey("valign")) {
|
||||
vAlign = css.get("valign");
|
||||
} else if (row != null) {
|
||||
if (row.getAttributes().containsKey("valign")) {
|
||||
vAlign = row.getAttributes().get("valign");
|
||||
} else if (row.getCSS().containsKey("valign")) {
|
||||
vAlign = row.getCSS().get("valign");
|
||||
}
|
||||
}
|
||||
if (vAlign != null)
|
||||
if (vAlign.equalsIgnoreCase("top")) {
|
||||
cell.setVerticalAlignment(4);
|
||||
} else if (vAlign.equalsIgnoreCase("bottom")) {
|
||||
cell.setVerticalAlignment(6);
|
||||
}
|
||||
String align = null;
|
||||
if (t.getAttributes().containsKey("align")) {
|
||||
align = t.getAttributes().get("align");
|
||||
} else if (css.containsKey("text-align")) {
|
||||
align = css.get("text-align");
|
||||
}
|
||||
if (align != null)
|
||||
if (align.equalsIgnoreCase("center")) {
|
||||
cell.setHorizontalAlignment(1);
|
||||
} else if (align.equalsIgnoreCase("right")) {
|
||||
cell.setHorizontalAlignment(2);
|
||||
} else if (align.equalsIgnoreCase("justify")) {
|
||||
cell.setHorizontalAlignment(3);
|
||||
}
|
||||
if (t.getAttributes().get("width") != null || css.get("width") != null)
|
||||
cell.setFixedWidth(new WidthCalculator().getWidth(t, memory.getRootTags(), psc.getPageSize().getWidth()));
|
||||
HeightCalculator heightCalc = new HeightCalculator();
|
||||
Float height = heightCalc.getHeight(t, psc.getPageSize().getHeight());
|
||||
if (height == null && row != null)
|
||||
height = heightCalc.getHeight(row, psc.getPageSize().getHeight());
|
||||
if (height != null)
|
||||
cell.setMinimumHeight(height.floatValue());
|
||||
String colspan = t.getAttributes().get("colspan");
|
||||
if (null != colspan)
|
||||
cell.setColspan(Integer.parseInt(colspan));
|
||||
String rowspan = t.getAttributes().get("rowspan");
|
||||
if (null != rowspan)
|
||||
cell.setRowspan(Integer.parseInt(rowspan));
|
||||
for (Map.Entry<String, String> entry : css.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
cell.setUseBorderPadding(true);
|
||||
if (key.equalsIgnoreCase("background-color")) {
|
||||
values.setBackground(HtmlUtilities.decodeColor(value));
|
||||
continue;
|
||||
}
|
||||
if (key.equalsIgnoreCase("vertical-align")) {
|
||||
if (value.equalsIgnoreCase("top")) {
|
||||
cell.setVerticalAlignment(4);
|
||||
cell.setPaddingTop(cell.getPaddingTop() + 6.0F);
|
||||
continue;
|
||||
}
|
||||
if (value.equalsIgnoreCase("bottom")) {
|
||||
cell.setVerticalAlignment(6);
|
||||
cell.setPaddingBottom(cell.getPaddingBottom() + 6.0F);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (key.contains("border")) {
|
||||
if (key.contains("top")) {
|
||||
setTopOfBorder(cell, key, value, values);
|
||||
continue;
|
||||
}
|
||||
if (key.contains("bottom")) {
|
||||
setBottomOfBorder(cell, key, value, values);
|
||||
continue;
|
||||
}
|
||||
if (key.contains("left")) {
|
||||
setLeftOfBorder(cell, key, value, values);
|
||||
continue;
|
||||
}
|
||||
if (key.contains("right"))
|
||||
setRightOfBorder(cell, key, value, values);
|
||||
continue;
|
||||
}
|
||||
if (key.contains("cellpadding") || key.contains("padding")) {
|
||||
if (key.contains("top")) {
|
||||
cell.setPaddingTop(cell.getPaddingTop() + this.utils.parsePxInCmMmPcToPt(value));
|
||||
continue;
|
||||
}
|
||||
if (key.contains("bottom")) {
|
||||
cell.setPaddingBottom(cell.getPaddingBottom() + this.utils.parsePxInCmMmPcToPt(value));
|
||||
continue;
|
||||
}
|
||||
if (key.contains("left")) {
|
||||
cell.setPaddingLeft(cell.getPaddingLeft() + this.utils.parsePxInCmMmPcToPt(value));
|
||||
continue;
|
||||
}
|
||||
if (key.contains("right"))
|
||||
cell.setPaddingRight(cell.getPaddingRight() + this.utils.parsePxInCmMmPcToPt(value));
|
||||
continue;
|
||||
}
|
||||
if (key.contains("text-align"))
|
||||
cell.setHorizontalAlignment(CSS.getElementAlignment(value));
|
||||
}
|
||||
cell.setPaddingLeft(cell.getPaddingLeft() + values.getHorBorderSpacing() + values.getBorderWidthLeft());
|
||||
cell.setPaddingRight(cell.getPaddingRight() + values.getBorderWidthRight());
|
||||
cell.setPaddingTop(cell.getPaddingTop() + values.getVerBorderSpacing() + values.getBorderWidthTop());
|
||||
cell.setPaddingBottom(cell.getPaddingBottom() + values.getBorderWidthBottom());
|
||||
}
|
||||
cell.setBorder(0);
|
||||
cell.setCellEvent(new CellSpacingEvent(values));
|
||||
cell.setCellValues(values);
|
||||
return cell;
|
||||
}
|
||||
|
||||
private void setTopOfBorder(HtmlCell cell, String key, String value, TableStyleValues values) {
|
||||
if (key.contains("width"))
|
||||
values.setBorderWidthTop(this.utils.parsePxInCmMmPcToPt(value));
|
||||
if (key.contains("color")) {
|
||||
values.setBorderColorTop(HtmlUtilities.decodeColor(value));
|
||||
} else if (values.getBorderColorTop() == null) {
|
||||
values.setBorderColorTop(BaseColor.BLACK);
|
||||
}
|
||||
if (key.contains("style"))
|
||||
if (values.getBorderWidthTop(false) == null)
|
||||
values.setBorderWidthTop(2.25F);
|
||||
}
|
||||
|
||||
private void setBottomOfBorder(HtmlCell cell, String key, String value, TableStyleValues values) {
|
||||
if (key.contains("width"))
|
||||
values.setBorderWidthBottom(this.utils.parsePxInCmMmPcToPt(value));
|
||||
if (key.contains("color")) {
|
||||
values.setBorderColorBottom(HtmlUtilities.decodeColor(value));
|
||||
} else if (values.getBorderColorBottom() == null) {
|
||||
values.setBorderColorBottom(BaseColor.BLACK);
|
||||
}
|
||||
if (key.contains("style"))
|
||||
if (values.getBorderWidthBottom(false) == null)
|
||||
values.setBorderWidthBottom(2.25F);
|
||||
}
|
||||
|
||||
private void setLeftOfBorder(HtmlCell cell, String key, String value, TableStyleValues values) {
|
||||
if (key.contains("width"))
|
||||
values.setBorderWidthLeft(this.utils.parsePxInCmMmPcToPt(value));
|
||||
if (key.contains("color")) {
|
||||
values.setBorderColorLeft(HtmlUtilities.decodeColor(value));
|
||||
} else if (values.getBorderColorLeft() == null) {
|
||||
values.setBorderColorLeft(BaseColor.BLACK);
|
||||
}
|
||||
if (key.contains("style"))
|
||||
if (values.getBorderWidthLeft(false) == null)
|
||||
values.setBorderWidthLeft(2.25F);
|
||||
}
|
||||
|
||||
private void setRightOfBorder(HtmlCell cell, String key, String value, TableStyleValues values) {
|
||||
if (key.contains("width"))
|
||||
values.setBorderWidthRight(this.utils.parsePxInCmMmPcToPt(value));
|
||||
if (key.contains("color")) {
|
||||
values.setBorderColorRight(HtmlUtilities.decodeColor(value));
|
||||
} else if (values.getBorderColorRight() == null) {
|
||||
values.setBorderColorRight(BaseColor.BLACK);
|
||||
}
|
||||
if (key.contains("style"))
|
||||
if (values.getBorderWidthRight(false) == null)
|
||||
values.setBorderWidthRight(2.25F);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
package com.itextpdf.tool.xml.css.apply;
|
||||
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.text.Image;
|
||||
import com.itextpdf.text.html.HtmlUtilities;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.css.CssUtils;
|
||||
import com.itextpdf.tool.xml.html.CssApplier;
|
||||
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
|
||||
import java.util.Map;
|
||||
|
||||
public class ImageCssApplier implements CssApplier<Image> {
|
||||
public Image apply(Image img, Tag tag) {
|
||||
return apply(img, tag, null, null, null);
|
||||
}
|
||||
|
||||
public Image apply(Image img, Tag tag, MarginMemory mm, PageSizeContainable psc, HtmlPipelineContext ctx) {
|
||||
Map<String, String> cssMap = tag.getCSS();
|
||||
String widthValue = cssMap.get("width");
|
||||
if (widthValue == null)
|
||||
widthValue = tag.getAttributes().get("width");
|
||||
String heightValue = cssMap.get("height");
|
||||
if (heightValue == null)
|
||||
heightValue = tag.getAttributes().get("height");
|
||||
if (widthValue == null) {
|
||||
img.setScaleToFitLineWhenOverflow(true);
|
||||
} else {
|
||||
img.setScaleToFitLineWhenOverflow(false);
|
||||
}
|
||||
img.setScaleToFitHeight(false);
|
||||
CssUtils utils = CssUtils.getInstance();
|
||||
float widthInPoints = utils.parsePxInCmMmPcToPt(widthValue);
|
||||
float heightInPoints = utils.parsePxInCmMmPcToPt(heightValue);
|
||||
if (widthInPoints > 0.0F && heightInPoints > 0.0F) {
|
||||
img.scaleAbsolute(widthInPoints, heightInPoints);
|
||||
} else if (widthInPoints > 0.0F) {
|
||||
heightInPoints = img.getHeight() * widthInPoints / img.getWidth();
|
||||
img.scaleAbsolute(widthInPoints, heightInPoints);
|
||||
} else if (heightInPoints > 0.0F) {
|
||||
widthInPoints = img.getWidth() * heightInPoints / img.getHeight();
|
||||
img.scaleAbsolute(widthInPoints, heightInPoints);
|
||||
}
|
||||
String borderTopColor = cssMap.get("border-top-color");
|
||||
if (borderTopColor != null)
|
||||
img.setBorderColorTop(HtmlUtilities.decodeColor(borderTopColor));
|
||||
String borderTopWidth = cssMap.get("border-top-width");
|
||||
if (borderTopWidth != null)
|
||||
img.setBorderWidthTop(utils.parseValueToPt(borderTopWidth, 1.0F));
|
||||
String borderRightColor = cssMap.get("border-right-color");
|
||||
if (borderRightColor != null)
|
||||
img.setBorderColorRight(HtmlUtilities.decodeColor(borderRightColor));
|
||||
String borderRightWidth = cssMap.get("border-right-width");
|
||||
if (borderRightWidth != null)
|
||||
img.setBorderWidthRight(utils.parseValueToPt(borderRightWidth, 1.0F));
|
||||
String borderBottomColor = cssMap.get("border-bottom-color");
|
||||
if (borderBottomColor != null)
|
||||
img.setBorderColorBottom(HtmlUtilities.decodeColor(borderBottomColor));
|
||||
String borderBottomWidth = cssMap.get("border-bottom-width");
|
||||
if (borderBottomWidth != null)
|
||||
img.setBorderWidthBottom(utils.parseValueToPt(borderBottomWidth, 1.0F));
|
||||
String borderLeftColor = cssMap.get("border-left-color");
|
||||
if (borderLeftColor != null)
|
||||
img.setBorderColorLeft(HtmlUtilities.decodeColor(borderLeftColor));
|
||||
String borderLeftWidth = cssMap.get("border-left-width");
|
||||
if (borderLeftWidth != null)
|
||||
img.setBorderWidthLeft(utils.parseValueToPt(borderLeftWidth, 1.0F));
|
||||
String before = cssMap.get("before");
|
||||
if (before != null)
|
||||
img.setSpacingBefore(Float.parseFloat(before));
|
||||
String after = cssMap.get("after");
|
||||
if (after != null)
|
||||
img.setSpacingAfter(Float.parseFloat(after));
|
||||
img.setWidthPercentage(0.0F);
|
||||
return img;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
package com.itextpdf.tool.xml.css.apply;
|
||||
|
||||
import com.itextpdf.text.BaseColor;
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.text.html.HtmlUtilities;
|
||||
import com.itextpdf.text.pdf.draw.LineSeparator;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.css.CssUtils;
|
||||
import com.itextpdf.tool.xml.html.CssApplier;
|
||||
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
|
||||
import java.util.Map;
|
||||
|
||||
public class LineSeparatorCssApplier implements CssApplier<LineSeparator> {
|
||||
public LineSeparator apply(LineSeparator ls, Tag t, PageSizeContainable psc) {
|
||||
return apply(ls, t, null, psc, null);
|
||||
}
|
||||
|
||||
public LineSeparator apply(LineSeparator ls, Tag t, MarginMemory mm, PageSizeContainable psc, HtmlPipelineContext ctx) {
|
||||
float lineWidth = 1.0F;
|
||||
Map<String, String> css = t.getCSS();
|
||||
if (t.getAttributes().get("size") != null) {
|
||||
lineWidth = CssUtils.getInstance().parsePxInCmMmPcToPt(t.getAttributes().get("size"));
|
||||
} else if (css.get("height") != null) {
|
||||
lineWidth = CssUtils.getInstance().parsePxInCmMmPcToPt(css.get("height"));
|
||||
}
|
||||
ls.setLineWidth(lineWidth);
|
||||
BaseColor lineColor = BaseColor.BLACK;
|
||||
if (t.getAttributes().get("color") != null) {
|
||||
lineColor = HtmlUtilities.decodeColor(t.getAttributes().get("color"));
|
||||
} else if (css.get("color") != null) {
|
||||
lineColor = HtmlUtilities.decodeColor(css.get("color"));
|
||||
} else if (css.get("background-color") != null) {
|
||||
lineColor = HtmlUtilities.decodeColor(css.get("background-color"));
|
||||
}
|
||||
ls.setLineColor(lineColor);
|
||||
float percentage = 100.0F;
|
||||
String widthStr = css.get("width");
|
||||
if (widthStr == null)
|
||||
widthStr = t.getAttributes().get("width");
|
||||
if (widthStr != null)
|
||||
if (widthStr.contains("%")) {
|
||||
percentage = Float.parseFloat(widthStr.replace("%", ""));
|
||||
} else {
|
||||
percentage = CssUtils.getInstance().parsePxInCmMmPcToPt(widthStr) / psc.getPageSize().getWidth() * 100.0F;
|
||||
}
|
||||
ls.setPercentage(percentage);
|
||||
String align = t.getAttributes().get("align");
|
||||
if ("right".equals(align)) {
|
||||
ls.setAlignment(2);
|
||||
} else if ("left".equals(align)) {
|
||||
ls.setAlignment(0);
|
||||
} else if ("center".equals(align)) {
|
||||
ls.setAlignment(1);
|
||||
}
|
||||
return ls;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
package com.itextpdf.tool.xml.css.apply;
|
||||
|
||||
import com.itextpdf.text.BaseColor;
|
||||
import com.itextpdf.text.Chunk;
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.text.Font;
|
||||
import com.itextpdf.text.GreekList;
|
||||
import com.itextpdf.text.Image;
|
||||
import com.itextpdf.text.List;
|
||||
import com.itextpdf.text.RomanList;
|
||||
import com.itextpdf.text.ZapfDingbatsList;
|
||||
import com.itextpdf.text.html.HtmlUtilities;
|
||||
import com.itextpdf.text.log.Level;
|
||||
import com.itextpdf.text.log.Logger;
|
||||
import com.itextpdf.text.log.LoggerFactory;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.css.CssUtils;
|
||||
import com.itextpdf.tool.xml.css.FontSizeTranslator;
|
||||
import com.itextpdf.tool.xml.exceptions.LocaleMessages;
|
||||
import com.itextpdf.tool.xml.html.CssApplier;
|
||||
import com.itextpdf.tool.xml.net.ImageRetrieve;
|
||||
import com.itextpdf.tool.xml.net.exc.NoImageException;
|
||||
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
|
||||
import java.util.Map;
|
||||
|
||||
public class ListStyleTypeCssApplier implements CssApplier<List> {
|
||||
private final CssUtils utils = CssUtils.getInstance();
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ListStyleTypeCssApplier.class);
|
||||
|
||||
public List apply(List list, Tag t, HtmlPipelineContext context) {
|
||||
return apply(list, t, null, null, context);
|
||||
}
|
||||
|
||||
public List apply(List list, Tag t, MarginMemory memory, PageSizeContainable psc, HtmlPipelineContext context) {
|
||||
float fontSize = FontSizeTranslator.getInstance().getFontSize(t);
|
||||
List lst = list;
|
||||
Map<String, String> css = t.getCSS();
|
||||
String styleType = css.get("list-style-type");
|
||||
BaseColor color = HtmlUtilities.decodeColor(css.get("color"));
|
||||
if (null == color)
|
||||
color = BaseColor.BLACK;
|
||||
if (null != styleType) {
|
||||
if (styleType.equalsIgnoreCase("none")) {
|
||||
lst.setLettered(false);
|
||||
lst.setNumbered(false);
|
||||
lst.setListSymbol("");
|
||||
} else if ("decimal".equalsIgnoreCase(styleType)) {
|
||||
lst = new List(true);
|
||||
} else if ("disc".equalsIgnoreCase(styleType)) {
|
||||
ZapfDingbatsList zapfDingbatsList = new ZapfDingbatsList(108);
|
||||
zapfDingbatsList.setAutoindent(false);
|
||||
zapfDingbatsList.setSymbolIndent(7.75F);
|
||||
Chunk symbol = zapfDingbatsList.getSymbol();
|
||||
symbol.setTextRise(1.5F);
|
||||
Font font = symbol.getFont();
|
||||
font.setSize(4.5F);
|
||||
font.setColor(color);
|
||||
} else if ("square".equalsIgnoreCase(styleType)) {
|
||||
ZapfDingbatsList zapfDingbatsList = new ZapfDingbatsList(110);
|
||||
shrinkSymbol((List)zapfDingbatsList, fontSize, color);
|
||||
} else if ("circle".equalsIgnoreCase(styleType)) {
|
||||
ZapfDingbatsList zapfDingbatsList = new ZapfDingbatsList(109);
|
||||
zapfDingbatsList.setAutoindent(false);
|
||||
zapfDingbatsList.setSymbolIndent(7.75F);
|
||||
Chunk symbol = zapfDingbatsList.getSymbol();
|
||||
symbol.setTextRise(1.5F);
|
||||
Font font = symbol.getFont();
|
||||
font.setSize(4.5F);
|
||||
} else if ("lower-roman".equals(styleType)) {
|
||||
RomanList romanList = new RomanList(true, 0);
|
||||
synchronizeSymbol(fontSize, (List)romanList, color);
|
||||
romanList.setAutoindent(true);
|
||||
} else if ("upper-roman".equals(styleType)) {
|
||||
RomanList romanList = new RomanList(false, 0);
|
||||
romanList.setAutoindent(true);
|
||||
synchronizeSymbol(fontSize, (List)romanList, color);
|
||||
} else if ("lower-greek".equals(styleType)) {
|
||||
GreekList greekList = new GreekList(true, 0);
|
||||
synchronizeSymbol(fontSize, (List)greekList, color);
|
||||
greekList.setAutoindent(true);
|
||||
} else if ("upper-greek".equals(styleType)) {
|
||||
GreekList greekList = new GreekList(false, 0);
|
||||
synchronizeSymbol(fontSize, (List)greekList, color);
|
||||
greekList.setAutoindent(true);
|
||||
} else if ("lower-alpha".equals(styleType) || "lower-latin".equals(styleType)) {
|
||||
lst = new List(true, true);
|
||||
synchronizeSymbol(fontSize, lst, color);
|
||||
lst.setLowercase(true);
|
||||
lst.setAutoindent(true);
|
||||
} else if ("upper-alpha".equals(styleType) || "upper-latin".equals(styleType)) {
|
||||
lst = new List(true, true);
|
||||
synchronizeSymbol(fontSize, lst, color);
|
||||
lst.setLowercase(false);
|
||||
lst.setAutoindent(true);
|
||||
}
|
||||
} else if (t.getName().equalsIgnoreCase("ol")) {
|
||||
lst = new List(true);
|
||||
String type = t.getAttributes().get("type");
|
||||
if (type != null)
|
||||
if (type.equals("A")) {
|
||||
lst.setLettered(true);
|
||||
} else if (type.equals("a")) {
|
||||
lst.setLettered(true);
|
||||
lst.setLowercase(true);
|
||||
}
|
||||
synchronizeSymbol(fontSize, lst, color);
|
||||
lst.setAutoindent(true);
|
||||
} else if (t.getName().equalsIgnoreCase("ul")) {
|
||||
lst = new List(false);
|
||||
shrinkSymbol(lst, fontSize, color);
|
||||
}
|
||||
if (null != css.get("list-style-image") &&
|
||||
!css.get("list-style-image").equalsIgnoreCase("none")) {
|
||||
lst = new List();
|
||||
String url = this.utils.extractUrl(css.get("list-style-image"));
|
||||
try {
|
||||
Image img = new ImageRetrieve(context.getResourcesRootPath(), context.getImageProvider()).retrieveImage(url);
|
||||
lst.setListSymbol(new Chunk(img, 0.0F, 0.0F, false));
|
||||
lst.setSymbolIndent(img.getWidth());
|
||||
if (LOG.isLogging(Level.TRACE))
|
||||
LOG.trace(String.format(LocaleMessages.getInstance().getMessage("html.tag.list"), url));
|
||||
} catch (NoImageException e) {
|
||||
if (LOG.isLogging(Level.ERROR))
|
||||
LOG.error(String.format(LocaleMessages.getInstance().getMessage("html.tag.img.failed"), url), e);
|
||||
lst = new List(false);
|
||||
}
|
||||
lst.setAutoindent(false);
|
||||
}
|
||||
lst.setAlignindent(false);
|
||||
float leftIndent = 0.0F;
|
||||
if (null != css.get("list-style-position") && css.get("list-style-position").equalsIgnoreCase("inside")) {
|
||||
leftIndent += 30.0F;
|
||||
} else {
|
||||
leftIndent += 15.0F;
|
||||
}
|
||||
leftIndent += (css.get("margin-left") != null) ? this.utils.parseValueToPt(css.get("margin-left"), fontSize) : 0.0F;
|
||||
leftIndent += (css.get("padding-left") != null) ? this.utils.parseValueToPt(css.get("padding-left"), fontSize) : 0.0F;
|
||||
lst.setIndentationLeft(leftIndent);
|
||||
String startAtr = t.getAttributes().get("start");
|
||||
if (startAtr != null)
|
||||
try {
|
||||
int start = Integer.parseInt(startAtr);
|
||||
lst.setFirst(start);
|
||||
} catch (NumberFormatException e) {}
|
||||
return lst;
|
||||
}
|
||||
|
||||
private void synchronizeSymbol(float fontSize, List lst, BaseColor color) {
|
||||
Font font = lst.getSymbol().getFont();
|
||||
font.setSize(fontSize);
|
||||
font.setColor(color);
|
||||
lst.setSymbolIndent(fontSize);
|
||||
}
|
||||
|
||||
private void shrinkSymbol(List lst, float fontSize, BaseColor color) {
|
||||
lst.setSymbolIndent(12.0F);
|
||||
Chunk symbol = lst.getSymbol();
|
||||
Font font = symbol.getFont();
|
||||
font.setSize(fontSize);
|
||||
font.setColor(color);
|
||||
}
|
||||
|
||||
public Element apply(List e, Tag t) {
|
||||
return (Element)apply(e, t, null, null, null);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.itextpdf.tool.xml.css.apply;
|
||||
|
||||
import com.itextpdf.tool.xml.exceptions.NoDataException;
|
||||
import java.util.List;
|
||||
|
||||
public interface MarginMemory {
|
||||
Float getLastMarginBottom() throws NoDataException;
|
||||
|
||||
List<String> getRootTags();
|
||||
|
||||
void setLastMarginBottom(Float paramFloat);
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
package com.itextpdf.tool.xml.css.apply;
|
||||
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.css.CssUtils;
|
||||
import com.itextpdf.tool.xml.css.FontSizeTranslator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public final class MaxLeadingAndSize {
|
||||
private final CssUtils utils = CssUtils.getInstance();
|
||||
|
||||
private final FontSizeTranslator fontSizeTranslator = FontSizeTranslator.getInstance();
|
||||
|
||||
private float largestLeading;
|
||||
|
||||
private float largestFont;
|
||||
|
||||
public float getLargestLeading() {
|
||||
return this.largestLeading;
|
||||
}
|
||||
|
||||
public float getLargestFont() {
|
||||
return this.largestFont;
|
||||
}
|
||||
|
||||
public void setVariablesBasedOnChildren(Tag t) {
|
||||
float fontSizeParent = this.fontSizeTranslator.getFontSize(t);
|
||||
float largestFontChildren = getLargestFontFromChildren(t.getChildren());
|
||||
this.largestFont = (fontSizeParent > largestFontChildren) ? fontSizeParent : largestFontChildren;
|
||||
float leadingParent = calculateLeading(t);
|
||||
float largestLeadingChildren = getLargestLeadingFromChildren(t.getChildren());
|
||||
this.largestLeading = (leadingParent > largestLeadingChildren) ? leadingParent : largestLeadingChildren;
|
||||
}
|
||||
|
||||
public void setLeading(Tag tag) {
|
||||
this.largestLeading = calculateLeading(tag);
|
||||
}
|
||||
|
||||
public float getLargestFontFromChildren(List<Tag> children) {
|
||||
float largestFont = 12.0F;
|
||||
for (Tag tag : children) {
|
||||
float fontSize = this.fontSizeTranslator.getFontSize(tag);
|
||||
if (fontSize > largestFont)
|
||||
largestFont = fontSize;
|
||||
}
|
||||
return largestFont;
|
||||
}
|
||||
|
||||
private float getLargestLeadingFromChildren(List<Tag> children) {
|
||||
float leading = 0.0F;
|
||||
for (Tag tag : children) {
|
||||
Float calculatedLineHeight = calculateLeading(tag);
|
||||
if (calculatedLineHeight > leading)
|
||||
leading = calculatedLineHeight;
|
||||
getLargestLeadingFromChildren(tag.getChildren());
|
||||
}
|
||||
return leading;
|
||||
}
|
||||
|
||||
public Float calculateLeading(Tag t) {
|
||||
float leading = 0.0F;
|
||||
Map<String, String> css = t.getCSS();
|
||||
float fontSize = this.fontSizeTranslator.getFontSize(t);
|
||||
if (css.get("line-height") != null) {
|
||||
String value = css.get("line-height");
|
||||
if (this.utils.isNumericValue(value)) {
|
||||
leading = Float.parseFloat(value) * fontSize;
|
||||
} else if (this.utils.isRelativeValue(value)) {
|
||||
leading = this.utils.parseRelativeValue(value, fontSize);
|
||||
} else if (this.utils.isMetricValue(value)) {
|
||||
leading = this.utils.parsePxInCmMmPcToPt(value);
|
||||
}
|
||||
if (leading == 0.0F)
|
||||
leading = fontSize * 1.5F;
|
||||
} else {
|
||||
leading = fontSize * 1.5F;
|
||||
}
|
||||
return leading;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
package com.itextpdf.tool.xml.css.apply;
|
||||
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.css.CSS;
|
||||
import com.itextpdf.tool.xml.css.CssUtils;
|
||||
import com.itextpdf.tool.xml.css.FontSizeTranslator;
|
||||
import com.itextpdf.tool.xml.html.CssApplier;
|
||||
import com.itextpdf.tool.xml.html.pdfelement.NoNewLineParagraph;
|
||||
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
|
||||
import java.util.Map;
|
||||
|
||||
public class NoNewLineParagraphCssApplier implements CssApplier<NoNewLineParagraph> {
|
||||
private final CssUtils utils = CssUtils.getInstance();
|
||||
|
||||
public NoNewLineParagraph apply(NoNewLineParagraph p, Tag t, MarginMemory configuration) {
|
||||
return apply(p, t, configuration, null, null);
|
||||
}
|
||||
|
||||
public NoNewLineParagraph apply(NoNewLineParagraph p, Tag t, MarginMemory configuration, PageSizeContainable psc, HtmlPipelineContext ctx) {
|
||||
float fontSize = FontSizeTranslator.getInstance().getFontSize(t);
|
||||
float lmb = 0.0F;
|
||||
boolean hasLMB = false;
|
||||
Map<String, String> css = t.getCSS();
|
||||
for (Map.Entry<String, String> entry : css.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
if ("margin-top".equalsIgnoreCase(key)) {
|
||||
p.setSpacingBefore(p.getSpacingBefore() + this.utils.calculateMarginTop(value, fontSize, configuration));
|
||||
continue;
|
||||
}
|
||||
if ("padding-top".equalsIgnoreCase(key)) {
|
||||
p.setSpacingBefore(p.getSpacingBefore() + this.utils.parseValueToPt(value, fontSize));
|
||||
continue;
|
||||
}
|
||||
if ("margin-bottom".equalsIgnoreCase(key)) {
|
||||
float after = this.utils.parseValueToPt(value, fontSize);
|
||||
p.setSpacingAfter(p.getSpacingAfter() + after);
|
||||
lmb = after;
|
||||
hasLMB = true;
|
||||
continue;
|
||||
}
|
||||
if ("padding-bottom".equalsIgnoreCase(key)) {
|
||||
p.setSpacingAfter(p.getSpacingAfter() + this.utils.parseValueToPt(value, fontSize));
|
||||
continue;
|
||||
}
|
||||
if ("margin-left".equalsIgnoreCase(key)) {
|
||||
p.setIndentationLeft(p.getIndentationLeft() + this.utils.parseValueToPt(value, fontSize));
|
||||
continue;
|
||||
}
|
||||
if ("margin-right".equalsIgnoreCase(key)) {
|
||||
p.setIndentationRight(p.getIndentationRight() + this.utils.parseValueToPt(value, fontSize));
|
||||
continue;
|
||||
}
|
||||
if ("padding-left".equalsIgnoreCase(key)) {
|
||||
p.setIndentationLeft(p.getIndentationLeft() + this.utils.parseValueToPt(value, fontSize));
|
||||
continue;
|
||||
}
|
||||
if ("padding-right".equalsIgnoreCase(key)) {
|
||||
p.setIndentationRight(p.getIndentationRight() + this.utils.parseValueToPt(value, fontSize));
|
||||
continue;
|
||||
}
|
||||
if ("text-align".equalsIgnoreCase(key)) {
|
||||
p.setAlignment(CSS.getElementAlignment(value));
|
||||
continue;
|
||||
}
|
||||
if ("text-indent".equalsIgnoreCase(key))
|
||||
p.setFirstLineIndent(this.utils.parseValueToPt(value, fontSize));
|
||||
}
|
||||
if (null != t.getParent()) {
|
||||
String parent = t.getParent().getName();
|
||||
if (css.get("margin-top") == null && configuration.getRootTags().contains(parent))
|
||||
p.setSpacingBefore(p.getSpacingBefore() + this.utils.calculateMarginTop(fontSize + "pt", 0.0F, configuration));
|
||||
if (css.get("margin-bottom") == null && configuration.getRootTags().contains(parent)) {
|
||||
p.setSpacingAfter(p.getSpacingAfter() + fontSize);
|
||||
css.put("margin-bottom", fontSize + "pt");
|
||||
lmb = fontSize;
|
||||
hasLMB = true;
|
||||
}
|
||||
if (p.getAlignment() == -1)
|
||||
p.setAlignment(0);
|
||||
}
|
||||
if (hasLMB)
|
||||
configuration.setLastMarginBottom(Float.valueOf(lmb));
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package com.itextpdf.tool.xml.css.apply;
|
||||
|
||||
import com.itextpdf.text.Rectangle;
|
||||
|
||||
public interface PageSizeContainable {
|
||||
Rectangle getPageSize();
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
package com.itextpdf.tool.xml.css.apply;
|
||||
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.text.Font;
|
||||
import com.itextpdf.text.Paragraph;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.css.CSS;
|
||||
import com.itextpdf.tool.xml.css.CssUtils;
|
||||
import com.itextpdf.tool.xml.css.FontSizeTranslator;
|
||||
import com.itextpdf.tool.xml.html.CssApplier;
|
||||
import com.itextpdf.tool.xml.html.CssAppliers;
|
||||
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
|
||||
import java.util.Map;
|
||||
|
||||
public class ParagraphCssApplier implements CssApplier<Paragraph> {
|
||||
private final CssAppliers appliers;
|
||||
|
||||
public ParagraphCssApplier(CssAppliers appliers) {
|
||||
this.appliers = appliers;
|
||||
}
|
||||
|
||||
public Paragraph apply(Paragraph p, Tag t, MarginMemory configuration) {
|
||||
return apply(p, t, configuration, null, null);
|
||||
}
|
||||
|
||||
public Paragraph apply(Paragraph p, Tag t, MarginMemory configuration, PageSizeContainable psc, HtmlPipelineContext ctx) {
|
||||
CssUtils utils = CssUtils.getInstance();
|
||||
float fontSize = FontSizeTranslator.getInstance().getFontSize(t);
|
||||
if (fontSize == -1.0F)
|
||||
fontSize = 0.0F;
|
||||
float lmb = 0.0F;
|
||||
boolean hasLMB = false;
|
||||
Map<String, String> css = t.getCSS();
|
||||
for (Map.Entry<String, String> entry : css.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
if ("margin-top".equalsIgnoreCase(key)) {
|
||||
p.setSpacingBefore(p.getSpacingBefore() + utils.calculateMarginTop(value, fontSize, configuration));
|
||||
continue;
|
||||
}
|
||||
if ("padding-top".equalsIgnoreCase(key)) {
|
||||
p.setSpacingBefore(p.getSpacingBefore() + utils.parseValueToPt(value, fontSize));
|
||||
p.setPaddingTop(utils.parseValueToPt(value, fontSize));
|
||||
continue;
|
||||
}
|
||||
if ("margin-bottom".equalsIgnoreCase(key)) {
|
||||
float after = utils.parseValueToPt(value, fontSize);
|
||||
p.setSpacingAfter(p.getSpacingAfter() + after);
|
||||
lmb = after;
|
||||
hasLMB = true;
|
||||
continue;
|
||||
}
|
||||
if ("padding-bottom".equalsIgnoreCase(key)) {
|
||||
p.setSpacingAfter(p.getSpacingAfter() + utils.parseValueToPt(value, fontSize));
|
||||
continue;
|
||||
}
|
||||
if ("margin-left".equalsIgnoreCase(key)) {
|
||||
p.setIndentationLeft(p.getIndentationLeft() + utils.parseValueToPt(value, fontSize));
|
||||
continue;
|
||||
}
|
||||
if ("margin-right".equalsIgnoreCase(key)) {
|
||||
p.setIndentationRight(p.getIndentationRight() + utils.parseValueToPt(value, fontSize));
|
||||
continue;
|
||||
}
|
||||
if ("padding-left".equalsIgnoreCase(key)) {
|
||||
p.setIndentationLeft(p.getIndentationLeft() + utils.parseValueToPt(value, fontSize));
|
||||
continue;
|
||||
}
|
||||
if ("padding-right".equalsIgnoreCase(key)) {
|
||||
p.setIndentationRight(p.getIndentationRight() + utils.parseValueToPt(value, fontSize));
|
||||
continue;
|
||||
}
|
||||
if ("text-align".equalsIgnoreCase(key)) {
|
||||
p.setAlignment(CSS.getElementAlignment(value));
|
||||
continue;
|
||||
}
|
||||
if ("text-indent".equalsIgnoreCase(key)) {
|
||||
p.setFirstLineIndent(utils.parseValueToPt(value, fontSize));
|
||||
continue;
|
||||
}
|
||||
if ("line-height".equalsIgnoreCase(key)) {
|
||||
if (utils.isNumericValue(value)) {
|
||||
p.setLeading(Float.parseFloat(value) * fontSize);
|
||||
continue;
|
||||
}
|
||||
if (utils.isRelativeValue(value)) {
|
||||
p.setLeading(utils.parseRelativeValue(value, fontSize));
|
||||
continue;
|
||||
}
|
||||
if (utils.isMetricValue(value))
|
||||
p.setLeading(utils.parsePxInCmMmPcToPt(value));
|
||||
}
|
||||
}
|
||||
if (t.getAttributes().containsKey("align")) {
|
||||
String value = t.getAttributes().get("align");
|
||||
if (value != null)
|
||||
p.setAlignment(CSS.getElementAlignment(value));
|
||||
}
|
||||
if (hasLMB)
|
||||
configuration.setLastMarginBottom(Float.valueOf(lmb));
|
||||
Font font = this.appliers.getChunkCssAplier().applyFontStyles(t);
|
||||
p.setFont(font);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,294 @@
|
|||
package com.itextpdf.tool.xml.css.parser;
|
||||
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.css.CssSelectorItem;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class CssSelectorParser {
|
||||
private static final String selectorPatternString = "(\\*)|([_a-zA-Z][\\w-]*)|(\\.[_a-zA-Z][\\w-]*)|(#[_a-z][\\w-]*)|(\\[[_a-zA-Z][\\w-]*(([~^$*|])?=((\"[\\w-]+\")|([\\w-]+)))?\\])|(:[\\w()-]*)|( )|(\\+)|(>)|(~)";
|
||||
|
||||
private static final Pattern selectorPattern = Pattern.compile("(\\*)|([_a-zA-Z][\\w-]*)|(\\.[_a-zA-Z][\\w-]*)|(#[_a-z][\\w-]*)|(\\[[_a-zA-Z][\\w-]*(([~^$*|])?=((\"[\\w-]+\")|([\\w-]+)))?\\])|(:[\\w()-]*)|( )|(\\+)|(>)|(~)");
|
||||
|
||||
private static final int a = 65536;
|
||||
|
||||
private static final int b = 256;
|
||||
|
||||
private static final int c = 1;
|
||||
|
||||
public static List<CssSelectorItem> createCssSelector(String selector) {
|
||||
List<CssSelectorItem> cssSelectorItems = new ArrayList<CssSelectorItem>();
|
||||
Matcher itemMatcher = selectorPattern.matcher(selector);
|
||||
boolean isTagSelector = false;
|
||||
int crc = 0;
|
||||
while (itemMatcher.find()) {
|
||||
CssSelectorItem lastItem, currItem;
|
||||
String selectorItem = itemMatcher.group(0);
|
||||
crc += selectorItem.length();
|
||||
switch (selectorItem.charAt(0)) {
|
||||
case '#':
|
||||
cssSelectorItems.add(new CssIdSelector(selectorItem.substring(1)));
|
||||
continue;
|
||||
case '.':
|
||||
cssSelectorItems.add(new CssClassSelector(selectorItem.substring(1)));
|
||||
continue;
|
||||
case '[':
|
||||
cssSelectorItems.add(new CssAttributeSelector(selectorItem));
|
||||
continue;
|
||||
case ':':
|
||||
cssSelectorItems.add(new CssPseudoSelector(selectorItem));
|
||||
continue;
|
||||
case ' ':
|
||||
case '+':
|
||||
case '>':
|
||||
case '~':
|
||||
if (cssSelectorItems.size() == 0)
|
||||
return null;
|
||||
lastItem = cssSelectorItems.get(cssSelectorItems.size() - 1);
|
||||
currItem = new CssSeparatorSelector(selectorItem.charAt(0));
|
||||
if (lastItem instanceof CssSeparatorSelector) {
|
||||
if (selectorItem.charAt(0) == ' ')
|
||||
continue;
|
||||
if (lastItem.getSeparator() == ' ') {
|
||||
cssSelectorItems.set(cssSelectorItems.size() - 1, currItem);
|
||||
continue;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
cssSelectorItems.add(currItem);
|
||||
isTagSelector = false;
|
||||
continue;
|
||||
}
|
||||
if (isTagSelector)
|
||||
return null;
|
||||
isTagSelector = true;
|
||||
cssSelectorItems.add(new CssTagSelector(selectorItem));
|
||||
}
|
||||
if (selector.length() == 0 || selector.length() != crc)
|
||||
return null;
|
||||
return cssSelectorItems;
|
||||
}
|
||||
|
||||
static class CssTagSelector implements CssSelectorItem {
|
||||
private String t;
|
||||
|
||||
private boolean isUniversal;
|
||||
|
||||
CssTagSelector(String t) {
|
||||
this.t = t;
|
||||
this.isUniversal = this.t.equals("*");
|
||||
}
|
||||
|
||||
public boolean matches(Tag t) {
|
||||
return (this.isUniversal || this.t.equals(t.getName()));
|
||||
}
|
||||
|
||||
public char getSeparator() {
|
||||
return '\000';
|
||||
}
|
||||
|
||||
public int getSpecificity() {
|
||||
if (this.isUniversal)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return this.t;
|
||||
}
|
||||
}
|
||||
|
||||
static class CssClassSelector implements CssSelectorItem {
|
||||
private String className;
|
||||
|
||||
CssClassSelector(String className) {
|
||||
this.className = className;
|
||||
}
|
||||
|
||||
public boolean matches(Tag t) {
|
||||
String classAttr = t.getAttributes().get("class");
|
||||
if (classAttr == null || classAttr.length() == 0)
|
||||
return false;
|
||||
String[] classNames = classAttr.split(" ");
|
||||
for (String currClassName : classNames) {
|
||||
if (this.className.equals(currClassName.trim()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public char getSeparator() {
|
||||
return '\000';
|
||||
}
|
||||
|
||||
public int getSpecificity() {
|
||||
return 256;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "." + this.className;
|
||||
}
|
||||
}
|
||||
|
||||
static class CssIdSelector implements CssSelectorItem {
|
||||
private String id;
|
||||
|
||||
CssIdSelector(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public boolean matches(Tag t) {
|
||||
String id = t.getAttributes().get("id");
|
||||
return (id != null && this.id.equals(id.trim()));
|
||||
}
|
||||
|
||||
public char getSeparator() {
|
||||
return '\000';
|
||||
}
|
||||
|
||||
public int getSpecificity() {
|
||||
return 65536;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "#" + this.id;
|
||||
}
|
||||
}
|
||||
|
||||
static class CssAttributeSelector implements CssSelectorItem {
|
||||
private String property;
|
||||
|
||||
private char matchSymbol = '\000';
|
||||
|
||||
private String value = null;
|
||||
|
||||
CssAttributeSelector(String attrSelector) {
|
||||
int indexOfEqual = attrSelector.indexOf('=');
|
||||
if (indexOfEqual == -1) {
|
||||
this.property = attrSelector.substring(1, attrSelector.length() - 1);
|
||||
} else {
|
||||
if (attrSelector.charAt(indexOfEqual + 1) == '"') {
|
||||
this.value = attrSelector.substring(indexOfEqual + 2, attrSelector.length() - 2);
|
||||
} else {
|
||||
this.value = attrSelector.substring(indexOfEqual + 1, attrSelector.length() - 1);
|
||||
}
|
||||
this.matchSymbol = attrSelector.charAt(indexOfEqual - 1);
|
||||
if ("~^$*|".indexOf(this.matchSymbol) == -1) {
|
||||
this.matchSymbol = '\000';
|
||||
this.property = attrSelector.substring(1, indexOfEqual);
|
||||
} else {
|
||||
this.property = attrSelector.substring(1, indexOfEqual - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public char getSeparator() {
|
||||
return '\000';
|
||||
}
|
||||
|
||||
public boolean matches(Tag t) {
|
||||
String pattern;
|
||||
if (t == null)
|
||||
return false;
|
||||
String attrValue = t.getAttributes().get(this.property);
|
||||
if (attrValue == null)
|
||||
return false;
|
||||
if (this.value == null)
|
||||
return true;
|
||||
switch (this.matchSymbol) {
|
||||
case '|':
|
||||
pattern = String.format("^%s-?", this.value);
|
||||
if (Pattern.compile(pattern).matcher(attrValue).find())
|
||||
return true;
|
||||
break;
|
||||
case '^':
|
||||
if (attrValue.startsWith(this.value))
|
||||
return true;
|
||||
break;
|
||||
case '$':
|
||||
if (attrValue.endsWith(this.value))
|
||||
return true;
|
||||
break;
|
||||
case '~':
|
||||
pattern = String.format("(^%s\\s+)|(\\s+%s\\s+)|(\\s+%s$)", this.value, this.value, this.value);
|
||||
if (Pattern.compile(pattern).matcher(attrValue).find())
|
||||
return true;
|
||||
break;
|
||||
case '\000':
|
||||
if (attrValue.equals(this.value))
|
||||
return true;
|
||||
break;
|
||||
case '*':
|
||||
if (attrValue.contains(this.value))
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getSpecificity() {
|
||||
return 256;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append('[').append(this.property);
|
||||
if (this.matchSymbol != '\000')
|
||||
buf.append(this.matchSymbol);
|
||||
if (this.value != null)
|
||||
buf.append('=').append('"').append(this.value).append('"');
|
||||
buf.append(']');
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
||||
static class CssPseudoSelector implements CssSelectorItem {
|
||||
private String selector;
|
||||
|
||||
CssPseudoSelector(String selector) {
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
public boolean matches(Tag t) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public char getSeparator() {
|
||||
return '\000';
|
||||
}
|
||||
|
||||
public int getSpecificity() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return this.selector;
|
||||
}
|
||||
}
|
||||
|
||||
static class CssSeparatorSelector implements CssSelectorItem {
|
||||
private char separator;
|
||||
|
||||
CssSeparatorSelector(char separator) {
|
||||
this.separator = separator;
|
||||
}
|
||||
|
||||
public char getSeparator() {
|
||||
return this.separator;
|
||||
}
|
||||
|
||||
public boolean matches(Tag t) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getSpecificity() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.valueOf(this.separator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
package com.itextpdf.tool.xml.css.parser;
|
||||
|
||||
import com.itextpdf.tool.xml.css.CssFile;
|
||||
import com.itextpdf.tool.xml.css.CssUtils;
|
||||
import com.itextpdf.tool.xml.css.parser.state.CommentEnd;
|
||||
import com.itextpdf.tool.xml.css.parser.state.CommentInside;
|
||||
import com.itextpdf.tool.xml.css.parser.state.CommentStart;
|
||||
import com.itextpdf.tool.xml.css.parser.state.Properties;
|
||||
import com.itextpdf.tool.xml.css.parser.state.Rule;
|
||||
import com.itextpdf.tool.xml.css.parser.state.Unknown;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class CssStateController {
|
||||
private State current;
|
||||
|
||||
private State previous;
|
||||
|
||||
private final State commentEnd;
|
||||
|
||||
private final State commentStart;
|
||||
|
||||
private final State commentInside;
|
||||
|
||||
private final StringBuilder buffer;
|
||||
|
||||
private final State properties;
|
||||
|
||||
private final State unknown;
|
||||
|
||||
private String currentSelector;
|
||||
|
||||
private final State rule;
|
||||
|
||||
private final CssUtils utils;
|
||||
|
||||
private final CssFile css;
|
||||
|
||||
public CssStateController(CssFile file) {
|
||||
this.css = file;
|
||||
this.utils = CssUtils.getInstance();
|
||||
this.buffer = new StringBuilder();
|
||||
this.commentStart = new CommentStart(this);
|
||||
this.commentEnd = new CommentEnd(this);
|
||||
this.commentInside = new CommentInside(this);
|
||||
this.unknown = new Unknown(this);
|
||||
this.properties = new Properties(this);
|
||||
this.rule = new Rule(this);
|
||||
this.current = this.unknown;
|
||||
}
|
||||
|
||||
public void append(char c) {
|
||||
this.buffer.append(c);
|
||||
}
|
||||
|
||||
public void previous() {
|
||||
this.current = this.previous;
|
||||
}
|
||||
|
||||
public void process(char c) {
|
||||
this.current.process(c);
|
||||
}
|
||||
|
||||
private void processProps(String props) {
|
||||
String[] split = props.split(";");
|
||||
Map<String, String> map = new LinkedHashMap<String, String>();
|
||||
for (String prop : split) {
|
||||
String[] propSplit = prop.split(":");
|
||||
if (propSplit.length == 2)
|
||||
map.put(this.utils.stripDoubleSpacesTrimAndToLowerCase(propSplit[0]), this.utils.stripDoubleSpacesAndTrim(propSplit[1]));
|
||||
}
|
||||
if (this.currentSelector.contains(",")) {
|
||||
String[] selectors = this.currentSelector.split(",");
|
||||
for (int i = 0; i < selectors.length; i++) {
|
||||
selectors[i] = this.utils.stripDoubleSpacesAndTrim(selectors[i]);
|
||||
if (selectors[i].length() == 0)
|
||||
return;
|
||||
}
|
||||
for (String selector : selectors) {
|
||||
if (!this.css.add(selector, map))
|
||||
map.clear();
|
||||
}
|
||||
} else {
|
||||
this.css.add(this.utils.stripDoubleSpacesAndTrim(this.currentSelector), map);
|
||||
}
|
||||
}
|
||||
|
||||
private void setState(State state) {
|
||||
this.current = state;
|
||||
}
|
||||
|
||||
private void setPrevious() {
|
||||
this.previous = this.current;
|
||||
}
|
||||
|
||||
public void stateCommentEnd() {
|
||||
setState(this.commentEnd);
|
||||
}
|
||||
|
||||
public void stateCommentInside() {
|
||||
setState(this.commentInside);
|
||||
}
|
||||
|
||||
public void stateCommentStart() {
|
||||
setPrevious();
|
||||
setState(this.commentStart);
|
||||
}
|
||||
|
||||
public void stateProperties() {
|
||||
this.previous = this.current;
|
||||
setState(this.properties);
|
||||
}
|
||||
|
||||
public void stateUnknown() {
|
||||
setState(this.unknown);
|
||||
}
|
||||
|
||||
public void stateRule() {
|
||||
setState(this.rule);
|
||||
}
|
||||
|
||||
public void storeSelector() {
|
||||
this.currentSelector = this.buffer.toString();
|
||||
this.buffer.setLength(0);
|
||||
}
|
||||
|
||||
public void storeProperties() {
|
||||
processProps(this.buffer.toString());
|
||||
this.buffer.setLength(0);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package com.itextpdf.tool.xml.css.parser;
|
||||
|
||||
public interface State {
|
||||
void process(char paramChar);
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.itextpdf.tool.xml.css.parser.state;
|
||||
|
||||
import com.itextpdf.tool.xml.css.parser.CssStateController;
|
||||
import com.itextpdf.tool.xml.css.parser.State;
|
||||
|
||||
public class CommentEnd implements State {
|
||||
private final CssStateController controller;
|
||||
|
||||
public CommentEnd(CssStateController controller) {
|
||||
this.controller = controller;
|
||||
}
|
||||
|
||||
public void process(char c) {
|
||||
if ('/' == c) {
|
||||
this.controller.previous();
|
||||
} else {
|
||||
this.controller.stateCommentInside();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.itextpdf.tool.xml.css.parser.state;
|
||||
|
||||
import com.itextpdf.tool.xml.css.parser.CssStateController;
|
||||
import com.itextpdf.tool.xml.css.parser.State;
|
||||
|
||||
public class CommentInside implements State {
|
||||
private final CssStateController controller;
|
||||
|
||||
public CommentInside(CssStateController cssStateController) {
|
||||
this.controller = cssStateController;
|
||||
}
|
||||
|
||||
public void process(char c) {
|
||||
if ('*' == c)
|
||||
this.controller.stateCommentEnd();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.itextpdf.tool.xml.css.parser.state;
|
||||
|
||||
import com.itextpdf.tool.xml.css.parser.CssStateController;
|
||||
import com.itextpdf.tool.xml.css.parser.State;
|
||||
|
||||
public class CommentStart implements State {
|
||||
private final CssStateController controller;
|
||||
|
||||
public CommentStart(CssStateController controller) {
|
||||
this.controller = controller;
|
||||
}
|
||||
|
||||
public void process(char c) {
|
||||
if ('*' == c) {
|
||||
this.controller.stateCommentInside();
|
||||
} else {
|
||||
this.controller.append('/');
|
||||
this.controller.append(c);
|
||||
this.controller.previous();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.itextpdf.tool.xml.css.parser.state;
|
||||
|
||||
import com.itextpdf.tool.xml.css.parser.CssStateController;
|
||||
import com.itextpdf.tool.xml.css.parser.State;
|
||||
|
||||
public class Properties implements State {
|
||||
private final CssStateController controller;
|
||||
|
||||
public Properties(CssStateController cssStateController) {
|
||||
this.controller = cssStateController;
|
||||
}
|
||||
|
||||
public void process(char c) {
|
||||
if ('}' == c) {
|
||||
this.controller.storeProperties();
|
||||
this.controller.stateUnknown();
|
||||
} else if ('/' == c) {
|
||||
this.controller.stateCommentStart();
|
||||
} else {
|
||||
this.controller.append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package com.itextpdf.tool.xml.css.parser.state;
|
||||
|
||||
import com.itextpdf.tool.xml.css.parser.CssStateController;
|
||||
import com.itextpdf.tool.xml.css.parser.State;
|
||||
|
||||
public class Rule implements State {
|
||||
private final CssStateController controller;
|
||||
|
||||
private boolean isCss3AtRule;
|
||||
|
||||
private int openParenthesesCount = 0;
|
||||
|
||||
public Rule(CssStateController cssStateController) {
|
||||
this.controller = cssStateController;
|
||||
}
|
||||
|
||||
public void process(char c) {
|
||||
if ('}' == c && this.isCss3AtRule) {
|
||||
this.openParenthesesCount--;
|
||||
if (this.openParenthesesCount == 0) {
|
||||
this.controller.stateUnknown();
|
||||
this.isCss3AtRule = false;
|
||||
}
|
||||
} else if (';' == c && !this.isCss3AtRule) {
|
||||
this.controller.stateUnknown();
|
||||
} else if ('{' == c) {
|
||||
this.openParenthesesCount++;
|
||||
this.isCss3AtRule = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.itextpdf.tool.xml.css.parser.state;
|
||||
|
||||
import com.itextpdf.tool.xml.css.parser.CssStateController;
|
||||
import com.itextpdf.tool.xml.css.parser.State;
|
||||
|
||||
public class Unknown implements State {
|
||||
private final CssStateController controller;
|
||||
|
||||
public Unknown(CssStateController cssStateController) {
|
||||
this.controller = cssStateController;
|
||||
}
|
||||
|
||||
public void process(char c) {
|
||||
if ('/' == c) {
|
||||
this.controller.stateCommentStart();
|
||||
} else if ('{' == c) {
|
||||
this.controller.storeSelector();
|
||||
this.controller.stateProperties();
|
||||
} else if ('@' == c) {
|
||||
this.controller.stateRule();
|
||||
} else {
|
||||
this.controller.append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.itextpdf.tool.xml.exceptions;
|
||||
|
||||
public class CssResolverException extends Exception {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public CssResolverException() {}
|
||||
|
||||
public CssResolverException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public CssResolverException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public CssResolverException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
package com.itextpdf.tool.xml.exceptions;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
public class LocaleMessages {
|
||||
public static final String UNSUPPORTED_CHARSET = "unsupported.charset";
|
||||
|
||||
public static final String INVALID_NESTED_TAG = "tag.invalidnesting";
|
||||
|
||||
public static final String NO_CUSTOM_CONTEXT = "customcontext.404";
|
||||
|
||||
public static final String CUSTOMCONTEXT_404_CONTINUE = "customcontext.404.continue";
|
||||
|
||||
public static final String UNSUPPORTED_CLONING = "unsupported.clone";
|
||||
|
||||
public static final String NO_TAGPROCESSOR = "tag.noprocessor";
|
||||
|
||||
public static final String NO_SIBLING = "tag.nosibling";
|
||||
|
||||
public static final String PIPELINE_AUTODOC = "pipeline.autodoc.missingdep";
|
||||
|
||||
public static final String STACK_404 = "pipeline.html.missingstack";
|
||||
|
||||
public static final String OWN_CONTEXT_404 = "pipeline.owncontextmissing";
|
||||
|
||||
public static final String ELEMENT_NOT_ADDED = "pipeline.pdfwriter.elemnotadded";
|
||||
|
||||
public static final String ELEMENT_NOT_ADDED_EXC = "pipeline.pdfwriter.elemnotaddedexc";
|
||||
|
||||
public static final String IMG_SRC_NOTCONVERTED = "exc.img.notconverted";
|
||||
|
||||
public static final String HTML_IMG_USE = "html.tag.img.try";
|
||||
|
||||
public static final String HTML_IMG_RETRIEVE_FAIL = "html.tag.img.failedretrieve";
|
||||
|
||||
public static final String ADD_HEADER = "html.tag.h.create";
|
||||
|
||||
public static final String HEADER_BM_DISABLED = "html.tag.h.disabled";
|
||||
|
||||
public static final String A_LOCALGOTO = "html.tag.a.local";
|
||||
|
||||
public static final String A_EXTERNAL = "html.tag.a.external";
|
||||
|
||||
public static final String A_SETLOCALGOTO = "html.tag.a.setlocal";
|
||||
|
||||
public static final String SPACEHACK = "html.tag.a.spacehack";
|
||||
|
||||
public static final String COLSPAN = "html.tag.table.colspan";
|
||||
|
||||
public static final String LINK_404 = "html.tag.link.404";
|
||||
|
||||
public static final String META_CC = "html.tag.meta.cc";
|
||||
|
||||
public static final String META_404 = "html.tag.meta.404";
|
||||
|
||||
public static final String STYLE_NOTPARSED = "html.tag.style.notparsed";
|
||||
|
||||
private static LocaleMessages myself = new LocaleMessages();
|
||||
|
||||
private final ResourceBundle bundle;
|
||||
|
||||
public static LocaleMessages getInstance() {
|
||||
return myself;
|
||||
}
|
||||
|
||||
public LocaleMessages() {
|
||||
this.bundle = ResourceBundle.getBundle("errors/errors", Locale.getDefault());
|
||||
}
|
||||
|
||||
public LocaleMessages(Locale locale) {
|
||||
this.bundle = ResourceBundle.getBundle("errors/errors", locale);
|
||||
}
|
||||
|
||||
public String getMessage(String key) {
|
||||
return this.bundle.getString(key);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.itextpdf.tool.xml.exceptions;
|
||||
|
||||
public class NoDataException extends Exception {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public NoDataException() {}
|
||||
|
||||
public NoDataException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public NoDataException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public NoDataException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.itextpdf.tool.xml.exceptions;
|
||||
|
||||
public class NoSiblingException extends Exception {
|
||||
private static final long serialVersionUID = 7472419463314328600L;
|
||||
|
||||
public NoSiblingException() {}
|
||||
|
||||
public NoSiblingException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public NoSiblingException(String s, Throwable e) {
|
||||
super(s, e);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.itextpdf.tool.xml.exceptions;
|
||||
|
||||
public class NoTagProcessorException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public NoTagProcessorException(String tag) {
|
||||
super(tag);
|
||||
}
|
||||
|
||||
public NoTagProcessorException(String tag, Exception e) {
|
||||
super(tag, e);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.itextpdf.tool.xml.exceptions;
|
||||
|
||||
public class NotImplementedException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public NotImplementedException() {}
|
||||
|
||||
public NotImplementedException(String arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
|
||||
public NotImplementedException(Throwable arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
|
||||
public NotImplementedException(String arg0, Throwable arg1) {
|
||||
super(arg0, arg1);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.itextpdf.tool.xml.exceptions;
|
||||
|
||||
public class RuntimeWorkerException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public RuntimeWorkerException() {}
|
||||
|
||||
public RuntimeWorkerException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public RuntimeWorkerException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public RuntimeWorkerException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,271 @@
|
|||
package com.itextpdf.tool.xml.html;
|
||||
|
||||
import com.itextpdf.text.Chunk;
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.text.Font;
|
||||
import com.itextpdf.text.Paragraph;
|
||||
import com.itextpdf.text.Phrase;
|
||||
import com.itextpdf.text.api.Indentable;
|
||||
import com.itextpdf.tool.xml.NoCustomContextException;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.WorkerContext;
|
||||
import com.itextpdf.tool.xml.css.FontSizeTranslator;
|
||||
import com.itextpdf.tool.xml.exceptions.LocaleMessages;
|
||||
import com.itextpdf.tool.xml.exceptions.RuntimeWorkerException;
|
||||
import com.itextpdf.tool.xml.html.pdfelement.NoNewLineParagraph;
|
||||
import com.itextpdf.tool.xml.pipeline.css.CSSResolver;
|
||||
import com.itextpdf.tool.xml.pipeline.css.CssResolverPipeline;
|
||||
import com.itextpdf.tool.xml.pipeline.ctx.ObjectContext;
|
||||
import com.itextpdf.tool.xml.pipeline.html.HtmlPipeline;
|
||||
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
|
||||
import com.itextpdf.tool.xml.util.ParentTreeUtil;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public abstract class AbstractTagProcessor implements TagProcessor, CssAppliersAware {
|
||||
private final FontSizeTranslator fontsizeTrans = FontSizeTranslator.getInstance();
|
||||
|
||||
private CssAppliers cssAppliers;
|
||||
|
||||
public CSSResolver getCSSResolver(WorkerContext context) throws NoCustomContextException {
|
||||
return ((ObjectContext<CSSResolver>)context.get(CssResolverPipeline.class.getName())).get();
|
||||
}
|
||||
|
||||
public HtmlPipelineContext getHtmlPipelineContext(WorkerContext context) throws NoCustomContextException {
|
||||
return (HtmlPipelineContext)context.get(HtmlPipeline.class.getName());
|
||||
}
|
||||
|
||||
public final List<Element> startElement(WorkerContext ctx, Tag tag) {
|
||||
float fontSize = this.fontsizeTrans.translateFontSize(tag);
|
||||
if (fontSize != -1.0F)
|
||||
tag.getCSS().put("font-size", fontSize + "pt");
|
||||
String pagebreak = tag.getCSS().get("page-break-before");
|
||||
if (null != pagebreak && "always".equalsIgnoreCase(pagebreak)) {
|
||||
List<Element> list = new ArrayList<Element>(2);
|
||||
list.add(Chunk.NEXTPAGE);
|
||||
list.addAll(start(ctx, tag));
|
||||
return list;
|
||||
}
|
||||
return start(ctx, tag);
|
||||
}
|
||||
|
||||
public List<Element> start(WorkerContext ctx, Tag tag) {
|
||||
return new ArrayList<Element>(0);
|
||||
}
|
||||
|
||||
public List<Element> content(WorkerContext ctx, Tag tag, String content) {
|
||||
return new ArrayList<Element>(0);
|
||||
}
|
||||
|
||||
private Set<String> ignoreDirAttribute = new HashSet<String>() {
|
||||
{
|
||||
add("p");
|
||||
add("span");
|
||||
}
|
||||
};
|
||||
|
||||
private List<Tag> tree;
|
||||
|
||||
private String getParentDirection() {
|
||||
String result = null;
|
||||
for (Tag tag : this.tree) {
|
||||
if (!this.ignoreDirAttribute.contains(tag.getName().toLowerCase())) {
|
||||
result = tag.getAttributes().get("dir");
|
||||
if (result != null)
|
||||
break;
|
||||
result = tag.getCSS().get("direction");
|
||||
if (result != null)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected int getRunDirection(Tag tag) {
|
||||
String dirValue = null;
|
||||
boolean toFetchRunDirFromThisTag = (tag.getName() != null &&
|
||||
!this.ignoreDirAttribute.contains(tag.getName().toLowerCase()));
|
||||
if (toFetchRunDirFromThisTag)
|
||||
dirValue = tag.getAttributes().get("dir");
|
||||
if (dirValue == null) {
|
||||
if (toFetchRunDirFromThisTag)
|
||||
dirValue = tag.getCSS().get("direction");
|
||||
if (dirValue == null) {
|
||||
this.tree = new ParentTreeUtil().getParentTagTree(tag, this.tree);
|
||||
dirValue = getParentDirection();
|
||||
}
|
||||
}
|
||||
if ("rtl".equalsIgnoreCase(dirValue))
|
||||
return 3;
|
||||
if ("ltr".equalsIgnoreCase(dirValue))
|
||||
return 2;
|
||||
if ("auto".equalsIgnoreCase(dirValue))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
protected List<Element> textContent(WorkerContext ctx, Tag tag, String content) {
|
||||
List<Chunk> sanitizedChunks = HTMLUtils.sanitize(content, false);
|
||||
List<Element> l = new ArrayList<Element>(1);
|
||||
for (Chunk sanitized : sanitizedChunks) {
|
||||
try {
|
||||
l.add(getCssAppliers().apply((Element)sanitized, tag, getHtmlPipelineContext(ctx)));
|
||||
} catch (NoCustomContextException e) {
|
||||
throw new RuntimeWorkerException(e);
|
||||
}
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
public final List<Element> endElement(WorkerContext ctx, Tag tag, List<Element> currentContent) {
|
||||
List<Element> list = new ArrayList<Element>();
|
||||
if (currentContent.isEmpty()) {
|
||||
list = end(ctx, tag, currentContent);
|
||||
} else {
|
||||
List<Element> elements = new ArrayList<Element>();
|
||||
for (Element el : currentContent) {
|
||||
if (el instanceof Chunk && ((Chunk)el).hasAttributes() && ((Chunk)el).getAttributes().containsKey("NEWPAGE")) {
|
||||
if (elements.size() > 0) {
|
||||
list.addAll(end(ctx, tag, elements));
|
||||
elements.clear();
|
||||
}
|
||||
list.add(el);
|
||||
continue;
|
||||
}
|
||||
elements.add(el);
|
||||
}
|
||||
if (elements.size() > 0) {
|
||||
list.addAll(end(ctx, tag, elements));
|
||||
elements.clear();
|
||||
}
|
||||
}
|
||||
String pagebreak = tag.getCSS().get("page-break-after");
|
||||
if (null != pagebreak && "always".equalsIgnoreCase(pagebreak))
|
||||
list.add(Chunk.NEXTPAGE);
|
||||
return list;
|
||||
}
|
||||
|
||||
public List<Element> end(WorkerContext ctx, Tag tag, List<Element> currentContent) {
|
||||
return new ArrayList<Element>(currentContent);
|
||||
}
|
||||
|
||||
public boolean isStackOwner() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<Element> currentContentToParagraph(List<Element> currentContent, boolean addNewLines, boolean applyCSS, Tag tag, WorkerContext ctx) {
|
||||
try {
|
||||
int direction = getRunDirection(tag);
|
||||
List<Element> list = new ArrayList<Element>();
|
||||
if (currentContent.size() > 0)
|
||||
if (addNewLines) {
|
||||
Paragraph p = createParagraph();
|
||||
p.setMultipliedLeading(1.2F);
|
||||
for (Element e : currentContent) {
|
||||
if (e instanceof com.itextpdf.text.pdf.draw.LineSeparator)
|
||||
try {
|
||||
HtmlPipelineContext htmlPipelineContext = getHtmlPipelineContext(ctx);
|
||||
Chunk newLine = (Chunk)getCssAppliers().apply(new Chunk(Chunk.NEWLINE), tag, htmlPipelineContext);
|
||||
p.add((Element)newLine);
|
||||
} catch (NoCustomContextException e1) {
|
||||
throw new RuntimeWorkerException(LocaleMessages.getInstance().getMessage("customcontext.404"), e1);
|
||||
}
|
||||
p.add(e);
|
||||
}
|
||||
if (p.trim()) {
|
||||
if (applyCSS)
|
||||
p = (Paragraph)getCssAppliers().apply((Element)p, tag, getHtmlPipelineContext(ctx));
|
||||
if (direction == 3) {
|
||||
doRtlIndentCorrections((Indentable)p);
|
||||
invertTextAlignForParagraph(p);
|
||||
}
|
||||
list.add(p);
|
||||
}
|
||||
} else {
|
||||
NoNewLineParagraph p = new NoNewLineParagraph(Float.NaN);
|
||||
p.setMultipliedLeading(1.2F);
|
||||
for (Element e : currentContent) {
|
||||
updateParagraphFontIfNeeded(p, e);
|
||||
p.add(e);
|
||||
}
|
||||
p = (NoNewLineParagraph)getCssAppliers().apply((Element)p, tag, getHtmlPipelineContext(ctx));
|
||||
if (direction == 3) {
|
||||
doRtlIndentCorrections(p);
|
||||
invertTextAlignForParagraph(p);
|
||||
}
|
||||
list.add(p);
|
||||
}
|
||||
return list;
|
||||
} catch (NoCustomContextException e) {
|
||||
throw new RuntimeWorkerException(LocaleMessages.getInstance().getMessage("customcontext.404"), e);
|
||||
}
|
||||
}
|
||||
|
||||
public final List<Element> currentContentToParagraph(List<Element> currentContent, boolean addNewLines) {
|
||||
return currentContentToParagraph(currentContent, addNewLines, false, null, null);
|
||||
}
|
||||
|
||||
public void setCssAppliers(CssAppliers cssAppliers) {
|
||||
this.cssAppliers = cssAppliers;
|
||||
}
|
||||
|
||||
public CssAppliers getCssAppliers() {
|
||||
return this.cssAppliers;
|
||||
}
|
||||
|
||||
protected Paragraph createParagraph() {
|
||||
return new Paragraph(Float.NaN);
|
||||
}
|
||||
|
||||
protected void doRtlIndentCorrections(Indentable p) {
|
||||
float right = p.getIndentationRight();
|
||||
p.setIndentationRight(p.getIndentationLeft());
|
||||
p.setIndentationLeft(right);
|
||||
}
|
||||
|
||||
protected void invertTextAlignForParagraph(Paragraph p) {
|
||||
switch (p.getAlignment()) {
|
||||
case -1:
|
||||
case 1:
|
||||
case 3:
|
||||
case 8:
|
||||
break;
|
||||
case 2:
|
||||
p.setAlignment(0);
|
||||
break;
|
||||
default:
|
||||
p.setAlignment(2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected void invertTextAlignForParagraph(NoNewLineParagraph p) {
|
||||
switch (p.getAlignment()) {
|
||||
case -1:
|
||||
case 1:
|
||||
case 3:
|
||||
case 8:
|
||||
break;
|
||||
case 2:
|
||||
p.setAlignment(0);
|
||||
break;
|
||||
default:
|
||||
p.setAlignment(2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateParagraphFontIfNeeded(Phrase p, Element child) {
|
||||
Font childFont = null;
|
||||
if (child instanceof Chunk) {
|
||||
childFont = ((Chunk)child).getFont();
|
||||
} else if (child instanceof Phrase) {
|
||||
childFont = ((Phrase)child).getFont();
|
||||
}
|
||||
float pFontSize = (p.getFont() != null) ? p.getFont().getSize() : 12.0F;
|
||||
if (childFont != null && childFont.getSize() > pFontSize)
|
||||
p.setFont(childFont);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
package com.itextpdf.tool.xml.html;
|
||||
|
||||
import com.itextpdf.text.Chunk;
|
||||
import com.itextpdf.text.Document;
|
||||
import com.itextpdf.text.DocumentException;
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.text.Phrase;
|
||||
import com.itextpdf.text.WritableDirectElement;
|
||||
import com.itextpdf.text.log.Level;
|
||||
import com.itextpdf.text.log.Logger;
|
||||
import com.itextpdf.text.log.LoggerFactory;
|
||||
import com.itextpdf.text.pdf.ColumnText;
|
||||
import com.itextpdf.text.pdf.PdfWriter;
|
||||
import com.itextpdf.tool.xml.NoCustomContextException;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.WorkerContext;
|
||||
import com.itextpdf.tool.xml.exceptions.LocaleMessages;
|
||||
import com.itextpdf.tool.xml.exceptions.RuntimeWorkerException;
|
||||
import com.itextpdf.tool.xml.html.pdfelement.NoNewLineParagraph;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Anchor extends AbstractTagProcessor {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(Anchor.class);
|
||||
|
||||
public List<Element> content(WorkerContext ctx, Tag tag, String content) {
|
||||
return textContent(ctx, tag, content);
|
||||
}
|
||||
|
||||
public List<Element> end(WorkerContext ctx, Tag tag, List<Element> currentContent) {
|
||||
try {
|
||||
final String name = tag.getAttributes().get("name");
|
||||
List<Element> elems = new ArrayList<Element>(0);
|
||||
if (currentContent.size() > 0) {
|
||||
NoNewLineParagraph p = new NoNewLineParagraph();
|
||||
String url = tag.getAttributes().get("href");
|
||||
for (Element e : currentContent) {
|
||||
if (e instanceof Chunk)
|
||||
if (null != url) {
|
||||
if (url.startsWith("#")) {
|
||||
if (LOGGER.isLogging(Level.TRACE))
|
||||
LOGGER.trace(String.format(LocaleMessages.getInstance().getMessage("html.tag.a.local"), url));
|
||||
((Chunk)e).setLocalGoto(url.replaceFirst("#", ""));
|
||||
} else {
|
||||
if (null != getHtmlPipelineContext(ctx).getLinkProvider() && !url.startsWith("http")) {
|
||||
String root = getHtmlPipelineContext(ctx).getLinkProvider().getLinkRoot();
|
||||
if (root.endsWith("/") && url.startsWith("/"))
|
||||
root = root.substring(0, root.length() - 1);
|
||||
url = root + url;
|
||||
}
|
||||
if (LOGGER.isLogging(Level.TRACE))
|
||||
LOGGER.trace(String.format(LocaleMessages.getInstance().getMessage("html.tag.a.external"), url));
|
||||
((Chunk)e).setAnchor(url);
|
||||
}
|
||||
} else if (null != name) {
|
||||
((Chunk)e).setLocalDestination(name);
|
||||
if (LOGGER.isLogging(Level.TRACE))
|
||||
LOGGER.trace(String.format(LocaleMessages.getInstance().getMessage("html.tag.a.setlocal"), name));
|
||||
}
|
||||
p.add(e);
|
||||
}
|
||||
elems.add(getCssAppliers().apply((Element)p, tag, getHtmlPipelineContext(ctx)));
|
||||
} else if (null != name) {
|
||||
if (LOGGER.isLogging(Level.TRACE))
|
||||
LOGGER.trace(String.format(LocaleMessages.getInstance().getMessage("html.tag.a.spacehack"), name));
|
||||
elems.add(new WritableDirectElement() {
|
||||
public void write(PdfWriter writer, Document doc) throws DocumentException {
|
||||
ColumnText c = new ColumnText(writer.getDirectContent());
|
||||
float verticalPosition = writer.getVerticalPosition(false);
|
||||
c.setSimpleColumn(new Phrase(new Chunk(" ").setLocalDestination(name)), 1.0F, verticalPosition - 5.0F, 6.0F, verticalPosition, 5.0F, 0);
|
||||
try {
|
||||
c.go();
|
||||
} catch (DocumentException e) {
|
||||
throw new RuntimeWorkerException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return elems;
|
||||
} catch (NoCustomContextException e) {
|
||||
throw new RuntimeWorkerException(LocaleMessages.getInstance().getMessage("customcontext.404"), e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isStackOwner() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
package com.itextpdf.tool.xml.html;
|
||||
|
||||
import com.itextpdf.text.Chunk;
|
||||
import com.itextpdf.text.Document;
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.text.Rectangle;
|
||||
import com.itextpdf.text.html.HtmlUtilities;
|
||||
import com.itextpdf.text.pdf.PdfBody;
|
||||
import com.itextpdf.tool.xml.NoCustomContextException;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.WorkerContext;
|
||||
import com.itextpdf.tool.xml.exceptions.LocaleMessages;
|
||||
import com.itextpdf.tool.xml.exceptions.RuntimeWorkerException;
|
||||
import com.itextpdf.tool.xml.html.pdfelement.NoNewLineParagraph;
|
||||
import com.itextpdf.tool.xml.pipeline.ctx.MapContext;
|
||||
import com.itextpdf.tool.xml.pipeline.end.PdfWriterPipeline;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class Body extends AbstractTagProcessor {
|
||||
public List<Element> content(WorkerContext ctx, Tag tag, String content) {
|
||||
List<Chunk> sanitizedChunks = HTMLUtils.sanitize(content, false);
|
||||
List<Element> l = new ArrayList<Element>(1);
|
||||
NoNewLineParagraph sanitizedNoNewLineParagraph = new NoNewLineParagraph();
|
||||
for (Chunk sanitized : sanitizedChunks) {
|
||||
Chunk c = getCssAppliers().getChunkCssAplier().apply(sanitized, tag);
|
||||
sanitizedNoNewLineParagraph.add((Element)c);
|
||||
}
|
||||
if (sanitizedNoNewLineParagraph.size() > 0)
|
||||
try {
|
||||
l.add(getCssAppliers().apply((Element)sanitizedNoNewLineParagraph, tag, getHtmlPipelineContext(ctx)));
|
||||
} catch (NoCustomContextException e) {
|
||||
throw new RuntimeWorkerException(LocaleMessages.getInstance().getMessage("customcontext.404"), e);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
public List<Element> start(WorkerContext ctx, Tag tag) {
|
||||
List<Element> l = new ArrayList<Element>(1);
|
||||
try {
|
||||
Map<String, String> css = tag.getCSS();
|
||||
if (css.containsKey("background-color")) {
|
||||
MapContext pipeline = (MapContext)ctx.get(PdfWriterPipeline.class.getName());
|
||||
if (pipeline != null) {
|
||||
Document document = (Document)pipeline.get("DOCUMENT");
|
||||
Rectangle rectangle = new Rectangle(document.left(), document.bottom(), document.right(), document.top(), document.getPageSize().getRotation());
|
||||
rectangle.setBackgroundColor(HtmlUtilities.decodeColor(css.get("background-color")));
|
||||
PdfBody body = new PdfBody(rectangle);
|
||||
l.add(body);
|
||||
}
|
||||
}
|
||||
} catch (NoCustomContextException e) {}
|
||||
return l;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package com.itextpdf.tool.xml.html;
|
||||
|
||||
import com.itextpdf.text.Chunk;
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.tool.xml.NoCustomContextException;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.WorkerContext;
|
||||
import com.itextpdf.tool.xml.exceptions.LocaleMessages;
|
||||
import com.itextpdf.tool.xml.exceptions.RuntimeWorkerException;
|
||||
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Break extends AbstractTagProcessor {
|
||||
public List<Element> end(WorkerContext ctx, Tag tag, List<Element> currentContent) {
|
||||
List<Element> l = new ArrayList<Element>(1);
|
||||
try {
|
||||
HtmlPipelineContext htmlPipelineContext = getHtmlPipelineContext(ctx);
|
||||
Chunk newLine = (Chunk)getCssAppliers().apply(new Chunk(Chunk.NEWLINE), tag, htmlPipelineContext);
|
||||
l.add(newLine);
|
||||
} catch (NoCustomContextException e1) {
|
||||
throw new RuntimeWorkerException(LocaleMessages.getInstance().getMessage("customcontext.404"), e1);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.itextpdf.tool.xml.html;
|
||||
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.css.apply.MarginMemory;
|
||||
import com.itextpdf.tool.xml.css.apply.PageSizeContainable;
|
||||
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
|
||||
|
||||
public interface CssApplier<T extends com.itextpdf.text.Element> {
|
||||
T apply(T paramT, Tag paramTag, MarginMemory paramMarginMemory, PageSizeContainable paramPageSizeContainable, HtmlPipelineContext paramHtmlPipelineContext);
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.itextpdf.tool.xml.html;
|
||||
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.css.apply.ChunkCssApplier;
|
||||
import com.itextpdf.tool.xml.css.apply.MarginMemory;
|
||||
import com.itextpdf.tool.xml.css.apply.PageSizeContainable;
|
||||
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
|
||||
|
||||
public interface CssAppliers {
|
||||
Element apply(Element paramElement, Tag paramTag, MarginMemory paramMarginMemory, PageSizeContainable paramPageSizeContainable, HtmlPipelineContext paramHtmlPipelineContext);
|
||||
|
||||
Element apply(Element paramElement, Tag paramTag, HtmlPipelineContext paramHtmlPipelineContext);
|
||||
|
||||
ChunkCssApplier getChunkCssAplier();
|
||||
|
||||
void setChunkCssAplier(ChunkCssApplier paramChunkCssApplier);
|
||||
|
||||
CssAppliers clone();
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package com.itextpdf.tool.xml.html;
|
||||
|
||||
public interface CssAppliersAware {
|
||||
void setCssAppliers(CssAppliers paramCssAppliers);
|
||||
|
||||
CssAppliers getCssAppliers();
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
package com.itextpdf.tool.xml.html;
|
||||
|
||||
import com.itextpdf.text.Chunk;
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.text.FontProvider;
|
||||
import com.itextpdf.text.List;
|
||||
import com.itextpdf.text.Paragraph;
|
||||
import com.itextpdf.text.pdf.PdfDiv;
|
||||
import com.itextpdf.text.pdf.draw.LineSeparator;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.css.apply.ChunkCssApplier;
|
||||
import com.itextpdf.tool.xml.css.apply.DivCssApplier;
|
||||
import com.itextpdf.tool.xml.css.apply.HtmlCellCssApplier;
|
||||
import com.itextpdf.tool.xml.css.apply.ImageCssApplier;
|
||||
import com.itextpdf.tool.xml.css.apply.LineSeparatorCssApplier;
|
||||
import com.itextpdf.tool.xml.css.apply.ListStyleTypeCssApplier;
|
||||
import com.itextpdf.tool.xml.css.apply.MarginMemory;
|
||||
import com.itextpdf.tool.xml.css.apply.NoNewLineParagraphCssApplier;
|
||||
import com.itextpdf.tool.xml.css.apply.PageSizeContainable;
|
||||
import com.itextpdf.tool.xml.css.apply.ParagraphCssApplier;
|
||||
import com.itextpdf.tool.xml.html.pdfelement.HtmlCell;
|
||||
import com.itextpdf.tool.xml.html.pdfelement.NoNewLineParagraph;
|
||||
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class CssAppliersImpl implements CssAppliers {
|
||||
private Map<Class<?>, CssApplier<? extends Element>> map;
|
||||
|
||||
public CssAppliersImpl() {
|
||||
this.map = new HashMap<Class<?>, CssApplier<? extends Element>>();
|
||||
this.map.put(Chunk.class, new ChunkCssApplier(null));
|
||||
this.map.put(Paragraph.class, new ParagraphCssApplier(this));
|
||||
this.map.put(NoNewLineParagraph.class, new NoNewLineParagraphCssApplier());
|
||||
this.map.put(HtmlCell.class, new HtmlCellCssApplier());
|
||||
this.map.put(List.class, new ListStyleTypeCssApplier());
|
||||
this.map.put(LineSeparator.class, new LineSeparatorCssApplier());
|
||||
this.map.put(com.itextpdf.text.Image.class, new ImageCssApplier());
|
||||
this.map.put(PdfDiv.class, new DivCssApplier());
|
||||
}
|
||||
|
||||
public CssAppliersImpl(FontProvider fontProvider) {
|
||||
this();
|
||||
((ChunkCssApplier)this.map.get(Chunk.class)).setFontProvider(fontProvider);
|
||||
}
|
||||
|
||||
public void putCssApplier(Class<?> s, CssApplier c) {
|
||||
this.map.put(s, c);
|
||||
}
|
||||
|
||||
public CssApplier getCssApplier(Class<?> s) {
|
||||
return this.map.get(s);
|
||||
}
|
||||
|
||||
public Element apply(Element e, Tag t, MarginMemory mm, PageSizeContainable psc, HtmlPipelineContext ctx) {
|
||||
CssApplier<Element> c = null;
|
||||
for (Map.Entry<Class<?>, CssApplier<? extends Element>> entry : this.map.entrySet()) {
|
||||
if (entry.getKey().isInstance(e)) {
|
||||
c = (CssApplier)entry.getValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (c == null)
|
||||
throw new RuntimeException();
|
||||
e = c.apply(e, t, mm, psc, ctx);
|
||||
return e;
|
||||
}
|
||||
|
||||
public Element apply(Element e, Tag t, HtmlPipelineContext ctx) {
|
||||
return apply(e, t, ctx, ctx, ctx);
|
||||
}
|
||||
|
||||
public ChunkCssApplier getChunkCssAplier() {
|
||||
return (ChunkCssApplier)this.map.get(Chunk.class);
|
||||
}
|
||||
|
||||
public void setChunkCssAplier(ChunkCssApplier chunkCssAplier) {
|
||||
this.map.put(Chunk.class, chunkCssAplier);
|
||||
}
|
||||
|
||||
public CssAppliers clone() {
|
||||
CssAppliersImpl clone = getClonedObject();
|
||||
clone.map = new HashMap<Class<?>, CssApplier<? extends Element>>(this.map);
|
||||
return clone;
|
||||
}
|
||||
|
||||
protected CssAppliersImpl getClonedObject() {
|
||||
return new CssAppliersImpl();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
package com.itextpdf.tool.xml.html;
|
||||
|
||||
import com.itextpdf.tool.xml.exceptions.LocaleMessages;
|
||||
import com.itextpdf.tool.xml.exceptions.NoTagProcessorException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class DefaultTagProcessorFactory implements TagProcessorFactory {
|
||||
private final Map<String, FactoryObject> map;
|
||||
|
||||
protected final class FactoryObject {
|
||||
private final String className;
|
||||
|
||||
private TagProcessor proc;
|
||||
|
||||
public FactoryObject(String className) {
|
||||
this.className = className;
|
||||
}
|
||||
|
||||
public FactoryObject(String className, TagProcessor processor) {
|
||||
this(className);
|
||||
this.proc = processor;
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return this.className;
|
||||
}
|
||||
|
||||
public TagProcessor getProcessor() {
|
||||
if (null == this.proc)
|
||||
this.proc = DefaultTagProcessorFactory.this.load(this.className);
|
||||
return this.proc;
|
||||
}
|
||||
}
|
||||
|
||||
public DefaultTagProcessorFactory() {
|
||||
this.map = new ConcurrentHashMap<String, FactoryObject>();
|
||||
}
|
||||
|
||||
protected TagProcessor load(String className) throws NoTagProcessorException {
|
||||
try {
|
||||
Class<?> c = Class.forName(className);
|
||||
return (TagProcessor)c.newInstance();
|
||||
} catch (LinkageError e) {
|
||||
throw new NoTagProcessorException(String.format(LocaleMessages.getInstance().getMessage("tag.noprocessor"), className));
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new NoTagProcessorException(String.format(LocaleMessages.getInstance().getMessage("tag.noprocessor"), className), e);
|
||||
} catch (InstantiationException e) {
|
||||
throw new NoTagProcessorException(String.format(LocaleMessages.getInstance().getMessage("tag.noprocessor"), className), e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new NoTagProcessorException(String.format(LocaleMessages.getInstance().getMessage("tag.noprocessor"), className), e);
|
||||
}
|
||||
}
|
||||
|
||||
protected TagProcessor load(String className, ClassLoader loader) throws NoTagProcessorException {
|
||||
try {
|
||||
Class<?> c = loader.loadClass(className);
|
||||
return (TagProcessor)c.newInstance();
|
||||
} catch (LinkageError e) {
|
||||
throw new NoTagProcessorException(String.format(
|
||||
LocaleMessages.getInstance().getMessage("tag.noprocessor"), className));
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new NoTagProcessorException(String.format(
|
||||
LocaleMessages.getInstance().getMessage("tag.noprocessor"), className), e);
|
||||
} catch (InstantiationException e) {
|
||||
throw new NoTagProcessorException(String.format(
|
||||
LocaleMessages.getInstance().getMessage("tag.noprocessor"), className), e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new NoTagProcessorException(String.format(
|
||||
LocaleMessages.getInstance().getMessage("tag.noprocessor"), className), e);
|
||||
}
|
||||
}
|
||||
|
||||
public TagProcessor getProcessor(String tag, String nameSpace) {
|
||||
FactoryObject fo = this.map.get(tag.toLowerCase());
|
||||
if (fo != null)
|
||||
return fo.getProcessor();
|
||||
throw new NoTagProcessorException(tag);
|
||||
}
|
||||
|
||||
public void addProcessor(String tag, String className) {
|
||||
this.map.put(tag, new FactoryObject(className));
|
||||
}
|
||||
|
||||
public void addProcessor(String tag, TagProcessor processor) {
|
||||
this.map.put(tag, new FactoryObject(processor.getClass().getName(), processor));
|
||||
}
|
||||
|
||||
public void addProcessor(TagProcessor processor, String... tags) {
|
||||
for (String tag : tags)
|
||||
addProcessor(tag, processor);
|
||||
}
|
||||
|
||||
public void addProcessor(String className, String... tags) {
|
||||
for (String tag : tags)
|
||||
addProcessor(tag, className);
|
||||
}
|
||||
|
||||
public void removeProcessor(String tag) {
|
||||
this.map.remove(tag);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
package com.itextpdf.tool.xml.html;
|
||||
|
||||
import com.itextpdf.text.Chunk;
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.text.Paragraph;
|
||||
import com.itextpdf.text.pdf.PdfDiv;
|
||||
import com.itextpdf.tool.xml.NoCustomContextException;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.WorkerContext;
|
||||
import com.itextpdf.tool.xml.exceptions.LocaleMessages;
|
||||
import com.itextpdf.tool.xml.exceptions.RuntimeWorkerException;
|
||||
import com.itextpdf.tool.xml.html.pdfelement.NoNewLineParagraph;
|
||||
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Div extends AbstractTagProcessor {
|
||||
public List<Element> content(WorkerContext ctx, Tag tag, String content) {
|
||||
List<Chunk> sanitizedChunks = HTMLUtils.sanitize(content, false);
|
||||
NoNewLineParagraph noNewLineParagraph = new NoNewLineParagraph();
|
||||
List<Element> l = new ArrayList<Element>(1);
|
||||
try {
|
||||
HtmlPipelineContext htmlPipelineContext = getHtmlPipelineContext(ctx);
|
||||
for (Chunk sanitized : sanitizedChunks)
|
||||
noNewLineParagraph.add(getCssAppliers().apply((Element)sanitized, tag, htmlPipelineContext));
|
||||
if (noNewLineParagraph.size() > 0)
|
||||
l.add(getCssAppliers().apply((Element)noNewLineParagraph, tag, htmlPipelineContext));
|
||||
} catch (NoCustomContextException e) {
|
||||
throw new RuntimeWorkerException(e);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
public List<Element> end(WorkerContext ctx, Tag tag, List<Element> currentContent) {
|
||||
try {
|
||||
Paragraph p = null;
|
||||
PdfDiv div = (PdfDiv)getCssAppliers().apply(new PdfDiv(), tag, getHtmlPipelineContext(ctx));
|
||||
int direction = getRunDirection(tag);
|
||||
if (direction != 1)
|
||||
div.setRunDirection(direction);
|
||||
for (Element e : currentContent) {
|
||||
if (e instanceof Paragraph || e instanceof com.itextpdf.text.pdf.PdfPTable || e instanceof PdfDiv) {
|
||||
if (p != null) {
|
||||
if (p.trim())
|
||||
div.addElement((Element)p);
|
||||
p = null;
|
||||
}
|
||||
div.addElement(e);
|
||||
continue;
|
||||
}
|
||||
if (p == null) {
|
||||
p = new Paragraph();
|
||||
p.setAlignment(div.getTextAlignment());
|
||||
if (direction == 3)
|
||||
invertTextAlignForParagraph(p);
|
||||
p.setMultipliedLeading(1.2F);
|
||||
}
|
||||
p.add(e);
|
||||
}
|
||||
if (p != null && p.trim())
|
||||
div.addElement((Element)p);
|
||||
if (direction == 3)
|
||||
invertTextAlignForDiv(div);
|
||||
List<Element> l = new ArrayList<Element>(1);
|
||||
l.add(div);
|
||||
return l;
|
||||
} catch (NoCustomContextException e) {
|
||||
throw new RuntimeWorkerException(LocaleMessages.getInstance().getMessage("customcontext.404"), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void invertTextAlignForDiv(PdfDiv div) {
|
||||
switch (div.getTextAlignment()) {
|
||||
case -1:
|
||||
case 1:
|
||||
case 3:
|
||||
case 8:
|
||||
break;
|
||||
case 2:
|
||||
div.setTextAlignment(0);
|
||||
break;
|
||||
default:
|
||||
div.setTextAlignment(2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isStackOwner() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.itextpdf.tool.xml.html;
|
||||
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.WorkerContext;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DummyTagProcessor implements TagProcessor {
|
||||
public List<Element> startElement(WorkerContext ctx, Tag tag) {
|
||||
return new ArrayList<Element>(0);
|
||||
}
|
||||
|
||||
public List<Element> content(WorkerContext ctx, Tag tag, String content) {
|
||||
return new ArrayList<Element>(0);
|
||||
}
|
||||
|
||||
public List<Element> endElement(WorkerContext ctx, Tag tag, List<Element> currentContent) {
|
||||
return new ArrayList<Element>(0);
|
||||
}
|
||||
|
||||
public boolean isStackOwner() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,279 @@
|
|||
package com.itextpdf.tool.xml.html;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public final class HTML {
|
||||
public static final class Tag {
|
||||
public static final String XML = "xml";
|
||||
|
||||
public static final String THEAD = "thead";
|
||||
|
||||
public static final String TBODY = "tbody";
|
||||
|
||||
public static final String TFOOT = "tfoot";
|
||||
|
||||
public static final String OL = "ol";
|
||||
|
||||
public static final String UL = "ul";
|
||||
|
||||
public static final String CAPTION = "caption";
|
||||
|
||||
public static final String PRE = "pre";
|
||||
|
||||
public static final String P = "p";
|
||||
|
||||
public static final String DIV = "div";
|
||||
|
||||
public static final String H1 = "h1";
|
||||
|
||||
public static final String H2 = "h2";
|
||||
|
||||
public static final String H3 = "h3";
|
||||
|
||||
public static final String H4 = "h4";
|
||||
|
||||
public static final String H5 = "h5";
|
||||
|
||||
public static final String H6 = "h6";
|
||||
|
||||
public static final String TD = "td";
|
||||
|
||||
public static final String BR = "br";
|
||||
|
||||
public static final String LI = "li";
|
||||
|
||||
public static final String DD = "dd";
|
||||
|
||||
public static final String DT = "dt";
|
||||
|
||||
public static final String TH = "th";
|
||||
|
||||
public static final String HR = "hr";
|
||||
|
||||
public static final String BODY = "body";
|
||||
|
||||
public static final String HTML = "html";
|
||||
|
||||
public static final String TABLE = "table";
|
||||
|
||||
public static final String SCRIPT = "script";
|
||||
|
||||
public static final String HEAD = "head";
|
||||
|
||||
public static final String LINK = "link";
|
||||
|
||||
public static final String META = "meta";
|
||||
|
||||
public static final String STYLE = "style";
|
||||
|
||||
public static final String ADDRESS = "address";
|
||||
|
||||
public static final String ARTICLE = "article";
|
||||
|
||||
public static final String ASIDE = "aside";
|
||||
|
||||
public static final String AUDIO = "audio";
|
||||
|
||||
public static final String BLOCKQUOTE = "blockquote";
|
||||
|
||||
public static final String CANVAS = "canvas";
|
||||
|
||||
public static final String FIELDSET = "fieldset";
|
||||
|
||||
public static final String FIGCAPTION = "figcaption";
|
||||
|
||||
public static final String FIGURE = "figure";
|
||||
|
||||
public static final String FOOTER = "footer";
|
||||
|
||||
public static final String FONT = "font";
|
||||
|
||||
public static final String FORM = "form";
|
||||
|
||||
public static final String HEADER = "header";
|
||||
|
||||
public static final String HGROUP = "hgroup";
|
||||
|
||||
public static final String NOSCRIPT = "noscript";
|
||||
|
||||
public static final String OUTPUT = "output";
|
||||
|
||||
public static final String SECTION = "section";
|
||||
|
||||
public static final String VIDEO = "video";
|
||||
|
||||
public static final String BASE = "base";
|
||||
|
||||
public static final String COMMAND = "command";
|
||||
|
||||
public static final String TITLE = "title";
|
||||
|
||||
public static final String A = "a";
|
||||
|
||||
public static final String ABBR = "abbr";
|
||||
|
||||
public static final String B = "b";
|
||||
|
||||
public static final String BDO = "bdo";
|
||||
|
||||
public static final String BUTTON = "button";
|
||||
|
||||
public static final String DETAILS = "details";
|
||||
|
||||
public static final String CODE = "code";
|
||||
|
||||
public static final String DEL = "del";
|
||||
|
||||
public static final String DATALIST = "datalist";
|
||||
|
||||
public static final String DFN = "dfn";
|
||||
|
||||
public static final String EMBED = "embed";
|
||||
|
||||
public static final String CITE = "cite";
|
||||
|
||||
public static final String DL = "dl";
|
||||
|
||||
public static final String EM = "em";
|
||||
|
||||
public static final String I = "i";
|
||||
|
||||
public static final String IFRAME = "iframe";
|
||||
|
||||
public static final String INPUT = "input";
|
||||
|
||||
public static final String IMG = "img";
|
||||
|
||||
public static final String INS = "ins";
|
||||
|
||||
public static final String MAP = "map";
|
||||
|
||||
public static final String KEYGEN = "keygen";
|
||||
|
||||
public static final String METER = "meter";
|
||||
|
||||
public static final String MENU = "menu";
|
||||
|
||||
public static final String NAV = "nav";
|
||||
|
||||
public static final String KBD = "kbd";
|
||||
|
||||
public static final String MATH = "math";
|
||||
|
||||
public static final String MARK = "mark";
|
||||
|
||||
public static final String LABEL = "label";
|
||||
|
||||
public static final String Q = "q";
|
||||
|
||||
public static final String SAMP = "samp";
|
||||
|
||||
public static final String PROGRESS = "progress";
|
||||
|
||||
public static final String RUBY = "ruby";
|
||||
|
||||
public static final String OBJECT = "object";
|
||||
|
||||
public static final String SMALL = "small";
|
||||
|
||||
public static final String SUB = "sub";
|
||||
|
||||
public static final String SUP = "sup";
|
||||
|
||||
public static final String STRONG = "strong";
|
||||
|
||||
public static final String SELECT = "select";
|
||||
|
||||
public static final String SPAN = "span";
|
||||
|
||||
public static final String SVG = "svg";
|
||||
|
||||
public static final String WBR = "wbr";
|
||||
|
||||
public static final String TIME = "time";
|
||||
|
||||
public static final String TEXTAREA = "textarea";
|
||||
|
||||
public static final String VAR = "var";
|
||||
|
||||
public static final String TR = "tr";
|
||||
|
||||
public static final String BIG = "big";
|
||||
|
||||
public static final String S = "s";
|
||||
|
||||
public static final String STRIKE = "strike";
|
||||
|
||||
public static final String TT = "tt";
|
||||
|
||||
public static final String U = "u";
|
||||
}
|
||||
|
||||
public static final class Category {
|
||||
public static final Set<String> NOT_VISIBLE = new HashSet<String>(Arrays.<String>asList("html", "head", "meta", "script", "link", "style", "title"));
|
||||
|
||||
public static final Set<String> BLOCK_LEVEL = new HashSet<String>(Arrays.<String>asList("address", "article", "aside", "audio", "blockquote", "canvas", "dd", "div", "fieldset", "figcaption", "figure", "footer", "form", "h1", "h2", "h3", "h4", "h5", "h6", "header", "hgroup", "hr", "noscript", "ol", "output", "p", "pre", "section", "table", "ul", "video"));
|
||||
|
||||
public static final Set<String> METADATA = new HashSet<String>(Arrays.<String>asList("base", "command", "link", "meta", "noscript", "style", "title"));
|
||||
|
||||
public static final Set<String> FLOW_CONTENT = new HashSet<String>(Arrays.<String>asList("a", "abbr", "address", "article", "aside", "audio", "b", "bdo", "blockquote", "br", "button", "canvas", "cite", "code", "command", "datalist", "del", "details", "dfn", "div", "dl", "em", "embed", "fieldset", "figure", "footer", "form", "h1", "h2", "h3", "h4", "h5", "h6", "header", "hgroup", "hr", "i", "iframe", "img", "input", "ins", "kbd", "keygen", "label", "map", "mark", "math", "menu", "meter", "nav", "noscript", "object", "ol", "output", "p", "pre", "progress", "q", "ruby", "samp", "script", "section", "select", "small", "span", "font", "strong", "sub", "sup", "svg", "table", "textarea", "time", "ul", "var", "video", "wbr"));
|
||||
|
||||
public static final Set<String> SECTIONING_CONTENT = new HashSet<String>(Arrays.<String>asList("article", "aside", "nav", "section"));
|
||||
|
||||
public static final Set<String> HEADING_CONTENT = new HashSet<String>(Arrays.<String>asList("h1", "h2", "h3", "h4", "h5", "h6", "hgroup"));
|
||||
|
||||
public static final Set<String> PHRASING_CONTENT = new HashSet<String>(Arrays.<String>asList("abbr", "audio", "b", "bdo", "br", "button", "canvas", "cite", "code", "command", "datalist", "dfn", "em", "embed", "i", "iframe", "img", "input", "kbd", "keygen", "label", "mark", "math", "meter", "noscript", "object", "output", "progress", "q", "ruby", "samp", "script", "select", "small", "span", "font", "strong", "sub", "sup", "svg", "textarea", "time", "var", "video", "wbr"));
|
||||
|
||||
public static final Set<String> EMBEDDED_CONTENT = new HashSet<String>(Arrays.<String>asList("audio", "canvas", "embed", "iframe", "img", "math", "object", "svg", "video"));
|
||||
}
|
||||
|
||||
public static final class Attribute {
|
||||
public static final String ALT = "alt";
|
||||
|
||||
public static final String CELLPADDING = "cellpadding";
|
||||
|
||||
public static final String CELLSPACING = "cellspacing";
|
||||
|
||||
public static final String STYLE = "style";
|
||||
|
||||
public static final String CLASS = "class";
|
||||
|
||||
public static final String ID = "id";
|
||||
|
||||
public static final String HREF = "href";
|
||||
|
||||
public static final String NAME = "name";
|
||||
|
||||
public static final String SRC = "src";
|
||||
|
||||
public static final String WIDTH = "width";
|
||||
|
||||
public static final String HEIGHT = "height";
|
||||
|
||||
public static final String TYPE = "type";
|
||||
|
||||
public static final String COLSPAN = "colspan";
|
||||
|
||||
public static final String ROWSPAN = "rowspan";
|
||||
|
||||
public static final String VALIGN = "valign";
|
||||
|
||||
public static final String ALIGN = "align";
|
||||
|
||||
public static final String FACE = "face";
|
||||
|
||||
public static final String SIZE = "size";
|
||||
|
||||
public static final String COLOR = "color";
|
||||
|
||||
public static final String START = "start";
|
||||
|
||||
public static final String DIR = "dir";
|
||||
|
||||
public static final class Value {
|
||||
public static final String TEXTCSS = "text/css";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package com.itextpdf.tool.xml.html;
|
||||
|
||||
import com.itextpdf.text.Chunk;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class HTMLUtils {
|
||||
private static List<Chunk> sanitize(String str, boolean preserveWhiteSpace, boolean replaceNonBreakableSpaces) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
StringBuilder whitespaceBuilder = new StringBuilder();
|
||||
char[] chars = str.toCharArray();
|
||||
ArrayList<Chunk> chunkList = new ArrayList<Chunk>();
|
||||
boolean isWhitespace = (chars.length > 0) ? Character.isWhitespace(chars[0]) : true;
|
||||
for (char c : chars) {
|
||||
if (isWhitespace && !Character.isWhitespace(c)) {
|
||||
if (builder.length() == 0) {
|
||||
chunkList.add(Chunk.createWhitespace(whitespaceBuilder.toString(), preserveWhiteSpace));
|
||||
} else {
|
||||
builder.append(preserveWhiteSpace ? whitespaceBuilder : " ");
|
||||
}
|
||||
whitespaceBuilder = new StringBuilder();
|
||||
}
|
||||
isWhitespace = Character.isWhitespace(c);
|
||||
if (isWhitespace) {
|
||||
whitespaceBuilder.append(c);
|
||||
} else {
|
||||
builder.append(c);
|
||||
}
|
||||
}
|
||||
if (builder.length() > 0)
|
||||
chunkList.add(new Chunk(replaceNonBreakableSpaces ? builder.toString().replace(Character.valueOf('\u00A0').charValue(), Character.valueOf(' ').charValue()) : builder.toString()));
|
||||
if (whitespaceBuilder.length() > 0)
|
||||
chunkList.add(Chunk.createWhitespace(whitespaceBuilder.toString(), preserveWhiteSpace));
|
||||
return chunkList;
|
||||
}
|
||||
|
||||
public static List<Chunk> sanitize(String str, boolean preserveWhiteSpace) {
|
||||
return sanitize(str, preserveWhiteSpace, false);
|
||||
}
|
||||
|
||||
public static List<Chunk> sanitizeInline(String str, boolean preserveWhiteSpace) {
|
||||
return sanitize(str, preserveWhiteSpace, false);
|
||||
}
|
||||
|
||||
public static List<Chunk> sanitizeInline(String str, boolean preserveWhiteSpace, boolean replaceNonBreakableSpaces) {
|
||||
return sanitize(str, preserveWhiteSpace, replaceNonBreakableSpaces);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
package com.itextpdf.tool.xml.html;
|
||||
|
||||
import com.itextpdf.text.Document;
|
||||
import com.itextpdf.text.DocumentException;
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.text.Paragraph;
|
||||
import com.itextpdf.text.WritableDirectElement;
|
||||
import com.itextpdf.text.log.Level;
|
||||
import com.itextpdf.text.log.Logger;
|
||||
import com.itextpdf.text.log.LoggerFactory;
|
||||
import com.itextpdf.text.pdf.PdfDestination;
|
||||
import com.itextpdf.text.pdf.PdfName;
|
||||
import com.itextpdf.text.pdf.PdfOutline;
|
||||
import com.itextpdf.text.pdf.PdfWriter;
|
||||
import com.itextpdf.tool.xml.NoCustomContextException;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.WorkerContext;
|
||||
import com.itextpdf.tool.xml.exceptions.LocaleMessages;
|
||||
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
|
||||
import com.itextpdf.tool.xml.util.ParentTreeUtil;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class Header extends AbstractTagProcessor {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(Header.class);
|
||||
|
||||
public List<Element> content(WorkerContext ctx, Tag tag, String content) {
|
||||
return textContent(ctx, tag, content);
|
||||
}
|
||||
|
||||
public List<Element> end(WorkerContext ctx, final Tag tag, List<Element> currentContent) {
|
||||
List<Element> l = new ArrayList<Element>(1);
|
||||
ParentTreeUtil pt = new ParentTreeUtil();
|
||||
if (currentContent.size() > 0) {
|
||||
List<Element> currentContentToParagraph = currentContentToParagraph(currentContent, true, true, tag, ctx);
|
||||
for (Element p : currentContentToParagraph)
|
||||
((Paragraph)p).setRole(getHeaderRole(getLevel(tag)));
|
||||
try {
|
||||
final HtmlPipelineContext context = getHtmlPipelineContext(ctx);
|
||||
boolean oldBookmark = context.autoBookmark();
|
||||
if (!pt.getParentTree(tag).isEmpty() && pt.getParentTree(tag).contains("td"))
|
||||
context.autoBookmark(false);
|
||||
if (context.autoBookmark()) {
|
||||
final Paragraph title = new Paragraph();
|
||||
for (Element w : currentContentToParagraph)
|
||||
title.add(w);
|
||||
l.add(new WritableDirectElement(1) {
|
||||
public void write(PdfWriter writer, Document doc) throws DocumentException {
|
||||
PdfDestination destination = new PdfDestination(0, 20.0F,
|
||||
writer.getVerticalPosition(false), 0.0F);
|
||||
Map<String, Object> memory = context.getMemory();
|
||||
HeaderNode tree = (HeaderNode)memory.get("header.autobookmark.RootNode");
|
||||
int level = Header.this.getLevel(tag);
|
||||
if (null == tree) {
|
||||
tree = new HeaderNode(0, writer.getRootOutline(), null);
|
||||
} else {
|
||||
int lastLevel = tree.level();
|
||||
if (lastLevel == level) {
|
||||
tree = tree.parent();
|
||||
} else if (lastLevel > level) {
|
||||
while (lastLevel >= level) {
|
||||
lastLevel = tree.parent().level();
|
||||
tree = tree.parent();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Header.LOGGER.isLogging(Level.TRACE))
|
||||
Header.LOGGER.trace(String.format(LocaleMessages.getInstance().getMessage("html.tag.h.create"), title.toString()));
|
||||
HeaderNode node = new HeaderNode(level, new PdfOutline(tree.outline(), destination, title), tree);
|
||||
memory.put("header.autobookmark.RootNode", node);
|
||||
}
|
||||
});
|
||||
}
|
||||
context.autoBookmark(oldBookmark);
|
||||
} catch (NoCustomContextException e) {
|
||||
if (LOGGER.isLogging(Level.ERROR))
|
||||
LOGGER.error(LocaleMessages.getInstance().getMessage("html.tag.h.disabled"), e);
|
||||
}
|
||||
l.addAll(currentContentToParagraph);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
private PdfName getHeaderRole(int level) {
|
||||
switch (level) {
|
||||
case 1:
|
||||
return PdfName.H1;
|
||||
case 2:
|
||||
return PdfName.H2;
|
||||
case 3:
|
||||
return PdfName.H3;
|
||||
case 4:
|
||||
return PdfName.H4;
|
||||
case 5:
|
||||
return PdfName.H5;
|
||||
case 6:
|
||||
return PdfName.H6;
|
||||
}
|
||||
return PdfName.H;
|
||||
}
|
||||
|
||||
private int getLevel(Tag tag) {
|
||||
return Integer.parseInt(Character.toString(tag.getName().charAt(1)));
|
||||
}
|
||||
|
||||
public boolean isStackOwner() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package com.itextpdf.tool.xml.html;
|
||||
|
||||
import com.itextpdf.text.pdf.PdfOutline;
|
||||
|
||||
public class HeaderNode {
|
||||
private int level;
|
||||
|
||||
private PdfOutline outline;
|
||||
|
||||
private HeaderNode parent;
|
||||
|
||||
public HeaderNode(int level, PdfOutline outline, HeaderNode parent) {
|
||||
this.level = level;
|
||||
this.outline = outline;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public HeaderNode parent() {
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
public int level() {
|
||||
return this.level;
|
||||
}
|
||||
|
||||
public PdfOutline outline() {
|
||||
return this.outline;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package com.itextpdf.tool.xml.html;
|
||||
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.text.Paragraph;
|
||||
import com.itextpdf.text.pdf.draw.LineSeparator;
|
||||
import com.itextpdf.tool.xml.NoCustomContextException;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.WorkerContext;
|
||||
import com.itextpdf.tool.xml.css.CssUtils;
|
||||
import com.itextpdf.tool.xml.exceptions.LocaleMessages;
|
||||
import com.itextpdf.tool.xml.exceptions.RuntimeWorkerException;
|
||||
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class HorizontalRule extends AbstractTagProcessor {
|
||||
public List<Element> start(WorkerContext ctx, Tag tag) {
|
||||
try {
|
||||
List<Element> list = new ArrayList<Element>();
|
||||
HtmlPipelineContext htmlPipelineContext = getHtmlPipelineContext(ctx);
|
||||
LineSeparator lineSeparator = (LineSeparator)getCssAppliers().apply(new LineSeparator(), tag, htmlPipelineContext);
|
||||
Paragraph p = new Paragraph();
|
||||
Map<String, String> css = tag.getCSS();
|
||||
float fontSize = 12.0F;
|
||||
if (css.get("font-size") != null)
|
||||
fontSize = CssUtils.getInstance().parsePxInCmMmPcToPt(css.get("font-size"));
|
||||
String marginTop = css.get("margin-top");
|
||||
if (marginTop == null)
|
||||
marginTop = "0.5em";
|
||||
String marginBottom = css.get("margin-bottom");
|
||||
if (marginBottom == null)
|
||||
marginBottom = "0.5em";
|
||||
p.setSpacingBefore(p.getSpacingBefore() + CssUtils.getInstance().parseValueToPt(marginTop, fontSize));
|
||||
p.setSpacingAfter(p.getSpacingAfter() + CssUtils.getInstance().parseValueToPt(marginBottom, fontSize));
|
||||
p.setLeading(0.0F);
|
||||
p.add((Element)lineSeparator);
|
||||
list.add(p);
|
||||
return list;
|
||||
} catch (NoCustomContextException e) {
|
||||
throw new RuntimeWorkerException(LocaleMessages.getInstance().getMessage("customcontext.404"), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
package com.itextpdf.tool.xml.html;
|
||||
|
||||
import com.itextpdf.text.Chunk;
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.text.log.Level;
|
||||
import com.itextpdf.text.log.Logger;
|
||||
import com.itextpdf.text.log.LoggerFactory;
|
||||
import com.itextpdf.text.pdf.PdfName;
|
||||
import com.itextpdf.text.pdf.PdfString;
|
||||
import com.itextpdf.text.xml.XMLUtil;
|
||||
import com.itextpdf.tool.xml.NoCustomContextException;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.WorkerContext;
|
||||
import com.itextpdf.tool.xml.css.CssUtils;
|
||||
import com.itextpdf.tool.xml.exceptions.LocaleMessages;
|
||||
import com.itextpdf.tool.xml.exceptions.RuntimeWorkerException;
|
||||
import com.itextpdf.tool.xml.net.ImageRetrieve;
|
||||
import com.itextpdf.tool.xml.net.exc.NoImageException;
|
||||
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class Image extends AbstractTagProcessor {
|
||||
private final CssUtils utils = CssUtils.getInstance();
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(Image.class);
|
||||
|
||||
public List<Element> end(WorkerContext ctx, Tag tag, List<Element> currentContent) {
|
||||
Map<String, String> attributes = tag.getAttributes();
|
||||
String src = attributes.get("src");
|
||||
com.itextpdf.text.Image img = null;
|
||||
List<Element> l = new ArrayList<Element>(1);
|
||||
if (null != src && src.length() > 0) {
|
||||
src = XMLUtil.unescapeXML(src);
|
||||
src = src.trim();
|
||||
try {
|
||||
if (logger.isLogging(Level.TRACE))
|
||||
logger.trace(String.format(LocaleMessages.getInstance().getMessage("html.tag.img.try"), src));
|
||||
HtmlPipelineContext context = getHtmlPipelineContext(ctx);
|
||||
img = new ImageRetrieve(context.getResourcesRootPath(), context.getImageProvider()).retrieveImage(src);
|
||||
} catch (NoImageException e) {
|
||||
if (logger.isLogging(Level.ERROR))
|
||||
logger.error(String.format(LocaleMessages.getInstance().getMessage("html.tag.img.failedretrieve"), src), e);
|
||||
} catch (NoCustomContextException e) {
|
||||
throw new RuntimeWorkerException(LocaleMessages.getInstance().getMessage("customcontext.404"), e);
|
||||
}
|
||||
if (null != img)
|
||||
try {
|
||||
if (attributes.get("alt") != null)
|
||||
img.setAccessibleAttribute(PdfName.ALT, new PdfString(attributes.get("alt")));
|
||||
HtmlPipelineContext htmlPipelineContext = getHtmlPipelineContext(ctx);
|
||||
l.add(getCssAppliers().apply(new Chunk((com.itextpdf.text.Image)getCssAppliers().apply((Element)img, tag, htmlPipelineContext), 0.0F, 0.0F, true), tag, htmlPipelineContext));
|
||||
} catch (NoCustomContextException e) {
|
||||
throw new RuntimeWorkerException(e);
|
||||
}
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
public boolean isStackOwner() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.itextpdf.tool.xml.html;
|
||||
|
||||
import com.itextpdf.text.Chunk;
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.tool.xml.NoCustomContextException;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.WorkerContext;
|
||||
import com.itextpdf.tool.xml.exceptions.RuntimeWorkerException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class NonSanitizedTag extends AbstractTagProcessor {
|
||||
public List<Element> content(WorkerContext ctx, Tag tag, String content) {
|
||||
List<Element> l = new ArrayList<Element>(1);
|
||||
if (null != content && content.length() > 0)
|
||||
try {
|
||||
l.add(getCssAppliers().apply(new Chunk(content), tag, getHtmlPipelineContext(ctx)));
|
||||
} catch (NoCustomContextException e) {
|
||||
throw new RuntimeWorkerException(e);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
public List<Element> end(WorkerContext ctx, Tag tag, List<Element> currentContent) {
|
||||
return currentContentToParagraph(currentContent, false, true, tag, ctx);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
package com.itextpdf.tool.xml.html;
|
||||
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.text.ListItem;
|
||||
import com.itextpdf.tool.xml.NoCustomContextException;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.WorkerContext;
|
||||
import com.itextpdf.tool.xml.css.CssUtils;
|
||||
import com.itextpdf.tool.xml.css.FontSizeTranslator;
|
||||
import com.itextpdf.tool.xml.exceptions.LocaleMessages;
|
||||
import com.itextpdf.tool.xml.exceptions.RuntimeWorkerException;
|
||||
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class OrderedUnorderedList extends AbstractTagProcessor {
|
||||
private static final FontSizeTranslator fst = FontSizeTranslator.getInstance();
|
||||
|
||||
private static final CssUtils utils = CssUtils.getInstance();
|
||||
|
||||
public List<Element> end(WorkerContext ctx, Tag tag, List<Element> currentContent) {
|
||||
List<Element> listElements = populateList(currentContent);
|
||||
int size = listElements.size();
|
||||
List<Element> returnedList = new ArrayList<Element>();
|
||||
if (size > 0) {
|
||||
com.itextpdf.text.List list;
|
||||
HtmlPipelineContext htmlPipelineContext = null;
|
||||
try {
|
||||
htmlPipelineContext = getHtmlPipelineContext(ctx);
|
||||
list = (com.itextpdf.text.List)getCssAppliers().apply(new com.itextpdf.text.List(), tag, htmlPipelineContext);
|
||||
} catch (NoCustomContextException e) {
|
||||
list = (com.itextpdf.text.List)getCssAppliers().apply(new com.itextpdf.text.List(), tag, null);
|
||||
}
|
||||
int i = 0;
|
||||
for (Element li : listElements) {
|
||||
if (li instanceof ListItem) {
|
||||
Tag child = tag.getChildren().get(i);
|
||||
if (size == 1) {
|
||||
child.getCSS().put("margin-top",
|
||||
calculateTopOrBottomSpacing(true, false, tag, child, ctx) + "pt");
|
||||
float marginBottom = calculateTopOrBottomSpacing(false, false, tag, child, ctx);
|
||||
child.getCSS().put("margin-bottom", marginBottom + "pt");
|
||||
} else {
|
||||
if (i == 0)
|
||||
child.getCSS().put("margin-top",
|
||||
calculateTopOrBottomSpacing(true, false, tag, child, ctx) + "pt");
|
||||
if (i == size - 1) {
|
||||
float marginBottom = calculateTopOrBottomSpacing(false, true, tag, child, ctx);
|
||||
child.getCSS().put("margin-bottom", marginBottom + "pt");
|
||||
}
|
||||
}
|
||||
try {
|
||||
list.add(getCssAppliers().apply(li, child, getHtmlPipelineContext(ctx)));
|
||||
} catch (NoCustomContextException e1) {
|
||||
throw new RuntimeWorkerException(LocaleMessages.getInstance().getMessage("customcontext.404"), e1);
|
||||
}
|
||||
} else {
|
||||
list.add(li);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
returnedList.add(list);
|
||||
}
|
||||
return returnedList;
|
||||
}
|
||||
|
||||
private List<Element> populateList(List<Element> currentContent) {
|
||||
List<Element> listElements = new ArrayList<Element>();
|
||||
for (Element e : currentContent) {
|
||||
if (e instanceof ListItem || e instanceof com.itextpdf.text.List) {
|
||||
listElements.add(e);
|
||||
continue;
|
||||
}
|
||||
ListItem listItem = new ListItem();
|
||||
listItem.add(e);
|
||||
listElements.add(listItem);
|
||||
}
|
||||
return listElements;
|
||||
}
|
||||
|
||||
private float calculateTopOrBottomSpacing(boolean isTop, boolean storeMarginBottom, Tag tag, Tag child, WorkerContext ctx) {
|
||||
float totalSpacing = 0.0F;
|
||||
try {
|
||||
HtmlPipelineContext context = getHtmlPipelineContext(ctx);
|
||||
String end = isTop ? "-top" : "-bottom";
|
||||
float ownFontSize = fst.getFontSize(tag);
|
||||
if (ownFontSize == -1.0F)
|
||||
ownFontSize = 0.0F;
|
||||
float ownMargin = 0.0F;
|
||||
String marginValue = tag.getCSS().get("margin" + end);
|
||||
if (marginValue == null) {
|
||||
if (null != tag.getParent() &&
|
||||
getHtmlPipelineContext(ctx).getRootTags().contains(tag.getParent().getName()))
|
||||
ownMargin = ownFontSize;
|
||||
} else {
|
||||
ownMargin = utils.parseValueToPt(marginValue, ownFontSize);
|
||||
}
|
||||
float ownPadding = (tag.getCSS().get("padding" + end) != null) ? utils.parseValueToPt(tag.getCSS()
|
||||
.get("padding" + end), ownFontSize) : 0.0F;
|
||||
float childFontSize = fst.getFontSize(child);
|
||||
float childMargin = (child.getCSS().get("margin" + end) != null) ? utils.parseValueToPt(
|
||||
child.getCSS().get("margin" + end), childFontSize) : 0.0F;
|
||||
if (ownPadding == 0.0F) {
|
||||
float margin = 0.0F;
|
||||
if (ownMargin != 0.0F && childMargin != 0.0F) {
|
||||
margin = (ownMargin >= childMargin) ? ownMargin : childMargin;
|
||||
} else if (ownMargin != 0.0F) {
|
||||
margin = ownMargin;
|
||||
} else if (childMargin != 0.0F) {
|
||||
margin = childMargin;
|
||||
}
|
||||
if (!isTop && storeMarginBottom)
|
||||
context.getMemory().put("lastMarginBottom", Float.valueOf(margin));
|
||||
totalSpacing = margin;
|
||||
} else {
|
||||
totalSpacing = ownMargin + ownPadding + childMargin;
|
||||
if (!isTop && storeMarginBottom)
|
||||
context.getMemory().put("lastMarginBottom", Float.valueOf(ownMargin));
|
||||
}
|
||||
} catch (NoCustomContextException e) {
|
||||
throw new RuntimeWorkerException(LocaleMessages.getInstance().getMessage("customcontext.404"), e);
|
||||
}
|
||||
return totalSpacing;
|
||||
}
|
||||
|
||||
public boolean isStackOwner() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package com.itextpdf.tool.xml.html;
|
||||
|
||||
import com.itextpdf.text.Chunk;
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.text.ListItem;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.WorkerContext;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class OrderedUnorderedListItem extends AbstractTagProcessor {
|
||||
public List<Element> content(WorkerContext ctx, Tag tag, String content) {
|
||||
return textContent(ctx, tag, content);
|
||||
}
|
||||
|
||||
public List<Element> end(WorkerContext ctx, Tag tag, List<Element> currentContent) {
|
||||
List<Element> l = new ArrayList<Element>(1);
|
||||
ListItem li = new ListItem();
|
||||
float maxSize = -1.0F;
|
||||
for (Element e : currentContent) {
|
||||
li.add(e);
|
||||
for (Chunk chunk : (Iterable<Chunk>)e.getChunks()) {
|
||||
float currFontSize = chunk.getFont().getCalculatedLeading(1.3333334F);
|
||||
if (maxSize < currFontSize)
|
||||
maxSize = currFontSize;
|
||||
}
|
||||
}
|
||||
if (li.getLeading() < maxSize)
|
||||
li.setLeading(maxSize);
|
||||
if (li.trim())
|
||||
l.add(li);
|
||||
return l;
|
||||
}
|
||||
|
||||
public boolean isStackOwner() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
package com.itextpdf.tool.xml.html;
|
||||
|
||||
import com.itextpdf.text.Chunk;
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.text.ListItem;
|
||||
import com.itextpdf.text.Paragraph;
|
||||
import com.itextpdf.text.pdf.draw.VerticalPositionMark;
|
||||
import com.itextpdf.tool.xml.NoCustomContextException;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.WorkerContext;
|
||||
import com.itextpdf.tool.xml.css.CssUtils;
|
||||
import com.itextpdf.tool.xml.exceptions.LocaleMessages;
|
||||
import com.itextpdf.tool.xml.exceptions.RuntimeWorkerException;
|
||||
import com.itextpdf.tool.xml.html.pdfelement.TabbedChunk;
|
||||
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ParaGraph extends AbstractTagProcessor {
|
||||
public List<Element> content(WorkerContext ctx, Tag tag, String content) {
|
||||
List<Chunk> sanitizedChunks = HTMLUtils.sanitize(content, false);
|
||||
List<Element> l = new ArrayList<Element>(1);
|
||||
for (Chunk sanitized : sanitizedChunks) {
|
||||
HtmlPipelineContext myctx;
|
||||
try {
|
||||
myctx = getHtmlPipelineContext(ctx);
|
||||
} catch (NoCustomContextException e) {
|
||||
throw new RuntimeWorkerException(e);
|
||||
}
|
||||
if (null != tag.getCSS().get("tab-interval")) {
|
||||
TabbedChunk tabbedChunk = new TabbedChunk(sanitized.getContent());
|
||||
if (null != getLastChild(tag) && null != getLastChild(tag).getCSS().get("xfa-tab-count"))
|
||||
tabbedChunk.setTabCount(Integer.parseInt(getLastChild(tag).getCSS().get("xfa-tab-count")));
|
||||
l.add(getCssAppliers().apply((Element)tabbedChunk, tag, myctx));
|
||||
continue;
|
||||
}
|
||||
if (null != getLastChild(tag) && null != getLastChild(tag).getCSS().get("xfa-tab-count")) {
|
||||
TabbedChunk tabbedChunk = new TabbedChunk(sanitized.getContent());
|
||||
tabbedChunk.setTabCount(Integer.parseInt(getLastChild(tag).getCSS().get("xfa-tab-count")));
|
||||
l.add(getCssAppliers().apply((Element)tabbedChunk, tag, myctx));
|
||||
continue;
|
||||
}
|
||||
l.add(getCssAppliers().apply((Element)sanitized, tag, myctx));
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
private Tag getLastChild(Tag tag) {
|
||||
if (0 != tag.getChildren().size())
|
||||
return tag.getChildren().get(tag.getChildren().size() - 1);
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<Element> end(WorkerContext ctx, Tag tag, List<Element> currentContent) {
|
||||
List<Element> l = new ArrayList<Element>(1);
|
||||
if (currentContent.size() > 0) {
|
||||
List<Element> elements = new ArrayList<Element>();
|
||||
List<ListItem> listItems = new ArrayList<ListItem>();
|
||||
for (Element el : currentContent) {
|
||||
if (el instanceof ListItem) {
|
||||
if (!elements.isEmpty()) {
|
||||
processParagraphItems(ctx, tag, elements, l);
|
||||
elements.clear();
|
||||
}
|
||||
listItems.add((ListItem)el);
|
||||
continue;
|
||||
}
|
||||
if (!listItems.isEmpty()) {
|
||||
processListItems(ctx, tag, listItems, l);
|
||||
listItems.clear();
|
||||
}
|
||||
elements.add(el);
|
||||
}
|
||||
if (!elements.isEmpty()) {
|
||||
processParagraphItems(ctx, tag, elements, l);
|
||||
elements.clear();
|
||||
} else if (!listItems.isEmpty()) {
|
||||
processListItems(ctx, tag, listItems, l);
|
||||
listItems.clear();
|
||||
}
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
protected void processParagraphItems(WorkerContext ctx, Tag tag, List<Element> paragraphItems, List<Element> l) {
|
||||
Paragraph p = new Paragraph();
|
||||
p.setMultipliedLeading(1.2F);
|
||||
Map<String, String> css = tag.getCSS();
|
||||
if (null != css.get("tab-interval")) {
|
||||
addTabIntervalContent(ctx, tag, paragraphItems, p, css.get("tab-interval"));
|
||||
l.add(p);
|
||||
} else if (null != css.get("tab-stops")) {
|
||||
addTabStopsContent(paragraphItems, p, css.get("tab-stops"));
|
||||
l.add(p);
|
||||
} else if (null != css.get("xfa-tab-stops")) {
|
||||
addTabStopsContent(paragraphItems, p, css.get("xfa-tab-stops"));
|
||||
l.add(p);
|
||||
} else {
|
||||
List<Element> paraList = currentContentToParagraph(paragraphItems, true, true, tag, ctx);
|
||||
if (!l.isEmpty() && !paraList.isEmpty()) {
|
||||
Element firstElement = paraList.get(0);
|
||||
if (firstElement instanceof Paragraph)
|
||||
((Paragraph)firstElement).setSpacingBefore(0.0F);
|
||||
}
|
||||
for (Element e : paraList)
|
||||
l.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void processListItems(WorkerContext ctx, Tag tag, List<ListItem> listItems, List<Element> l) {
|
||||
try {
|
||||
com.itextpdf.text.List list = new com.itextpdf.text.List();
|
||||
list.setAlignindent(false);
|
||||
list = (com.itextpdf.text.List)getCssAppliers().apply((Element)list, tag,
|
||||
getHtmlPipelineContext(ctx));
|
||||
list.setIndentationLeft(0.0F);
|
||||
int i = 0;
|
||||
for (ListItem li : listItems) {
|
||||
li = (ListItem)getCssAppliers().apply((Element)li, tag, getHtmlPipelineContext(ctx));
|
||||
if (i != listItems.size() - 1)
|
||||
li.setSpacingAfter(0.0F);
|
||||
if (i != 0)
|
||||
li.setSpacingBefore(0.0F);
|
||||
i++;
|
||||
li.setMultipliedLeading(1.2F);
|
||||
list.add((Element)li);
|
||||
}
|
||||
if (!l.isEmpty()) {
|
||||
Element latestElement = l.get(l.size() - 1);
|
||||
if (latestElement instanceof Paragraph)
|
||||
((Paragraph)latestElement).setSpacingAfter(0.0F);
|
||||
}
|
||||
l.add(list);
|
||||
} catch (NoCustomContextException e) {
|
||||
throw new RuntimeWorkerException(LocaleMessages.getInstance().getMessage("customcontext.404"), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void addTabIntervalContent(WorkerContext ctx, Tag tag, List<Element> currentContent, Paragraph p, String value) {
|
||||
float width = 0.0F;
|
||||
for (Element e : currentContent) {
|
||||
if (e instanceof TabbedChunk) {
|
||||
width += (float)((TabbedChunk)e).getTabCount() * CssUtils.getInstance().parsePxInCmMmPcToPt(value);
|
||||
TabbedChunk tab = new TabbedChunk(new VerticalPositionMark(), width, false);
|
||||
p.add(new Chunk(tab));
|
||||
p.add(new Chunk((TabbedChunk)e));
|
||||
continue;
|
||||
}
|
||||
if (e instanceof com.itextpdf.text.pdf.draw.LineSeparator)
|
||||
try {
|
||||
HtmlPipelineContext htmlPipelineContext = getHtmlPipelineContext(ctx);
|
||||
Chunk newLine = (Chunk)getCssAppliers().apply(new Chunk(Chunk.NEWLINE), tag, htmlPipelineContext);
|
||||
p.add((Element)newLine);
|
||||
} catch (NoCustomContextException e1) {
|
||||
throw new RuntimeWorkerException(LocaleMessages.getInstance().getMessage("customcontext.404"), e1);
|
||||
}
|
||||
p.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void addTabStopsContent(List<Element> currentContent, Paragraph p, String value) {
|
||||
List<Chunk> tabs = new ArrayList<Chunk>();
|
||||
String[] alignAndWidth = value.split(" ");
|
||||
float tabWidth = 0.0F;
|
||||
for (int i = 0, j = 1; j < alignAndWidth.length; i += 2, j += 2) {
|
||||
tabWidth += CssUtils.getInstance().parsePxInCmMmPcToPt(alignAndWidth[j]);
|
||||
TabbedChunk tab = new TabbedChunk(new VerticalPositionMark(), tabWidth, true, alignAndWidth[i]);
|
||||
tabs.add(tab);
|
||||
}
|
||||
int tabsPerRow = tabs.size();
|
||||
int currentTab = 0;
|
||||
for (Element e : currentContent) {
|
||||
if (e instanceof TabbedChunk) {
|
||||
if (currentTab == tabsPerRow)
|
||||
currentTab = 0;
|
||||
if (((TabbedChunk)e).getTabCount() != 0) {
|
||||
p.add(new Chunk(tabs.get(currentTab)));
|
||||
p.add(new Chunk((TabbedChunk)e));
|
||||
currentTab++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
p.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isStackOwner() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.itextpdf.tool.xml.html;
|
||||
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.WorkerContext;
|
||||
import java.util.List;
|
||||
|
||||
public class Span extends AbstractTagProcessor {
|
||||
public List<Element> content(WorkerContext ctx, Tag tag, String content) {
|
||||
return textContent(ctx, tag, content);
|
||||
}
|
||||
|
||||
public List<Element> end(WorkerContext ctx, Tag tag, List<Element> currentContent) {
|
||||
return currentContentToParagraph(currentContent, false, true, tag, ctx);
|
||||
}
|
||||
|
||||
public boolean isStackOwner() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.itextpdf.tool.xml.html;
|
||||
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.WorkerContext;
|
||||
import java.util.List;
|
||||
|
||||
public interface TagProcessor {
|
||||
List<Element> startElement(WorkerContext paramWorkerContext, Tag paramTag);
|
||||
|
||||
List<Element> content(WorkerContext paramWorkerContext, Tag paramTag, String paramString);
|
||||
|
||||
List<Element> endElement(WorkerContext paramWorkerContext, Tag paramTag, List<Element> paramList);
|
||||
|
||||
boolean isStackOwner();
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.itextpdf.tool.xml.html;
|
||||
|
||||
import com.itextpdf.tool.xml.exceptions.NoTagProcessorException;
|
||||
|
||||
public interface TagProcessorFactory {
|
||||
TagProcessor getProcessor(String paramString1, String paramString2) throws NoTagProcessorException;
|
||||
|
||||
void addProcessor(TagProcessor paramTagProcessor, String... paramVarArgs);
|
||||
|
||||
void removeProcessor(String paramString);
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
package com.itextpdf.tool.xml.html;
|
||||
|
||||
public class Tags {
|
||||
private static String defaultpackage = "com.itextpdf.tool.xml.html.";
|
||||
|
||||
private static String dummyTagProcessor = defaultpackage + "DummyTagProcessor";
|
||||
|
||||
private static String headers = defaultpackage + "Header";
|
||||
|
||||
private static String span = defaultpackage + "Span";
|
||||
|
||||
private static String nonSanitized = defaultpackage + "NonSanitizedTag";
|
||||
|
||||
private static String paragraph = defaultpackage + "ParaGraph";
|
||||
|
||||
public static final TagProcessorFactory getHtmlTagProcessorFactory() {
|
||||
DefaultTagProcessorFactory factory = new DefaultTagProcessorFactory();
|
||||
factory.addProcessor("xml", dummyTagProcessor);
|
||||
factory.addProcessor("!doctype", dummyTagProcessor);
|
||||
factory.addProcessor("html", dummyTagProcessor);
|
||||
factory.addProcessor("head", dummyTagProcessor);
|
||||
factory.addProcessor("meta", dummyTagProcessor);
|
||||
factory.addProcessor("object", dummyTagProcessor);
|
||||
factory.addProcessor("title", defaultpackage + "head.Title");
|
||||
factory.addProcessor("link", defaultpackage + "head.Link");
|
||||
factory.addProcessor("style", defaultpackage + "head.Style");
|
||||
factory.addProcessor("body", defaultpackage + "Body");
|
||||
factory.addProcessor("div", defaultpackage + "Div");
|
||||
factory.addProcessor("a", defaultpackage + "Anchor");
|
||||
factory.addProcessor("table", defaultpackage + "table.Table");
|
||||
factory.addProcessor("tr", defaultpackage + "table.TableRow");
|
||||
factory.addProcessor("td", defaultpackage + "table.TableData");
|
||||
factory.addProcessor("th", defaultpackage + "table.TableData");
|
||||
factory.addProcessor("caption", paragraph);
|
||||
factory.addProcessor("p", paragraph);
|
||||
factory.addProcessor("dt", paragraph);
|
||||
factory.addProcessor("dd", paragraph);
|
||||
factory.addProcessor("blockquote", paragraph);
|
||||
factory.addProcessor("br", defaultpackage + "Break");
|
||||
factory.addProcessor("span", span);
|
||||
factory.addProcessor("small", span);
|
||||
factory.addProcessor("big", span);
|
||||
factory.addProcessor("s", span);
|
||||
factory.addProcessor("strike", span);
|
||||
factory.addProcessor("del", span);
|
||||
factory.addProcessor("sub", span);
|
||||
factory.addProcessor("sup", span);
|
||||
factory.addProcessor("b", span);
|
||||
factory.addProcessor("strong", span);
|
||||
factory.addProcessor("font", span);
|
||||
factory.addProcessor("i", span);
|
||||
factory.addProcessor("cite", span);
|
||||
factory.addProcessor("em", span);
|
||||
factory.addProcessor("address", span);
|
||||
factory.addProcessor("dfn", span);
|
||||
factory.addProcessor("var", span);
|
||||
factory.addProcessor("pre", nonSanitized);
|
||||
factory.addProcessor("tt", nonSanitized);
|
||||
factory.addProcessor("code", nonSanitized);
|
||||
factory.addProcessor("kbd", nonSanitized);
|
||||
factory.addProcessor("samp", nonSanitized);
|
||||
factory.addProcessor("u", span);
|
||||
factory.addProcessor("ins", span);
|
||||
factory.addProcessor("img", defaultpackage + "Image");
|
||||
factory.addProcessor("ul", defaultpackage + "OrderedUnorderedList");
|
||||
factory.addProcessor("ol", defaultpackage + "OrderedUnorderedList");
|
||||
factory.addProcessor("li", defaultpackage + "OrderedUnorderedListItem");
|
||||
factory.addProcessor("h1", headers);
|
||||
factory.addProcessor("h2", headers);
|
||||
factory.addProcessor("h3", headers);
|
||||
factory.addProcessor("h4", headers);
|
||||
factory.addProcessor("h5", headers);
|
||||
factory.addProcessor("h6", headers);
|
||||
factory.addProcessor("hr", defaultpackage + "HorizontalRule");
|
||||
factory.addProcessor("label", span);
|
||||
return factory;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package com.itextpdf.tool.xml.html.head;
|
||||
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.text.log.Logger;
|
||||
import com.itextpdf.text.log.LoggerFactory;
|
||||
import com.itextpdf.tool.xml.NoCustomContextException;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.WorkerContext;
|
||||
import com.itextpdf.tool.xml.exceptions.CssResolverException;
|
||||
import com.itextpdf.tool.xml.exceptions.LocaleMessages;
|
||||
import com.itextpdf.tool.xml.html.AbstractTagProcessor;
|
||||
import com.itextpdf.tool.xml.pipeline.css.CssResolverPipeline;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Link extends AbstractTagProcessor {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Link.class);
|
||||
|
||||
public List<Element> start(WorkerContext ctx, Tag tag) {
|
||||
if ("text/css".equalsIgnoreCase(tag.getAttributes().get("type"))) {
|
||||
String href = tag.getAttributes().get("href");
|
||||
if (null != href)
|
||||
try {
|
||||
getCSSResolver(ctx).addCssFile(href, false);
|
||||
} catch (CssResolverException e) {
|
||||
LOG.error(String.format(LocaleMessages.getInstance().getMessage("html.tag.link.404"), href), e);
|
||||
} catch (NoCustomContextException e) {
|
||||
LOG.warn(String.format(LocaleMessages.getInstance().getMessage("customcontext.404.continue"), CssResolverPipeline.class.getName()));
|
||||
}
|
||||
}
|
||||
return new ArrayList<Element>(0);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package com.itextpdf.tool.xml.html.head;
|
||||
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.text.log.Level;
|
||||
import com.itextpdf.text.log.Logger;
|
||||
import com.itextpdf.text.log.LoggerFactory;
|
||||
import com.itextpdf.tool.xml.NoCustomContextException;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.WorkerContext;
|
||||
import com.itextpdf.tool.xml.exceptions.LocaleMessages;
|
||||
import com.itextpdf.tool.xml.html.AbstractTagProcessor;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Meta extends AbstractTagProcessor {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(Meta.class);
|
||||
|
||||
public List<Element> start(WorkerContext ctx, Tag tag) {
|
||||
if (null != tag.getAttributes().get("http-equiv") && "Content-Type"
|
||||
.equalsIgnoreCase(tag.getAttributes().get("http-equiv"))) {
|
||||
String content = tag.getAttributes().get("content");
|
||||
if (null != content) {
|
||||
String[] split = content.split(";");
|
||||
for (String str : split) {
|
||||
if (str.contains("charset")) {
|
||||
String[] split2 = str.split("=");
|
||||
if (split2.length > 1) {
|
||||
String enc = split2[1];
|
||||
try {
|
||||
if (Charset.isSupported(enc)) {
|
||||
getHtmlPipelineContext(ctx).charSet(Charset.forName(enc));
|
||||
if (LOGGER.isLogging(Level.DEBUG))
|
||||
LOGGER.debug(
|
||||
String.format(LocaleMessages.getInstance().getMessage("html.tag.meta.cc"), enc));
|
||||
} else if (LOGGER.isLogging(Level.DEBUG)) {
|
||||
LOGGER.debug(
|
||||
String.format(LocaleMessages.getInstance().getMessage("html.tag.meta.404"), getHtmlPipelineContext(ctx)
|
||||
.charSet()));
|
||||
}
|
||||
} catch (NoCustomContextException e) {
|
||||
LOGGER.error("", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new ArrayList<Element>(0);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package com.itextpdf.tool.xml.html.head;
|
||||
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.text.log.Level;
|
||||
import com.itextpdf.text.log.Logger;
|
||||
import com.itextpdf.text.log.LoggerFactory;
|
||||
import com.itextpdf.tool.xml.NoCustomContextException;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.WorkerContext;
|
||||
import com.itextpdf.tool.xml.exceptions.CssResolverException;
|
||||
import com.itextpdf.tool.xml.exceptions.LocaleMessages;
|
||||
import com.itextpdf.tool.xml.html.AbstractTagProcessor;
|
||||
import com.itextpdf.tool.xml.pipeline.css.CSSResolver;
|
||||
import com.itextpdf.tool.xml.pipeline.css.CssResolverPipeline;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Style extends AbstractTagProcessor {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Style.class);
|
||||
|
||||
public List<Element> content(WorkerContext ctx, Tag tag, String content) {
|
||||
try {
|
||||
CSSResolver cssResolver = getCSSResolver(ctx);
|
||||
cssResolver.addCss(content, false);
|
||||
} catch (CssResolverException e) {
|
||||
LOG.error(LocaleMessages.getInstance().getMessage("html.tag.style.notparsed"), e);
|
||||
if (LOG.isLogging(Level.TRACE))
|
||||
LOG.trace(content);
|
||||
} catch (NoCustomContextException e) {
|
||||
LOG.warn(String.format(LocaleMessages.getInstance().getMessage("customcontext.404.continue"), CssResolverPipeline.class.getName()));
|
||||
}
|
||||
return new ArrayList<Element>(0);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.itextpdf.tool.xml.html.head;
|
||||
|
||||
import com.itextpdf.text.Document;
|
||||
import com.itextpdf.text.DocumentException;
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.text.WritableDirectElement;
|
||||
import com.itextpdf.text.pdf.PdfWriter;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.WorkerContext;
|
||||
import com.itextpdf.tool.xml.html.AbstractTagProcessor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Title extends AbstractTagProcessor {
|
||||
public List<Element> content(WorkerContext ctx, Tag tag, final String content) {
|
||||
ArrayList<Element> list = new ArrayList<Element>(1);
|
||||
list.add(new WritableDirectElement() {
|
||||
public void write(PdfWriter writer, Document doc) throws DocumentException {
|
||||
doc.addTitle(content);
|
||||
}
|
||||
});
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.itextpdf.tool.xml.html.head;
|
||||
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.text.log.Level;
|
||||
import com.itextpdf.text.log.Logger;
|
||||
import com.itextpdf.text.log.LoggerFactory;
|
||||
import com.itextpdf.tool.xml.NoCustomContextException;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.WorkerContext;
|
||||
import com.itextpdf.tool.xml.exceptions.LocaleMessages;
|
||||
import com.itextpdf.tool.xml.exceptions.RuntimeWorkerException;
|
||||
import com.itextpdf.tool.xml.html.AbstractTagProcessor;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class XML extends AbstractTagProcessor {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(XML.class);
|
||||
|
||||
public List<Element> start(WorkerContext ctx, Tag tag) {
|
||||
String enc = tag.getAttributes().get("encoding");
|
||||
if (null != enc)
|
||||
try {
|
||||
if (Charset.isSupported(enc)) {
|
||||
getHtmlPipelineContext(ctx).charSet(Charset.forName(enc));
|
||||
if (LOGGER.isLogging(Level.DEBUG))
|
||||
LOGGER.debug(
|
||||
String.format(LocaleMessages.getInstance().getMessage("html.tag.meta.cc"), enc));
|
||||
} else if (LOGGER.isLogging(Level.DEBUG)) {
|
||||
LOGGER.debug(
|
||||
String.format(LocaleMessages.getInstance().getMessage("html.tag.meta.404"), getHtmlPipelineContext(ctx)
|
||||
.charSet()));
|
||||
}
|
||||
} catch (NoCustomContextException e) {
|
||||
throw new RuntimeWorkerException(LocaleMessages.getInstance().getMessage("customcontext.404"));
|
||||
}
|
||||
return new ArrayList<Element>(0);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package com.itextpdf.tool.xml.html.pdfelement;
|
||||
|
||||
import com.itextpdf.text.pdf.PdfPCell;
|
||||
import com.itextpdf.tool.xml.html.table.TableStyleValues;
|
||||
|
||||
public class HtmlCell extends PdfPCell {
|
||||
private float fixedWidth;
|
||||
|
||||
private TableStyleValues values = new TableStyleValues();
|
||||
|
||||
public HtmlCell() {
|
||||
this.fixedWidth = 0.0F;
|
||||
setPaddingLeft(0.0F);
|
||||
setPaddingRight(0.0F);
|
||||
setPaddingTop(0.0F);
|
||||
setPaddingBottom(0.0F);
|
||||
setUseAscender(true);
|
||||
setUseDescender(true);
|
||||
}
|
||||
|
||||
public HtmlCell(PdfPCell pdfPCell, boolean b) {
|
||||
this(pdfPCell);
|
||||
this.values.setLastInRow(b);
|
||||
}
|
||||
|
||||
public HtmlCell(PdfPCell pdfPCell) {
|
||||
super(pdfPCell);
|
||||
}
|
||||
|
||||
public void setFixedWidth(float fixedWidth) {
|
||||
this.fixedWidth = fixedWidth;
|
||||
}
|
||||
|
||||
public float getFixedWidth() {
|
||||
return this.fixedWidth;
|
||||
}
|
||||
|
||||
public TableStyleValues getCellValues() {
|
||||
return this.values;
|
||||
}
|
||||
|
||||
public void setCellValues(TableStyleValues values) {
|
||||
this.values = values;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
package com.itextpdf.tool.xml.html.pdfelement;
|
||||
|
||||
import com.itextpdf.text.Chunk;
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.text.Font;
|
||||
import com.itextpdf.text.List;
|
||||
import com.itextpdf.text.Paragraph;
|
||||
import com.itextpdf.text.Phrase;
|
||||
import com.itextpdf.text.api.Indentable;
|
||||
|
||||
public class NoNewLineParagraph extends Phrase implements Indentable {
|
||||
private static final long serialVersionUID = -8392940968188620772L;
|
||||
|
||||
protected int alignment = -1;
|
||||
|
||||
protected float indentationLeft;
|
||||
|
||||
protected float indentationRight;
|
||||
|
||||
private float firstLineIndent = 0.0F;
|
||||
|
||||
protected float spacingBefore;
|
||||
|
||||
protected float spacingAfter;
|
||||
|
||||
private float extraParagraphSpace = 0.0F;
|
||||
|
||||
protected boolean keeptogether = false;
|
||||
|
||||
public NoNewLineParagraph(float leading) {
|
||||
super(leading);
|
||||
}
|
||||
|
||||
public NoNewLineParagraph(Chunk chunk) {
|
||||
super(chunk);
|
||||
}
|
||||
|
||||
public NoNewLineParagraph(float leading, Chunk chunk) {
|
||||
super(leading, chunk);
|
||||
}
|
||||
|
||||
public NoNewLineParagraph(String string) {
|
||||
super(string);
|
||||
}
|
||||
|
||||
public NoNewLineParagraph(String string, Font font) {
|
||||
super(string, font);
|
||||
}
|
||||
|
||||
public NoNewLineParagraph(float leading, String string) {
|
||||
super(leading, string);
|
||||
}
|
||||
|
||||
public NoNewLineParagraph(float leading, String string, Font font) {
|
||||
super(leading, string, font);
|
||||
}
|
||||
|
||||
public NoNewLineParagraph(Phrase phrase) {
|
||||
super(phrase);
|
||||
if (phrase instanceof NoNewLineParagraph) {
|
||||
NoNewLineParagraph p = (NoNewLineParagraph)phrase;
|
||||
this.alignment = p.getAlignment();
|
||||
this.indentationLeft = p.getIndentationLeft();
|
||||
this.indentationRight = p.getIndentationRight();
|
||||
this.firstLineIndent = p.getFirstLineIndent();
|
||||
this.spacingAfter = p.getSpacingAfter();
|
||||
this.spacingBefore = p.getSpacingBefore();
|
||||
this.extraParagraphSpace = p.getExtraParagraphSpace();
|
||||
}
|
||||
if (phrase instanceof Paragraph) {
|
||||
Paragraph p = (Paragraph)phrase;
|
||||
setAlignment(p.getAlignment());
|
||||
setIndentationLeft(p.getIndentationLeft());
|
||||
setIndentationRight(p.getIndentationRight());
|
||||
setFirstLineIndent(p.getFirstLineIndent());
|
||||
setSpacingAfter(p.getSpacingAfter());
|
||||
setSpacingBefore(p.getSpacingBefore());
|
||||
setExtraParagraphSpace(p.getExtraParagraphSpace());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean add(Element o) {
|
||||
if (o instanceof List) {
|
||||
List list = (List)o;
|
||||
list.setIndentationLeft(list.getIndentationLeft() + this.indentationLeft);
|
||||
list.setIndentationRight(this.indentationRight);
|
||||
return super.add((Element)list);
|
||||
}
|
||||
if (o instanceof com.itextpdf.text.Image) {
|
||||
addSpecial(o);
|
||||
return true;
|
||||
}
|
||||
return super.add(o);
|
||||
}
|
||||
|
||||
public void setAlignment(int alignment) {
|
||||
this.alignment = alignment;
|
||||
}
|
||||
|
||||
public void setIndentationLeft(float indentation) {
|
||||
this.indentationLeft = indentation;
|
||||
}
|
||||
|
||||
public void setIndentationRight(float indentation) {
|
||||
this.indentationRight = indentation;
|
||||
}
|
||||
|
||||
public void setFirstLineIndent(float firstLineIndent) {
|
||||
this.firstLineIndent = firstLineIndent;
|
||||
}
|
||||
|
||||
public void setSpacingBefore(float spacing) {
|
||||
this.spacingBefore = spacing;
|
||||
}
|
||||
|
||||
public void setSpacingAfter(float spacing) {
|
||||
this.spacingAfter = spacing;
|
||||
}
|
||||
|
||||
public void setKeepTogether(boolean keeptogether) {
|
||||
this.keeptogether = keeptogether;
|
||||
}
|
||||
|
||||
public boolean getKeepTogether() {
|
||||
return this.keeptogether;
|
||||
}
|
||||
|
||||
public int getAlignment() {
|
||||
return this.alignment;
|
||||
}
|
||||
|
||||
public float getIndentationLeft() {
|
||||
return this.indentationLeft;
|
||||
}
|
||||
|
||||
public float getIndentationRight() {
|
||||
return this.indentationRight;
|
||||
}
|
||||
|
||||
public float getFirstLineIndent() {
|
||||
return this.firstLineIndent;
|
||||
}
|
||||
|
||||
public float getSpacingBefore() {
|
||||
return this.spacingBefore;
|
||||
}
|
||||
|
||||
public float getSpacingAfter() {
|
||||
return this.spacingAfter;
|
||||
}
|
||||
|
||||
public float getExtraParagraphSpace() {
|
||||
return this.extraParagraphSpace;
|
||||
}
|
||||
|
||||
public void setExtraParagraphSpace(float extraParagraphSpace) {
|
||||
this.extraParagraphSpace = extraParagraphSpace;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public float spacingBefore() {
|
||||
return getSpacingBefore();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public float spacingAfter() {
|
||||
return this.spacingAfter;
|
||||
}
|
||||
|
||||
public NoNewLineParagraph() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package com.itextpdf.tool.xml.html.pdfelement;
|
||||
|
||||
import com.itextpdf.text.Chunk;
|
||||
import com.itextpdf.text.pdf.draw.DrawInterface;
|
||||
import com.itextpdf.text.pdf.draw.VerticalPositionMark;
|
||||
|
||||
public class TabbedChunk extends Chunk {
|
||||
private int tabCount;
|
||||
|
||||
private String alignment;
|
||||
|
||||
public TabbedChunk(String content) {
|
||||
super(content);
|
||||
}
|
||||
|
||||
public TabbedChunk(VerticalPositionMark verticalPositionMark, float parseToPt, boolean b, String alignment) {
|
||||
super((DrawInterface)verticalPositionMark, parseToPt, b);
|
||||
this.alignment = alignment;
|
||||
}
|
||||
|
||||
public TabbedChunk(VerticalPositionMark verticalPositionMark, float parseToPt, boolean b) {
|
||||
super((DrawInterface)verticalPositionMark, parseToPt, b);
|
||||
}
|
||||
|
||||
public void setTabCount(int tabCount) {
|
||||
this.tabCount = tabCount;
|
||||
}
|
||||
|
||||
public int getTabCount() {
|
||||
return this.tabCount;
|
||||
}
|
||||
|
||||
public void setAlignment(String alignment) {
|
||||
this.alignment = alignment;
|
||||
}
|
||||
|
||||
public String getAlignment() {
|
||||
return this.alignment;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
package com.itextpdf.tool.xml.html.table;
|
||||
|
||||
import com.itextpdf.text.BaseColor;
|
||||
import com.itextpdf.text.Rectangle;
|
||||
import com.itextpdf.text.pdf.PdfContentByte;
|
||||
import com.itextpdf.text.pdf.PdfPCell;
|
||||
import com.itextpdf.text.pdf.PdfPCellEvent;
|
||||
|
||||
public class CellSpacingEvent implements PdfPCellEvent {
|
||||
private final TableStyleValues styleValues;
|
||||
|
||||
public CellSpacingEvent(TableStyleValues styleValues) {
|
||||
this.styleValues = styleValues;
|
||||
}
|
||||
|
||||
public void cellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases) {
|
||||
float effectivePadding = this.styleValues.getBorderWidthLeft() / 2.0F + this.styleValues.getHorBorderSpacing();
|
||||
float x1 = position.getLeft() + effectivePadding;
|
||||
if (this.styleValues.isLastInRow()) {
|
||||
effectivePadding = this.styleValues.getBorderWidthRight() / 2.0F + this.styleValues.getHorBorderSpacing();
|
||||
} else {
|
||||
effectivePadding = this.styleValues.getBorderWidthRight() / 2.0F;
|
||||
}
|
||||
float x2 = position.getRight() - effectivePadding;
|
||||
effectivePadding = this.styleValues.getBorderWidthTop() / 2.0F + this.styleValues.getVerBorderSpacing();
|
||||
float y1 = position.getTop() - effectivePadding;
|
||||
effectivePadding = this.styleValues.getBorderWidthBottom() / 2.0F;
|
||||
float y2 = position.getBottom() + effectivePadding;
|
||||
PdfContentByte cb = canvases[2];
|
||||
BaseColor color = this.styleValues.getBackground();
|
||||
if (color != null) {
|
||||
cb.setColorStroke(color);
|
||||
cb.setColorFill(color);
|
||||
cb.rectangle(x1, y1, x2 - x1, y2 - y1);
|
||||
cb.fill();
|
||||
}
|
||||
BaseColor borderColor = this.styleValues.getBorderColorLeft();
|
||||
float width = this.styleValues.getBorderWidthLeft();
|
||||
if (borderColor != null && width != 0.0F) {
|
||||
cb.setLineWidth(width);
|
||||
cb.setColorStroke(borderColor);
|
||||
cb.moveTo(x1, y1);
|
||||
cb.lineTo(x1, y2);
|
||||
cb.stroke();
|
||||
}
|
||||
borderColor = this.styleValues.getBorderColorBottom();
|
||||
width = this.styleValues.getBorderWidthBottom();
|
||||
if (borderColor != null && width != 0.0F) {
|
||||
cb.setLineWidth(width);
|
||||
cb.setColorStroke(borderColor);
|
||||
cb.moveTo(x1, y2);
|
||||
cb.lineTo(x2, y2);
|
||||
cb.stroke();
|
||||
}
|
||||
borderColor = this.styleValues.getBorderColorRight();
|
||||
width = this.styleValues.getBorderWidthRight();
|
||||
if (borderColor != null && width != 0.0F) {
|
||||
cb.setLineWidth(width);
|
||||
cb.setColorStroke(borderColor);
|
||||
cb.moveTo(x2, y2);
|
||||
cb.lineTo(x2, y1);
|
||||
cb.stroke();
|
||||
}
|
||||
borderColor = this.styleValues.getBorderColorTop();
|
||||
width = this.styleValues.getBorderWidthTop();
|
||||
if (borderColor != null && width != 0.0F) {
|
||||
cb.setLineWidth(width);
|
||||
cb.setColorStroke(borderColor);
|
||||
cb.moveTo(x2, y1);
|
||||
cb.lineTo(x1, y1);
|
||||
cb.stroke();
|
||||
}
|
||||
cb.resetRGBColorStroke();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,681 @@
|
|||
package com.itextpdf.tool.xml.html.table;
|
||||
|
||||
import com.itextpdf.text.BaseColor;
|
||||
import com.itextpdf.text.Chunk;
|
||||
import com.itextpdf.text.DocumentException;
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.text.Image;
|
||||
import com.itextpdf.text.ListItem;
|
||||
import com.itextpdf.text.Paragraph;
|
||||
import com.itextpdf.text.Phrase;
|
||||
import com.itextpdf.text.html.HtmlUtilities;
|
||||
import com.itextpdf.text.log.Level;
|
||||
import com.itextpdf.text.log.Logger;
|
||||
import com.itextpdf.text.log.LoggerFactory;
|
||||
import com.itextpdf.text.pdf.PdfDiv;
|
||||
import com.itextpdf.text.pdf.PdfPCell;
|
||||
import com.itextpdf.text.pdf.PdfPRow;
|
||||
import com.itextpdf.text.pdf.PdfPTable;
|
||||
import com.itextpdf.text.pdf.PdfPTableEvent;
|
||||
import com.itextpdf.tool.xml.NoCustomContextException;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.WorkerContext;
|
||||
import com.itextpdf.tool.xml.css.CSS;
|
||||
import com.itextpdf.tool.xml.css.CssUtils;
|
||||
import com.itextpdf.tool.xml.css.FontSizeTranslator;
|
||||
import com.itextpdf.tool.xml.css.HeightCalculator;
|
||||
import com.itextpdf.tool.xml.css.WidthCalculator;
|
||||
import com.itextpdf.tool.xml.exceptions.LocaleMessages;
|
||||
import com.itextpdf.tool.xml.exceptions.RuntimeWorkerException;
|
||||
import com.itextpdf.tool.xml.html.AbstractTagProcessor;
|
||||
import com.itextpdf.tool.xml.html.pdfelement.HtmlCell;
|
||||
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class Table extends AbstractTagProcessor {
|
||||
public static final float DEFAULT_CELL_BORDER_WIDTH = 0.75F;
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Table.class);
|
||||
|
||||
private static final CssUtils utils = CssUtils.getInstance();
|
||||
|
||||
private static final FontSizeTranslator fst = FontSizeTranslator.getInstance();
|
||||
|
||||
private final class NormalRowComparator implements Comparator<TableRowElement> {
|
||||
private NormalRowComparator() {}
|
||||
|
||||
public int compare(TableRowElement o1, TableRowElement o2) {
|
||||
return o1.getPlace().getNormal().compareTo(o2.getPlace().getNormal());
|
||||
}
|
||||
}
|
||||
|
||||
private final class RepeatedRowComparator implements Comparator<TableRowElement> {
|
||||
private RepeatedRowComparator() {}
|
||||
|
||||
public int compare(TableRowElement o1, TableRowElement o2) {
|
||||
return o1.getPlace().getRepeated().compareTo(o2.getPlace().getRepeated());
|
||||
}
|
||||
}
|
||||
|
||||
public List<Element> end(WorkerContext ctx, Tag tag, List<Element> currentContent) {
|
||||
try {
|
||||
boolean percentage = false;
|
||||
String widthValue = tag.getCSS().get("width");
|
||||
if (widthValue == null)
|
||||
widthValue = tag.getAttributes().get("width");
|
||||
if (widthValue != null && widthValue.trim().endsWith("%"))
|
||||
percentage = true;
|
||||
int numberOfColumns = 0;
|
||||
List<TableRowElement> tableRows = new ArrayList<TableRowElement>(currentContent.size());
|
||||
List<Element> invalidRowElements = new ArrayList<Element>(1);
|
||||
String repeatHeader = tag.getCSS().get("repeat-header");
|
||||
String repeatFooter = tag.getCSS().get("repeat-footer");
|
||||
int headerRows = 0;
|
||||
int footerRows = 0;
|
||||
for (Element e : currentContent) {
|
||||
int localNumCols = 0;
|
||||
if (e instanceof TableRowElement) {
|
||||
TableRowElement tableRowElement = (TableRowElement)e;
|
||||
for (HtmlCell cell : tableRowElement.getContent())
|
||||
localNumCols += cell.getColspan();
|
||||
if (localNumCols > numberOfColumns)
|
||||
numberOfColumns = localNumCols;
|
||||
tableRows.add(tableRowElement);
|
||||
if (repeatHeader != null && repeatHeader.equalsIgnoreCase("yes") &&
|
||||
tableRowElement.getPlace().equals(TableRowElement.Place.HEADER))
|
||||
headerRows++;
|
||||
if (repeatFooter != null && repeatFooter.equalsIgnoreCase("yes") &&
|
||||
tableRowElement.getPlace().equals(TableRowElement.Place.FOOTER))
|
||||
footerRows++;
|
||||
continue;
|
||||
}
|
||||
invalidRowElements.add(e);
|
||||
}
|
||||
if (repeatFooter == null || !repeatFooter.equalsIgnoreCase("yes")) {
|
||||
Collections.<TableRowElement>sort(tableRows, new NormalRowComparator());
|
||||
} else {
|
||||
Collections.<TableRowElement>sort(tableRows, new RepeatedRowComparator());
|
||||
}
|
||||
PdfPTable table = intPdfPTable(numberOfColumns);
|
||||
table.setHeaderRows(headerRows + footerRows);
|
||||
table.setFooterRows(footerRows);
|
||||
if (tag.getAttributes().containsKey("align")) {
|
||||
String value = tag.getAttributes().get("align");
|
||||
table.setHorizontalAlignment(CSS.getElementAlignment(value));
|
||||
}
|
||||
int direction = getRunDirection(tag);
|
||||
table.setRunDirection(direction);
|
||||
for (Map.Entry<String, String> entry : tag.getCSS().entrySet()) {
|
||||
if (entry.getKey().equalsIgnoreCase("page-break-inside") &&
|
||||
entry.getValue().equalsIgnoreCase("avoid"))
|
||||
table.setKeepTogether(true);
|
||||
}
|
||||
TableStyleValues styleValues = setStyleValues(tag);
|
||||
table.setTableEvent(new TableBorderEvent(styleValues));
|
||||
setVerticalMargin(table, tag, styleValues, ctx);
|
||||
widenLastCell(tableRows, styleValues.getHorBorderSpacing());
|
||||
float[] columnWidths = new float[numberOfColumns];
|
||||
float[] widestWords = new float[numberOfColumns];
|
||||
float[] fixedWidths = new float[numberOfColumns];
|
||||
float[] colspanWidestWords = new float[numberOfColumns];
|
||||
int[] rowspanValue = new int[numberOfColumns];
|
||||
float largestColumn = 0.0F;
|
||||
float largestColspanColumn = 0.0F;
|
||||
int indexOfLargestColumn = -1;
|
||||
int indexOfLargestColspanColumn = -1;
|
||||
for (TableRowElement row : tableRows) {
|
||||
int column = 0;
|
||||
for (HtmlCell cell : row.getContent()) {
|
||||
while (column < numberOfColumns && rowspanValue[column] > 0) {
|
||||
rowspanValue[column] = rowspanValue[column] - 1;
|
||||
column++;
|
||||
}
|
||||
if (cell.getRowspan() > 1 && column != numberOfColumns - 1 && column < rowspanValue.length)
|
||||
rowspanValue[column] = cell.getRowspan() - 1;
|
||||
int colspan = cell.getColspan();
|
||||
if (cell.getFixedWidth() != 0.0F) {
|
||||
float fixedWidth = cell.getFixedWidth() + getCellStartWidth(cell);
|
||||
float colSpanWidthSum = 0.0F;
|
||||
int nonZeroColspanCols = 0;
|
||||
for (int i = column; i < column + colspan && i < numberOfColumns; i++) {
|
||||
colSpanWidthSum += fixedWidths[i];
|
||||
if (fixedWidths[i] != 0.0F)
|
||||
nonZeroColspanCols++;
|
||||
}
|
||||
for (int c = column; c < column + colspan && c < numberOfColumns; c++) {
|
||||
if (fixedWidths[c] == 0.0F) {
|
||||
fixedWidths[c] = (fixedWidth - colSpanWidthSum) / (float)(colspan - nonZeroColspanCols);
|
||||
columnWidths[c] = (fixedWidth - colSpanWidthSum) / (float)(colspan - nonZeroColspanCols);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cell.getCompositeElements() != null) {
|
||||
float[] widthValues = setCellWidthAndWidestWord(cell);
|
||||
float cellWidth = widthValues[0] / (float)colspan;
|
||||
float widestWordOfCell = widthValues[1] / (float)colspan;
|
||||
for (int i = 0; i < colspan; i++) {
|
||||
int c = column + i;
|
||||
if (c < numberOfColumns) {
|
||||
if (fixedWidths[c] == 0.0F && cellWidth > columnWidths[c]) {
|
||||
columnWidths[c] = cellWidth;
|
||||
if (colspan == 1) {
|
||||
if (cellWidth > largestColumn) {
|
||||
largestColumn = cellWidth;
|
||||
indexOfLargestColumn = c;
|
||||
}
|
||||
} else if (cellWidth > largestColspanColumn) {
|
||||
largestColspanColumn = cellWidth;
|
||||
indexOfLargestColspanColumn = c;
|
||||
}
|
||||
}
|
||||
if (colspan == 1) {
|
||||
if (widestWordOfCell > widestWords[c])
|
||||
widestWords[c] = widestWordOfCell;
|
||||
} else if (widestWordOfCell > colspanWidestWords[c]) {
|
||||
colspanWidestWords[c] = widestWordOfCell;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (colspan > 1) {
|
||||
if (LOG.isLogging(Level.TRACE))
|
||||
LOG.trace(String.format(LocaleMessages.getInstance().getMessage("html.tag.table.colspan"), colspan));
|
||||
column += colspan - 1;
|
||||
}
|
||||
column++;
|
||||
}
|
||||
}
|
||||
if (indexOfLargestColumn == -1) {
|
||||
indexOfLargestColumn = indexOfLargestColspanColumn;
|
||||
if (indexOfLargestColumn == -1)
|
||||
indexOfLargestColumn = 0;
|
||||
for (int column = 0; column < numberOfColumns; column++)
|
||||
widestWords[column] = colspanWidestWords[column];
|
||||
}
|
||||
float outerWidth = getTableOuterWidth(tag, styleValues.getHorBorderSpacing(), ctx);
|
||||
float initialTotalWidth = getTableWidth(columnWidths, 0.0F);
|
||||
float targetWidth = 0.0F;
|
||||
HtmlPipelineContext htmlPipelineContext = getHtmlPipelineContext(ctx);
|
||||
float max = htmlPipelineContext.getPageSize().getWidth() - outerWidth;
|
||||
boolean tableWidthFixed = false;
|
||||
if (tag.getAttributes().get("width") != null || tag.getCSS().get("width") != null) {
|
||||
targetWidth = new WidthCalculator().getWidth(tag, htmlPipelineContext.getRootTags(), htmlPipelineContext.getPageSize().getWidth(), initialTotalWidth);
|
||||
if (targetWidth > max)
|
||||
targetWidth = max;
|
||||
tableWidthFixed = true;
|
||||
} else if (initialTotalWidth <= max) {
|
||||
targetWidth = initialTotalWidth;
|
||||
} else if (null == tag.getParent() || (null != tag.getParent() && htmlPipelineContext.getRootTags().contains(tag.getParent().getName()))) {
|
||||
targetWidth = max;
|
||||
} else {
|
||||
targetWidth = getTableWidth(columnWidths, outerWidth);
|
||||
}
|
||||
float totalFixedColumnWidth = getTableWidth(fixedWidths, 0.0F);
|
||||
float targetPercentage = 0.0F;
|
||||
if (totalFixedColumnWidth == initialTotalWidth) {
|
||||
targetPercentage = targetWidth / initialTotalWidth;
|
||||
if (initialTotalWidth > targetWidth) {
|
||||
for (int column = 0; column < columnWidths.length; column++)
|
||||
columnWidths[column] = columnWidths[column] * targetPercentage;
|
||||
} else if (tableWidthFixed && targetPercentage != 1.0F) {
|
||||
for (int column = 0; column < columnWidths.length; column++)
|
||||
columnWidths[column] = columnWidths[column] * targetPercentage;
|
||||
}
|
||||
} else {
|
||||
targetPercentage = (targetWidth - totalFixedColumnWidth) / (initialTotalWidth - totalFixedColumnWidth);
|
||||
if (initialTotalWidth > targetWidth) {
|
||||
float leftToReduce = 0.0F;
|
||||
for (int column = 0; column < columnWidths.length; column++) {
|
||||
if (fixedWidths[column] == 0.0F) {
|
||||
if (widestWords[column] <= columnWidths[column] * targetPercentage) {
|
||||
columnWidths[column] = columnWidths[column] * targetPercentage;
|
||||
} else {
|
||||
columnWidths[column] = widestWords[column];
|
||||
leftToReduce += widestWords[column] - columnWidths[column] * targetPercentage;
|
||||
}
|
||||
} else if (fixedWidths[column] < widestWords[column]) {
|
||||
columnWidths[column] = widestWords[column];
|
||||
leftToReduce += widestWords[column] - fixedWidths[column];
|
||||
}
|
||||
}
|
||||
if (leftToReduce != 0.0F)
|
||||
if (widestWords[indexOfLargestColumn] <= columnWidths[indexOfLargestColumn] - leftToReduce) {
|
||||
columnWidths[indexOfLargestColumn] = columnWidths[indexOfLargestColumn] - leftToReduce;
|
||||
} else {
|
||||
for (int i = 0; leftToReduce != 0.0F && i < columnWidths.length; i++) {
|
||||
if (fixedWidths[i] == 0.0F && columnWidths[i] > widestWords[i]) {
|
||||
float difference = columnWidths[i] - widestWords[i];
|
||||
if (difference <= leftToReduce) {
|
||||
leftToReduce -= difference;
|
||||
columnWidths[i] = widestWords[i];
|
||||
} else {
|
||||
columnWidths[i] = columnWidths[i] - leftToReduce;
|
||||
leftToReduce = 0.0F;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (leftToReduce != 0.0F) {
|
||||
float pageWidth = getHtmlPipelineContext(ctx).getPageSize().getWidth();
|
||||
if (getTableWidth(widestWords, outerWidth) < pageWidth) {
|
||||
targetWidth = getTableWidth(widestWords, outerWidth);
|
||||
leftToReduce = 0.0F;
|
||||
} else {
|
||||
targetWidth = pageWidth - outerWidth;
|
||||
leftToReduce = 0.0F;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (initialTotalWidth < targetWidth) {
|
||||
for (int column = 0; column < columnWidths.length; column++) {
|
||||
if (fixedWidths[column] == 0.0F)
|
||||
columnWidths[column] = columnWidths[column] * targetPercentage;
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
table.setTotalWidth(columnWidths);
|
||||
table.setLockedWidth(true);
|
||||
table.getDefaultCell().setBorder(0);
|
||||
} catch (DocumentException e) {
|
||||
throw new RuntimeWorkerException(LocaleMessages.getInstance().getMessage("customcontext.404"), e);
|
||||
}
|
||||
Float tableHeight = new HeightCalculator().getHeight(tag, getHtmlPipelineContext(ctx).getPageSize().getHeight());
|
||||
Float tableRowHeight = null;
|
||||
if (tableHeight != null && tableHeight > 0.0F)
|
||||
tableRowHeight = tableHeight / (float)tableRows.size();
|
||||
int rowNumber = 0;
|
||||
for (TableRowElement row : tableRows) {
|
||||
int columnNumber = -1;
|
||||
Float computedRowHeight = null;
|
||||
List<HtmlCell> rowContent = row.getContent();
|
||||
if (rowContent.size() < 1)
|
||||
continue;
|
||||
for (HtmlCell cell : rowContent) {
|
||||
List<Element> compositeElements = cell.getCompositeElements();
|
||||
if (compositeElements != null)
|
||||
for (Element baseLevel : compositeElements) {
|
||||
if (baseLevel instanceof PdfPTable) {
|
||||
TableStyleValues cellValues = cell.getCellValues();
|
||||
float totalBordersWidth = cellValues.isLastInRow() ? (
|
||||
styleValues.getHorBorderSpacing() * 2.0F) :
|
||||
styleValues.getHorBorderSpacing();
|
||||
totalBordersWidth += cellValues.getBorderWidthLeft() +
|
||||
cellValues.getBorderWidthRight();
|
||||
float columnWidth = 0.0F;
|
||||
for (int currentColumnNumber = columnNumber + 1; currentColumnNumber <= columnNumber + cell.getColspan(); currentColumnNumber++)
|
||||
columnWidth += columnWidths[currentColumnNumber];
|
||||
PdfPTableEvent tableEvent = ((PdfPTable)baseLevel).getTableEvent();
|
||||
TableStyleValues innerStyleValues = ((TableBorderEvent)tableEvent)
|
||||
.getTableStyleValues();
|
||||
totalBordersWidth += innerStyleValues.getBorderWidthLeft();
|
||||
totalBordersWidth += innerStyleValues.getBorderWidthRight();
|
||||
((PdfPTable)baseLevel).setTotalWidth(columnWidth - totalBordersWidth);
|
||||
}
|
||||
}
|
||||
columnNumber += cell.getColspan();
|
||||
table.addCell(cell);
|
||||
}
|
||||
table.completeRow();
|
||||
if ((computedRowHeight == null || computedRowHeight <= 0.0F) && tableRowHeight != null)
|
||||
computedRowHeight = tableRowHeight;
|
||||
if (computedRowHeight != null && computedRowHeight > 0.0F) {
|
||||
float rowHeight = table.getRow(rowNumber).getMaxHeights();
|
||||
if (rowHeight < computedRowHeight) {
|
||||
table.getRow(rowNumber).setMaxHeights(computedRowHeight.floatValue());
|
||||
} else if (tableRowHeight != null && tableRowHeight < rowHeight) {
|
||||
tableRowHeight = (tableHeight - rowHeight - (float)rowNumber * tableRowHeight) /
|
||||
(float)(tableRows.size() - rowNumber - 1);
|
||||
}
|
||||
}
|
||||
rowNumber++;
|
||||
}
|
||||
if (percentage) {
|
||||
table.setWidthPercentage(utils.parsePxInCmMmPcToPt(widthValue));
|
||||
table.setLockedWidth(false);
|
||||
}
|
||||
List<Element> elems = new ArrayList<Element>();
|
||||
if (invalidRowElements.size() > 0) {
|
||||
int i = 0;
|
||||
Tag captionTag = tag.getChildren().get(i++);
|
||||
while (!captionTag.getName().equalsIgnoreCase("caption") && i < tag.getChildren().size()) {
|
||||
captionTag = tag.getChildren().get(i);
|
||||
i++;
|
||||
}
|
||||
String captionSideValue = captionTag.getCSS().get("caption-side");
|
||||
if (captionSideValue != null && captionSideValue.equalsIgnoreCase("bottom")) {
|
||||
elems.add(table);
|
||||
elems.addAll(invalidRowElements);
|
||||
} else {
|
||||
elems.addAll(invalidRowElements);
|
||||
elems.add(table);
|
||||
}
|
||||
} else {
|
||||
elems.add(table);
|
||||
}
|
||||
return elems;
|
||||
} catch (NoCustomContextException e) {
|
||||
throw new RuntimeWorkerException(LocaleMessages.getInstance().getMessage("customcontext.404"), e);
|
||||
}
|
||||
}
|
||||
|
||||
protected PdfPTable intPdfPTable(int numberOfColumn) {
|
||||
PdfPTable table = new PdfPTable(numberOfColumn);
|
||||
table.setHorizontalAlignment(0);
|
||||
table.setSplitLate(false);
|
||||
return table;
|
||||
}
|
||||
|
||||
private float calculateTargetWidth(Tag tag, float[] columnWidths, float outerWidth, WorkerContext ctx) throws NoCustomContextException {
|
||||
float targetWidth = 0.0F;
|
||||
HtmlPipelineContext htmlPipelineContext = getHtmlPipelineContext(ctx);
|
||||
float max = htmlPipelineContext.getPageSize().getWidth() - outerWidth;
|
||||
float start = getTableWidth(columnWidths, 0.0F);
|
||||
if (tag.getAttributes().get("width") != null || tag.getCSS().get("width") != null) {
|
||||
targetWidth = new WidthCalculator().getWidth(tag, htmlPipelineContext.getRootTags(),
|
||||
htmlPipelineContext.getPageSize().getWidth());
|
||||
if (targetWidth > max)
|
||||
targetWidth = max;
|
||||
} else if (start <= max) {
|
||||
targetWidth = start;
|
||||
} else if (null == tag.getParent() || (null !=
|
||||
tag.getParent() && htmlPipelineContext.getRootTags().contains(tag.getParent().getName()))) {
|
||||
targetWidth = max;
|
||||
} else {
|
||||
targetWidth = getTableWidth(columnWidths, outerWidth);
|
||||
}
|
||||
return targetWidth;
|
||||
}
|
||||
|
||||
private void widenLastCell(List<TableRowElement> tableRows, float horBorderSpacing) {
|
||||
for (TableRowElement row : tableRows) {
|
||||
List<HtmlCell> cells = row.getContent();
|
||||
if (cells.size() < 1)
|
||||
continue;
|
||||
HtmlCell last = cells.get(cells.size() - 1);
|
||||
last.getCellValues().setLastInRow(true);
|
||||
last.setPaddingRight(last.getPaddingRight() + horBorderSpacing);
|
||||
}
|
||||
}
|
||||
|
||||
public static TableStyleValues setStyleValues(Tag tag) {
|
||||
TableStyleValues styleValues = new TableStyleValues();
|
||||
Map<String, String> css = tag.getCSS();
|
||||
Map<String, String> attributes = tag.getAttributes();
|
||||
if (attributes.containsKey("border")) {
|
||||
styleValues.setBorderColor(BaseColor.BLACK);
|
||||
String borderValue = attributes.get("border");
|
||||
if ("".equals(borderValue)) {
|
||||
styleValues.setBorderWidth(0.75F);
|
||||
} else {
|
||||
styleValues.setBorderWidth(utils.parsePxInCmMmPcToPt(borderValue));
|
||||
}
|
||||
} else {
|
||||
for (Map.Entry<String, String> entry : css.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
if (key.equalsIgnoreCase("border-left-style") && "solid".equalsIgnoreCase(value)) {
|
||||
styleValues.setBorderColorLeft(BaseColor.BLACK);
|
||||
styleValues.setBorderWidthLeft(0.75F);
|
||||
continue;
|
||||
}
|
||||
if (key.equalsIgnoreCase("border-right-style") && "solid".equalsIgnoreCase(value)) {
|
||||
styleValues.setBorderColorRight(BaseColor.BLACK);
|
||||
styleValues.setBorderWidthRight(0.75F);
|
||||
continue;
|
||||
}
|
||||
if (key.equalsIgnoreCase("border-top-style") && "solid".equalsIgnoreCase(value)) {
|
||||
styleValues.setBorderColorTop(BaseColor.BLACK);
|
||||
styleValues.setBorderWidthTop(0.75F);
|
||||
continue;
|
||||
}
|
||||
if (key.equalsIgnoreCase("border-bottom-style") && "solid".equalsIgnoreCase(value)) {
|
||||
styleValues.setBorderColorBottom(BaseColor.BLACK);
|
||||
styleValues.setBorderWidthBottom(0.75F);
|
||||
}
|
||||
}
|
||||
String color = css.get("border-bottom-color");
|
||||
if (color != null)
|
||||
styleValues.setBorderColorBottom(HtmlUtilities.decodeColor(color));
|
||||
color = css.get("border-top-color");
|
||||
if (color != null)
|
||||
styleValues.setBorderColorTop(HtmlUtilities.decodeColor(color));
|
||||
color = css.get("border-left-color");
|
||||
if (color != null)
|
||||
styleValues.setBorderColorLeft(HtmlUtilities.decodeColor(color));
|
||||
color = css.get("border-right-color");
|
||||
if (color != null)
|
||||
styleValues.setBorderColorRight(HtmlUtilities.decodeColor(color));
|
||||
Float width = utils.checkMetricStyle(css, "border-bottom-width");
|
||||
if (width != null)
|
||||
styleValues.setBorderWidthBottom(width.floatValue());
|
||||
width = utils.checkMetricStyle(css, "border-top-width");
|
||||
if (width != null)
|
||||
styleValues.setBorderWidthTop(width.floatValue());
|
||||
width = utils.checkMetricStyle(css, "border-right-width");
|
||||
if (width != null)
|
||||
styleValues.setBorderWidthRight(width.floatValue());
|
||||
width = utils.checkMetricStyle(css, "border-left-width");
|
||||
if (width != null)
|
||||
styleValues.setBorderWidthLeft(width.floatValue());
|
||||
}
|
||||
styleValues.setBackground(HtmlUtilities.decodeColor(css.get("background-color")));
|
||||
styleValues.setHorBorderSpacing(getBorderOrCellSpacing(true, css, attributes));
|
||||
styleValues.setVerBorderSpacing(getBorderOrCellSpacing(false, css, attributes));
|
||||
return styleValues;
|
||||
}
|
||||
|
||||
public static TableStyleValues setBorderAttributeForCell(Tag tag) {
|
||||
TableStyleValues styleValues = new TableStyleValues();
|
||||
if (tag == null)
|
||||
return styleValues;
|
||||
Map<String, String> attributes = tag.getAttributes();
|
||||
Map<String, String> css = tag.getCSS();
|
||||
String border = attributes.get("border");
|
||||
if (border != null && (border.trim().length() == 0 || utils.parsePxInCmMmPcToPt(attributes.get("border")) > 0.0F)) {
|
||||
styleValues.setBorderColor(BaseColor.BLACK);
|
||||
styleValues.setBorderWidth(0.75F);
|
||||
}
|
||||
styleValues.setHorBorderSpacing(getBorderOrCellSpacing(true, css, attributes));
|
||||
styleValues.setVerBorderSpacing(getBorderOrCellSpacing(false, css, attributes));
|
||||
return styleValues;
|
||||
}
|
||||
|
||||
public static float getBorderOrCellSpacing(boolean getHor, Map<String, String> css, Map<String, String> attributes) {
|
||||
float spacing = 0.0F;
|
||||
String collapse = css.get("border-collapse");
|
||||
if (collapse == null || collapse.equals("separate")) {
|
||||
String borderSpacing = css.get("border-spacing");
|
||||
String cellSpacing = attributes.get("cellspacing");
|
||||
if (borderSpacing != null) {
|
||||
if (borderSpacing.contains(" ")) {
|
||||
if (getHor) {
|
||||
spacing = utils.parsePxInCmMmPcToPt(borderSpacing.split(" ")[0]);
|
||||
} else {
|
||||
spacing = utils.parsePxInCmMmPcToPt(borderSpacing.split(" ")[1]);
|
||||
}
|
||||
} else {
|
||||
spacing = utils.parsePxInCmMmPcToPt(borderSpacing);
|
||||
}
|
||||
} else if (cellSpacing != null) {
|
||||
spacing = utils.parsePxInCmMmPcToPt(cellSpacing);
|
||||
} else {
|
||||
spacing = 1.5F;
|
||||
}
|
||||
} else if (collapse.equals("collapse")) {
|
||||
spacing = 0.0F;
|
||||
}
|
||||
return spacing;
|
||||
}
|
||||
|
||||
private float[] setCellWidthAndWidestWord(HtmlCell cell) {
|
||||
List<Float> rulesWidth = new ArrayList<Float>();
|
||||
float widestWordOfCell = 0.0F;
|
||||
float startWidth = getCellStartWidth(cell);
|
||||
float widthDeviation = 0.001F;
|
||||
List<Element> compositeElements = cell.getCompositeElements();
|
||||
if (compositeElements != null)
|
||||
for (Element baseLevel : compositeElements) {
|
||||
float f = Float.NaN;
|
||||
if (baseLevel instanceof Phrase) {
|
||||
for (int i = 0; i < ((Phrase)baseLevel).size(); i++) {
|
||||
Element inner = (Element)((Phrase)baseLevel).get(i);
|
||||
if (inner instanceof Chunk) {
|
||||
if (Float.isNaN(f))
|
||||
f = startWidth + widthDeviation;
|
||||
f += ((Chunk)inner).getWidthPoint();
|
||||
float widestWord = startWidth + widthDeviation + getCssAppliers().getChunkCssAplier().getWidestWord((Chunk)inner);
|
||||
if (widestWord > widestWordOfCell)
|
||||
widestWordOfCell = widestWord;
|
||||
}
|
||||
}
|
||||
if (!Float.isNaN(f))
|
||||
rulesWidth.add(Float.valueOf(f));
|
||||
continue;
|
||||
}
|
||||
if (baseLevel instanceof com.itextpdf.text.List) {
|
||||
for (Element li : (Iterable<Element>)((com.itextpdf.text.List)baseLevel).getItems()) {
|
||||
f = startWidth + widthDeviation + ((ListItem)li).getIndentationLeft();
|
||||
for (Chunk c : (Iterable<Chunk>)li.getChunks()) {
|
||||
f += c.getWidthPoint();
|
||||
float widestWord = getCssAppliers().getChunkCssAplier().getWidestWord(c);
|
||||
if (startWidth + widthDeviation + widestWord > widestWordOfCell)
|
||||
widestWordOfCell = startWidth + widthDeviation + widestWord;
|
||||
}
|
||||
rulesWidth.add(Float.valueOf(f));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (baseLevel instanceof PdfPTable) {
|
||||
f = startWidth + widthDeviation + ((PdfPTable)baseLevel).getTotalWidth();
|
||||
for (PdfPRow innerRow : (Iterable<PdfPRow>)((PdfPTable)baseLevel).getRows()) {
|
||||
int size = (innerRow.getCells()).length;
|
||||
TableBorderEvent event = (TableBorderEvent)((PdfPTable)baseLevel).getTableEvent();
|
||||
TableStyleValues values = event.getTableStyleValues();
|
||||
float minRowWidth = values.getBorderWidthLeft() + (float)(size + 1) * values.getHorBorderSpacing() +
|
||||
values.getBorderWidthRight();
|
||||
int celnr = 0;
|
||||
for (PdfPCell innerCell : innerRow.getCells()) {
|
||||
celnr++;
|
||||
if (innerCell != null) {
|
||||
float innerWidestWordOfCell = setCellWidthAndWidestWord(new HtmlCell(innerCell, (celnr == size)))[1];
|
||||
minRowWidth += innerWidestWordOfCell;
|
||||
}
|
||||
}
|
||||
if (minRowWidth > widestWordOfCell)
|
||||
widestWordOfCell = minRowWidth;
|
||||
}
|
||||
rulesWidth.add(Float.valueOf(f));
|
||||
continue;
|
||||
}
|
||||
if (baseLevel instanceof PdfDiv) {
|
||||
float divActualWidth;
|
||||
PdfDiv div = (PdfDiv)baseLevel;
|
||||
if (div.getWidth() != null) {
|
||||
divActualWidth = div.getWidth();
|
||||
} else {
|
||||
ArrayList<Element> divContent = div.getContent();
|
||||
divActualWidth = calculateDivWidestElementWidth(divContent);
|
||||
}
|
||||
f = startWidth + widthDeviation + divActualWidth;
|
||||
rulesWidth.add(Float.valueOf(f));
|
||||
}
|
||||
}
|
||||
float cellWidth = startWidth;
|
||||
for (Float width : rulesWidth) {
|
||||
if (width > cellWidth)
|
||||
cellWidth = width;
|
||||
}
|
||||
return new float[] { cellWidth, widestWordOfCell };
|
||||
}
|
||||
|
||||
private float calculateDivWidestElementWidth(ArrayList<Element> divContent) {
|
||||
float maxWidth = 0.0F;
|
||||
for (Element element : divContent) {
|
||||
float width = 0.0F;
|
||||
if (element instanceof PdfDiv) {
|
||||
width = calculateDivWidestElementWidth(((PdfDiv)element).getContent());
|
||||
} else if (element instanceof PdfPTable) {
|
||||
width = ((PdfPTable)element).getTotalWidth();
|
||||
} else if (element instanceof Paragraph) {
|
||||
Paragraph p = (Paragraph)element;
|
||||
float widestWordOfParagraph = 0.0F;
|
||||
for (Element inner : (Iterable<Element>)p) {
|
||||
float widestWord = 0.0F;
|
||||
if (inner instanceof Chunk) {
|
||||
HashMap<String, Object> chunkAttributes = ((Chunk)inner).getAttributes();
|
||||
if (chunkAttributes != null && chunkAttributes.containsKey("IMAGE")) {
|
||||
Object o = chunkAttributes.get("IMAGE");
|
||||
if (o instanceof Object[] && ((Object[])o)[0] instanceof Image)
|
||||
widestWord = ((Image)((Object[])o)[0]).getWidth();
|
||||
} else {
|
||||
widestWord = getCssAppliers().getChunkCssAplier().getWidestWord((Chunk)inner);
|
||||
}
|
||||
}
|
||||
if (widestWord > widestWordOfParagraph)
|
||||
widestWordOfParagraph = widestWord;
|
||||
}
|
||||
width = widestWordOfParagraph;
|
||||
}
|
||||
if (width > maxWidth)
|
||||
maxWidth = width;
|
||||
}
|
||||
return maxWidth;
|
||||
}
|
||||
|
||||
private float getTableWidth(float[] widths, float outerWidth) throws NoCustomContextException {
|
||||
float width = 0.0F;
|
||||
for (float f : widths)
|
||||
width += f;
|
||||
return width + outerWidth;
|
||||
}
|
||||
|
||||
private float getTableOuterWidth(Tag tag, float horBorderSpacing, WorkerContext ctx) throws NoCustomContextException {
|
||||
float total = utils.getLeftAndRightMargin(tag, getHtmlPipelineContext(ctx).getPageSize().getWidth()) +
|
||||
utils.checkMetricStyle(tag, "border-left-width") +
|
||||
utils.checkMetricStyle(tag, "border-right-width") + horBorderSpacing;
|
||||
Tag parent = tag.getParent();
|
||||
if (parent != null)
|
||||
total += utils.getLeftAndRightMargin(parent, getHtmlPipelineContext(ctx).getPageSize().getWidth());
|
||||
return total;
|
||||
}
|
||||
|
||||
private float getCellStartWidth(HtmlCell cell) {
|
||||
TableStyleValues cellStyleValues = cell.getCellValues();
|
||||
int spacingMultiplier = cell.getColspan() - 1;
|
||||
float spacing = (float)spacingMultiplier * cellStyleValues.getHorBorderSpacing();
|
||||
return spacing + cell.getPaddingLeft() + cell.getPaddingRight();
|
||||
}
|
||||
|
||||
private void setVerticalMargin(PdfPTable table, Tag t, TableStyleValues values, WorkerContext ctx) throws NoCustomContextException {
|
||||
float spacingBefore = values.getBorderWidthTop();
|
||||
float spacingAfter = values.getVerBorderSpacing() + values.getBorderWidthBottom();
|
||||
for (Map.Entry<String, String> css : t.getCSS().entrySet()) {
|
||||
String key = css.getKey();
|
||||
String value = css.getValue();
|
||||
if ("margin-top".equalsIgnoreCase(key)) {
|
||||
CssUtils utils = CssUtils.getInstance();
|
||||
spacingBefore += utils.calculateMarginTop(value, fst.getFontSize(t), getHtmlPipelineContext(ctx));
|
||||
continue;
|
||||
}
|
||||
if ("margin-bottom".equalsIgnoreCase(key)) {
|
||||
float marginBottom = Table.utils.parseValueToPt(value, fst.getFontSize(t));
|
||||
spacingAfter += marginBottom;
|
||||
getHtmlPipelineContext(ctx).getMemory().put("lastMarginBottom", Float.valueOf(marginBottom));
|
||||
continue;
|
||||
}
|
||||
if ("padding-top".equalsIgnoreCase(key))
|
||||
table.setPaddingTop(Table.utils.parseValueToPt(value, fst.getFontSize(t)));
|
||||
}
|
||||
table.setSpacingBefore(spacingBefore);
|
||||
table.setSpacingAfter(spacingAfter);
|
||||
}
|
||||
|
||||
public boolean isStackOwner() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
package com.itextpdf.tool.xml.html.table;
|
||||
|
||||
import com.itextpdf.text.BaseColor;
|
||||
import com.itextpdf.text.pdf.PdfContentByte;
|
||||
import com.itextpdf.text.pdf.PdfPTable;
|
||||
import com.itextpdf.text.pdf.PdfPTableEvent;
|
||||
|
||||
public class TableBorderEvent implements PdfPTableEvent {
|
||||
private final TableStyleValues styleValues;
|
||||
|
||||
public TableBorderEvent(TableStyleValues styleValues) {
|
||||
this.styleValues = styleValues;
|
||||
}
|
||||
|
||||
public void tableLayout(PdfPTable table, float[][] width, float[] height, int headerRows, int rowStart, PdfContentByte[] canvas) {
|
||||
float left = this.styleValues.getBorderWidthLeft();
|
||||
float right = this.styleValues.getBorderWidthRight();
|
||||
float top = this.styleValues.getBorderWidthTop();
|
||||
float bottom = this.styleValues.getBorderWidthBottom();
|
||||
float[] widths = width[0];
|
||||
float effectivePadding = left / 2.0F;
|
||||
float x1 = widths[0] - effectivePadding;
|
||||
effectivePadding = right / 2.0F;
|
||||
float x2 = widths[widths.length - 1] + effectivePadding;
|
||||
effectivePadding = top / 2.0F;
|
||||
float y1 = height[0] + effectivePadding;
|
||||
effectivePadding = bottom / 2.0F + this.styleValues.getVerBorderSpacing();
|
||||
float y2 = height[height.length - 1] - effectivePadding;
|
||||
PdfContentByte cb = canvas[1];
|
||||
BaseColor color = this.styleValues.getBackground();
|
||||
if (color != null) {
|
||||
cb.setColorFill(color);
|
||||
cb.rectangle(x1, y1, x2 - x1, y2 - y1);
|
||||
cb.fill();
|
||||
}
|
||||
cb = canvas[2];
|
||||
if (left != 0.0F) {
|
||||
color = this.styleValues.getBorderColorLeft();
|
||||
if (color == null)
|
||||
color = BaseColor.BLACK;
|
||||
cb.setLineWidth(left);
|
||||
cb.setColorStroke(color);
|
||||
cb.moveTo(x1, y1);
|
||||
cb.lineTo(x1, y2);
|
||||
cb.stroke();
|
||||
}
|
||||
if (bottom != 0.0F) {
|
||||
color = this.styleValues.getBorderColorBottom();
|
||||
if (color == null)
|
||||
color = BaseColor.BLACK;
|
||||
cb.setLineWidth(bottom);
|
||||
cb.setColorStroke(color);
|
||||
cb.moveTo(x1, y2);
|
||||
cb.lineTo(x2, y2);
|
||||
cb.stroke();
|
||||
}
|
||||
if (right != 0.0F) {
|
||||
color = this.styleValues.getBorderColorRight();
|
||||
if (color == null)
|
||||
color = BaseColor.BLACK;
|
||||
cb.setLineWidth(right);
|
||||
cb.setColorStroke(color);
|
||||
cb.moveTo(x2, y2);
|
||||
cb.lineTo(x2, y1);
|
||||
cb.stroke();
|
||||
}
|
||||
if (top != 0.0F) {
|
||||
color = this.styleValues.getBorderColorTop();
|
||||
if (color == null)
|
||||
color = BaseColor.BLACK;
|
||||
cb.setLineWidth(top);
|
||||
cb.setColorStroke(color);
|
||||
cb.moveTo(x2, y1);
|
||||
cb.lineTo(x1, y1);
|
||||
cb.stroke();
|
||||
}
|
||||
cb.resetRGBColorStroke();
|
||||
}
|
||||
|
||||
public TableStyleValues getTableStyleValues() {
|
||||
return this.styleValues;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
package com.itextpdf.tool.xml.html.table;
|
||||
|
||||
import com.itextpdf.text.Chunk;
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.text.ListItem;
|
||||
import com.itextpdf.text.Paragraph;
|
||||
import com.itextpdf.text.pdf.PdfName;
|
||||
import com.itextpdf.tool.xml.NoCustomContextException;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.WorkerContext;
|
||||
import com.itextpdf.tool.xml.exceptions.LocaleMessages;
|
||||
import com.itextpdf.tool.xml.exceptions.RuntimeWorkerException;
|
||||
import com.itextpdf.tool.xml.html.AbstractTagProcessor;
|
||||
import com.itextpdf.tool.xml.html.pdfelement.HtmlCell;
|
||||
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TableData extends AbstractTagProcessor {
|
||||
public List<Element> content(WorkerContext ctx, Tag tag, String content) {
|
||||
return textContent(ctx, tag, content);
|
||||
}
|
||||
|
||||
public List<Element> end(WorkerContext ctx, Tag tag, List<Element> currentContent) {
|
||||
HtmlCell cell = new HtmlCell();
|
||||
int direction = getRunDirection(tag);
|
||||
if (direction != 1)
|
||||
cell.setRunDirection(direction);
|
||||
if ("th".equalsIgnoreCase(tag.getName()))
|
||||
cell.setRole(PdfName.TH);
|
||||
try {
|
||||
HtmlPipelineContext htmlPipelineContext = getHtmlPipelineContext(ctx);
|
||||
cell = (HtmlCell)getCssAppliers().apply((Element)cell, tag, htmlPipelineContext);
|
||||
} catch (NoCustomContextException e1) {
|
||||
throw new RuntimeWorkerException(LocaleMessages.getInstance().getMessage("customcontext.404"), e1);
|
||||
}
|
||||
List<Element> l = new ArrayList<Element>(1);
|
||||
List<Element> chunks = new ArrayList<Element>();
|
||||
List<ListItem> listItems = new ArrayList<ListItem>();
|
||||
int index = -1;
|
||||
for (Element e : currentContent) {
|
||||
index++;
|
||||
if (e instanceof Chunk || e instanceof com.itextpdf.tool.xml.html.pdfelement.NoNewLineParagraph || e instanceof com.itextpdf.text.pdf.draw.LineSeparator) {
|
||||
if (!listItems.isEmpty())
|
||||
processListItems(ctx, tag, listItems, cell);
|
||||
if (e instanceof Chunk && Chunk.NEWLINE.getContent().equals(((Chunk)e).getContent())) {
|
||||
if (index == currentContent.size() - 1)
|
||||
continue;
|
||||
Element nextElement = currentContent.get(index + 1);
|
||||
if (!chunks.isEmpty() && !(nextElement instanceof Chunk) && !(nextElement instanceof com.itextpdf.tool.xml.html.pdfelement.NoNewLineParagraph))
|
||||
continue;
|
||||
} else if (e instanceof com.itextpdf.text.pdf.draw.LineSeparator) {
|
||||
try {
|
||||
HtmlPipelineContext htmlPipelineContext = getHtmlPipelineContext(ctx);
|
||||
Chunk newLine = (Chunk)getCssAppliers().apply(new Chunk(Chunk.NEWLINE), tag, htmlPipelineContext);
|
||||
chunks.add(newLine);
|
||||
} catch (NoCustomContextException e1) {
|
||||
throw new RuntimeWorkerException(LocaleMessages.getInstance().getMessage("customcontext.404"), e1);
|
||||
}
|
||||
}
|
||||
chunks.add(e);
|
||||
continue;
|
||||
}
|
||||
if (e instanceof ListItem) {
|
||||
if (!chunks.isEmpty())
|
||||
processChunkItems(chunks, cell);
|
||||
listItems.add((ListItem)e);
|
||||
continue;
|
||||
}
|
||||
if (!chunks.isEmpty())
|
||||
processChunkItems(chunks, cell);
|
||||
if (!listItems.isEmpty())
|
||||
processListItems(ctx, tag, listItems, cell);
|
||||
if (e instanceof Paragraph && (
|
||||
(Paragraph)e).getAlignment() == -1)
|
||||
((Paragraph)e).setAlignment(cell.getHorizontalAlignment());
|
||||
cell.addElement(e);
|
||||
}
|
||||
if (!chunks.isEmpty())
|
||||
processChunkItems(chunks, cell);
|
||||
l.add(cell);
|
||||
return l;
|
||||
}
|
||||
|
||||
public boolean isStackOwner() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void processChunkItems(List<Element> chunks, HtmlCell cell) {
|
||||
Paragraph p = new Paragraph();
|
||||
p.setMultipliedLeading(1.2F);
|
||||
p.addAll(chunks);
|
||||
p.setAlignment(cell.getHorizontalAlignment());
|
||||
if (p.trim())
|
||||
cell.addElement((Element)p);
|
||||
chunks.clear();
|
||||
}
|
||||
|
||||
protected void processListItems(WorkerContext ctx, Tag tag, List<ListItem> listItems, HtmlCell cell) {
|
||||
try {
|
||||
com.itextpdf.text.List list = new com.itextpdf.text.List();
|
||||
list.setAutoindent(false);
|
||||
list = (com.itextpdf.text.List)getCssAppliers().apply((Element)list, tag,
|
||||
getHtmlPipelineContext(ctx));
|
||||
list.setIndentationLeft(0.0F);
|
||||
for (ListItem li : listItems) {
|
||||
li = (ListItem)getCssAppliers().apply((Element)li, tag, getHtmlPipelineContext(ctx));
|
||||
li.setSpacingAfter(0.0F);
|
||||
li.setSpacingBefore(0.0F);
|
||||
li.setMultipliedLeading(1.2F);
|
||||
list.add((Element)li);
|
||||
}
|
||||
cell.addElement((Element)list);
|
||||
listItems.clear();
|
||||
} catch (NoCustomContextException e) {
|
||||
throw new RuntimeWorkerException(LocaleMessages.getInstance().getMessage("customcontext.404"), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package com.itextpdf.tool.xml.html.table;
|
||||
|
||||
import com.itextpdf.text.Element;
|
||||
import com.itextpdf.tool.xml.Tag;
|
||||
import com.itextpdf.tool.xml.WorkerContext;
|
||||
import com.itextpdf.tool.xml.html.AbstractTagProcessor;
|
||||
import com.itextpdf.tool.xml.html.pdfelement.HtmlCell;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TableRow extends AbstractTagProcessor {
|
||||
public List<Element> end(WorkerContext ctx, Tag tag, List<Element> currentContent) {
|
||||
TableRowElement row = null;
|
||||
List<Element> l = new ArrayList<Element>(1);
|
||||
if (tag.getParent().getName().equalsIgnoreCase("thead")) {
|
||||
row = new TableRowElement(currentContent, TableRowElement.Place.HEADER);
|
||||
} else if (tag.getParent().getName().equalsIgnoreCase("tbody")) {
|
||||
row = new TableRowElement(currentContent, TableRowElement.Place.BODY);
|
||||
} else if (tag.getParent().getName().equalsIgnoreCase("tfoot")) {
|
||||
row = new TableRowElement(currentContent, TableRowElement.Place.FOOTER);
|
||||
} else {
|
||||
row = new TableRowElement(currentContent, TableRowElement.Place.BODY);
|
||||
}
|
||||
int direction = getRunDirection(tag);
|
||||
if (direction != 1)
|
||||
for (HtmlCell cell : row.getContent()) {
|
||||
if (cell.getRunDirection() == 1)
|
||||
cell.setRunDirection(direction);
|
||||
}
|
||||
l.add(row);
|
||||
return l;
|
||||
}
|
||||
|
||||
public boolean isStackOwner() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue