All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.openhtmltopdf.outputdevice.helper.BaseRendererBuilder Maven / Gradle / Ivy

Go to download

Open HTML to PDF is a CSS 2.1 renderer written in Java. This artifact contains the core rendering and layout code.

There is a newer version: 1.1.4
Show newest version
package com.openhtmltopdf.outputdevice.helper;

import com.openhtmltopdf.bidi.BidiReorderer;
import com.openhtmltopdf.bidi.BidiSplitterFactory;
import com.openhtmltopdf.extend.*;
import com.openhtmltopdf.layout.Layer;
import com.openhtmltopdf.swing.NaiveUserAgent;

import com.openhtmltopdf.util.Diagnostic;
import com.openhtmltopdf.util.ThreadCtx;
import org.w3c.dom.Document;

import java.io.Closeable;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiPredicate;
import java.util.function.Consumer;

/**
 * Baseclass for all RendererBuilders (PDF and Java2D), has all common settings
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
public abstract class BaseRendererBuilder {
	public static final float PAGE_SIZE_LETTER_WIDTH = 8.5f;
	public static final float PAGE_SIZE_LETTER_HEIGHT = 11.0f;
	public static final PageSizeUnits PAGE_SIZE_LETTER_UNITS = PageSizeUnits.INCHES;

	/**
	 * This class is an internal implementation detail.
* This is internal, please don't use directly. */ public abstract static class BaseRendererBuilderState { public final List _fonts = new ArrayList<>(); public final List _domMutators = new ArrayList<>(); public BiPredicate _beforeAccessController = new NaiveUserAgent.DefaultAccessController(); public BiPredicate _afterAccessController = new NaiveUserAgent.DefaultAccessController(); public final Map _streamFactoryMap = new HashMap<>(); public FSUriResolver _resolver; public String _html; public String _baseUri; public Document _document; public SVGDrawer _svgImpl; public SVGDrawer _mathmlImpl; public String _replacementText; public FSTextBreaker _lineBreaker; public FSTextBreaker _charBreaker; public FSTextTransformer _unicodeToUpperTransformer; public FSTextTransformer _unicodeToLowerTransformer; public FSTextTransformer _unicodeToTitleTransformer; public BidiSplitterFactory _splitter; public BidiReorderer _reorderer; public boolean _textDirection = false; public Float _pageWidth; public Float _pageHeight; public boolean _isPageSizeInches; public String _uri; public File _file; public boolean _testMode = false; public int _initialPageNumber; public short _pagingMode = Layer.PAGED_MODE_PRINT; public FSObjectDrawerFactory _objectDrawerFactory; public String _preferredTransformerFactoryImplementationClass = "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"; public String _preferredDocumentBuilderFactoryImplementationClass = "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl"; public Consumer _diagnosticConsumer; } protected final TBaseRendererBuilderState state; protected BaseRendererBuilder(TBaseRendererBuilderState state) { this.state = state; this.useProtocolsStreamImplementation(new NaiveUserAgent.DefaultHttpStreamFactory(), "http", "https"); this.useProtocolsStreamImplementation(new NaiveUserAgent.DataUriFactory(), "data"); } /** * Add a DOM mutator to this builder. DOM mutators allow to modify the DOM * before it is rendered. e.g. LaTeXDOMMutator can be used to translate latex * text within a <latex> node to HTMl and MathML. * * @param domMutator * the DOM Mutator * @return this for method chaining */ public TFinalClass addDOMMutator(FSDOMMutator domMutator) { state._domMutators.add(domMutator); return (TFinalClass) this; } /** * This method should be considered advanced and is not required for most * setups. Set a preferred implementation class for use as * javax.xml.transform.TransformerFactory. Use null to let a default * implementation class be used. The default is * "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl". This * seems to work with most systems but not JBoss Wildfly and related setups. In * this case you can use null to let the container use whatever * TransformerFactory it has available. * * @param transformerFactoryClass * @return this for method chaining */ public final TFinalClass useTransformerFactoryImplementationClass(String transformerFactoryClass) { state._preferredTransformerFactoryImplementationClass = transformerFactoryClass; return (TFinalClass) this; } /** * This method should be considered advanced and is not required for most * setups. Set a preferred implementation class for use as * javax.xml.parsers.DocumentBuilderFactory. Use null to let a default * implementation class be used. The default is * "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl". If the * default does not work you can use null to let the container use whatever * DocumentBuilderFactory it has available. * * @param documentBuilderFactoryClass * @return this for method chaining */ public final TFinalClass useDocumentBuilderFactoryImplementationClass(String documentBuilderFactoryClass) { state._preferredDocumentBuilderFactoryImplementationClass = documentBuilderFactoryClass; return (TFinalClass) this; } /** * The default text direction of the document. LTR by default. * * @param textDirection * @return this for method chaining */ public final TFinalClass defaultTextDirection(TextDirection textDirection) { state._textDirection = textDirection == TextDirection.RTL; return (TFinalClass) this; } /** * Whether to use test mode and output the PDF uncompressed. Turned off by * default. * * @param mode * @return this for method chaining */ public final TFinalClass testMode(boolean mode) { state._testMode = mode; return (TFinalClass) this; } /** * Provides an HttpStreamFactory implementation if the user desires to use an * external HTTP/HTTPS implementation. Uses URL::openStream by default. * * @see #useProtocolsStreamImplementation(FSStreamFactory, String[]) * * @param factory the factory to use for HTTP/HTTPS * @return this for method chaining */ public final TFinalClass useHttpStreamImplementation(FSStreamFactory factory) { this.useProtocolsStreamImplementation(factory, "http", "https"); return (TFinalClass) this; } /** * Provides an {@link com.openhtmltopdf.extend.FSStreamFactory} * implementation if the user desires to use an external * stream provider for a particular set of protocols. * Protocols should always be in lower case. * * NOTE: HttpStreamFactory, despite its historical name, can be used for any protocol * including private made-up protocols. * * @see #useHttpStreamImplementation(FSStreamFactory) * @see #useProtocolsStreamImplementation(FSStreamFactory, String[]) * @param factory the stream factory to use * @param protocols the list of protocols the factory should be used for * @return this for method chaining */ public final TFinalClass useProtocolsStreamImplementation(FSStreamFactory factory, Set protocols) { for (String protocol : protocols) { state._streamFactoryMap.put(protocol, factory); } return (TFinalClass) this; } /** * Provides an {@link com.openhtmltopdf.extend.FSStreamFactory} * implementation if the user desires to use an external * stream provider for a particular list of protocols. * Protocols should always be in lower case. * * NOTE: HttpStreamFactory, despite its historical name, can be used for any protocol * including private made-up protocols. * * @see #useHttpStreamImplementation(FSStreamFactory) * @see #useProtocolsStreamImplementation(FSStreamFactory, Set) * @param factory the stream factory to use * @param protocols the list of protocols the stream factory should be used for * @return this for method chaining */ public final TFinalClass useProtocolsStreamImplementation(FSStreamFactory factory, String... protocols) { for (String protocol : protocols) { state._streamFactoryMap.put(protocol, factory); } return (TFinalClass) this; } /** * Provides a uri resolver to resolve relative uris or private uri schemes. * * @param resolver the URI resolver used to resolve any kind of private URIs/protocolls * @return this for method chaining */ public final TFinalClass useUriResolver(FSUriResolver resolver) { state._resolver = resolver; return (TFinalClass) this; } /** * Provides a text splitter to split text into directional runs. Does nothing by * default. * * @param splitter the unicode bidi splitter to use. * @return this for method chaining */ public final TFinalClass useUnicodeBidiSplitter(BidiSplitterFactory splitter) { state._splitter = splitter; return (TFinalClass) this; } /** * Provides a reorderer to properly reverse RTL text. No-op by default. * * @param reorderer the unicode bidi reorderer to use. * @return this for method chaining */ public final TFinalClass useUnicodeBidiReorderer(BidiReorderer reorderer) { state._reorderer = reorderer; return (TFinalClass) this; } /** * Provides a string containing XHTML/XML to convert to PDF. * Note that baseDocumentUri can be null if there are no relative resources, otherwise * should be a uri to a (possibly fake) document that is used to resolve relative resources. * Examples: * file:///Users/user/my-dummy-doc.html, * file:/C:/Users/me/Desktop/dummy.html * * @param html the HTML text to use. * @param baseDocumentUri the base document URI to resolve future relative resources (e.g. images) * @return this for method chaining */ public final TFinalClass withHtmlContent(String html, String baseDocumentUri) { state._html = html; state._baseUri = baseDocumentUri; return (TFinalClass) this; } /** * Provides a w3c DOM Document acquired from an external source. * * @param doc the DOM of the HTML document * @param baseUri the base URI, it will be used to resolve future resources (images, etc. * @return this for method chaining */ public final TFinalClass withW3cDocument(org.w3c.dom.Document doc, String baseUri) { state._document = doc; state._baseUri = baseUri; return (TFinalClass) this; } /** * Provides a URI to convert to PDF. The URI MUST point to a strict XHTML/XML * document. * * @param uri the URI of the HTML source to convert. * @return this for method chaining */ public final TFinalClass withUri(String uri) { state._uri = uri; return (TFinalClass) this; } /** * Provides a file to convert to PDF. The file MUST contain XHTML/XML in UTF-8 * encoding. * * @param file the file with the HTML source to convert * @return this for method chaining */ public final TFinalClass withFile(File file) { state._file = file; return (TFinalClass) this; } /** * Uses the specified SVG drawer implementation. * * NOTE: This implementation is used for both inline SVG markup and SVG markup in external * files included via the img tag. Please be very careful if using an insecure * SVGDrawer that all SVG images are trusted. * * @param svgImpl * the SVG implementation * @return this for method chaining */ public final TFinalClass useSVGDrawer(SVGDrawer svgImpl) { state._svgImpl = svgImpl; return (TFinalClass) this; } /** * Use the specified MathML implementation. * * @param mathMlImpl * the MathML implementation * @return this for method chaining */ public final TFinalClass useMathMLDrawer(SVGDrawer mathMlImpl) { state._mathmlImpl = mathMlImpl; return (TFinalClass) this; } /** * The replacement text to use if a character is cannot be renderered by any of * the specified fonts. This is not broken across lines so should be one or zero * characters for best results. Also, make sure it can be rendered by at least * one of your specified fonts! The default is the # character. * * @param replacement * the default replacement text * @return this for method chaining */ public final TFinalClass useReplacementText(String replacement) { state._replacementText = replacement; return (TFinalClass) this; } /** * Specify the line breaker. By default a Java default BreakIterator line * instance is used with US locale. Additionally, this is wrapped with * UrlAwareLineBreakIterator to also break before the forward slash (/) * character so that long URIs can be broken on to multiple lines. * * You may want to use a BreakIterator with a different locale (wrapped by * UrlAwareLineBreakIterator or not) or a more advanced BreakIterator from icu4j * (see the rtl-support module for an example). * * @param breaker the text breaker to use * @return this for method chaining */ public final TFinalClass useUnicodeLineBreaker(FSTextBreaker breaker) { state._lineBreaker = breaker; return (TFinalClass) this; } /** * Specify the character breaker. By default a break iterator character instance * is used with US locale. Currently this is used when * word-wrap: break-word is in effect. * * @param breaker the character breaker to use * @return this for method chaining */ public final TFinalClass useUnicodeCharacterBreaker(FSTextBreaker breaker) { state._charBreaker = breaker; return (TFinalClass) this; } /** * Specify a transformer to use to upper case strings. By default * String::toUpperCase(Locale.US) is used. * * @param tr the text transformer to use * @return this for method chaining */ public final TFinalClass useUnicodeToUpperTransformer(FSTextTransformer tr) { state._unicodeToUpperTransformer = tr; return (TFinalClass) this; } /** * Specify a transformer to use to lower case strings. By default * String::toLowerCase(Locale.US) is used. * * @param tr the text transformer to use. * @return this for method chaining */ public final TFinalClass useUnicodeToLowerTransformer(FSTextTransformer tr) { state._unicodeToLowerTransformer = tr; return (TFinalClass) this; } /** * Specify a transformer to title case strings. By default a best effort * implementation (non locale aware) is used. * * @param tr the text transformer to use * @return this for method chaining */ public final TFinalClass useUnicodeToTitleTransformer(FSTextTransformer tr) { state._unicodeToTitleTransformer = tr; return (TFinalClass) this; } /** * Specifies the default page size to use if none is specified in CSS. * * @param pageWidth the new default width * @param pageHeight the new default height * @param units * either mm or inches. * @see #PAGE_SIZE_LETTER_WIDTH * @see #PAGE_SIZE_LETTER_HEIGHT * @see #PAGE_SIZE_LETTER_UNITS * @return this for method chaining */ public final TFinalClass useDefaultPageSize(float pageWidth, float pageHeight, PageSizeUnits units) { state._pageWidth = pageWidth; state._pageHeight = pageHeight; state._isPageSizeInches = (units == PageSizeUnits.INCHES); return (TFinalClass) this; } /** * Set a factory for <object> drawers * * @param objectDrawerFactory * Object Drawer Factory * @return this for method chaining */ public final TFinalClass useObjectDrawerFactory(FSObjectDrawerFactory objectDrawerFactory) { state._objectDrawerFactory = objectDrawerFactory; return (TFinalClass) this; } /** * Use the new (May 2018) fast renderer. * This renderer can be 100s of times faster for very large documents. * Please note that the fast renderer will be the only renderer at some future * release so please at least test your code using the fast mode. * * Note: As of version 1.0.11 the fast renderer will be the only renderer * and this method is not required. * * @return this for method chaining */ public final TFinalClass useFastMode() { return (TFinalClass) this; } /** *

Allows the user to provide a font file for use by the main * document only (not SVGs). See: * {@link #useFont(File, String, Integer, FontStyle, boolean, Set)}

* *

For gotchas related to font handling please see: * Wiki: Fonts

*/ public TFinalClass useFont( File fontFile, String fontFamily, Integer fontWeight, FontStyle fontStyle, boolean subset) { state._fonts.add(new AddedFont(null, fontFile, fontWeight, fontFamily, subset, fontStyle, EnumSet.of(FSFontUseCase.DOCUMENT))); return (TFinalClass) this; } /** *

Allows the user to provide a font file for use any or all of * the use cases listed in {@link FSFontUseCase} such as main * document, SVGs, etc.

* *

For gotchas related to font handling please see: * Wiki: Fonts

* * @param fontFile A file system font file in true-type format. Beware of using resources as * they will not be separate files in the final jar. * @param fontFamily Font family name. If using a font in Java2D, SVG or MathML this should match * Font.createFont(Font.TRUETYPE_FONT, fontFile).getFamily(). * @param fontWeight Font boldness, usually 400 for regular fonts and 700 for bold fonts. * @param fontStyle Normal, italic or oblique. * @param subset For PDF use whether the font is subset, usually true unless the font is * being used by form controls. * @param fontUsedFor Which components use the font such as main document, SVG, etc. Example: * EnumSet.of(FSFontUseCase.DOCUMENT, FSFontUseCase.SVG) * @return this for method chaining */ public TFinalClass useFont( File fontFile, String fontFamily, Integer fontWeight, FontStyle fontStyle, boolean subset, Set fontUsedFor) { state._fonts.add(new AddedFont(null, fontFile, fontWeight, fontFamily, subset, fontStyle, fontUsedFor)); return (TFinalClass) this; } /** * Simpler overload for * {@link #useFont(File, String, Integer, FontStyle, boolean)} * * @return this for method chaining */ public TFinalClass useFont(File fontFile, String fontFamily) { return this.useFont(fontFile, fontFamily, 400, FontStyle.NORMAL, true); } /** *

Add a font programmatically. If the font is NOT subset, it will be downloaded * when the renderer is run, otherwise, assuming a font-metrics cache has been configured, * the font will only be downloaded if required. Therefore, the user could add many fonts, * confident that only those that are needed will be downloaded and processed.

* *

The InputStream returned by the supplier will be closed by the caller. Fonts * should generally be subset (Java2D renderer ignores this argument), * except when used in form controls. FSSupplier is a lambda compatible interface.

* *

Fonts can also be added using a font-face at-rule in the CSS (not * recommended for Java2D usage).

* *

IMPORTANT: This method will add fonts for use by the main document * only. It is not recommended for use with Java2D. * To add fonts for use by Java2D, SVG, etc see: * {@link #useFont(File, String, Integer, FontStyle, boolean, Set)}

* *

For gotchas related to font handling please see: * Wiki: Fonts

* * @return this for method chaining */ public TFinalClass useFont(FSSupplier supplier, String fontFamily, Integer fontWeight, FontStyle fontStyle, boolean subset) { state._fonts.add(new AddedFont(supplier, null, fontWeight, fontFamily, subset, fontStyle, EnumSet.of(FSFontUseCase.DOCUMENT))); return (TFinalClass) this; } /** *

Add a font programmatically. If the font is NOT subset, it will be downloaded * when the renderer is run, otherwise, assuming a font-metrics cache has been configured, * the font will only be downloaded if required. Therefore, the user could add many fonts, * confident that only those that are needed will be downloaded and processed.

* *

The InputStream returned by the supplier will be closed by the caller. Fonts * should generally be subset (Java2D renderer ignores this argument), * except when used in form controls. FSSupplier is a lambda compatible interface.

* *

Fonts can also be added using a font-face at-rule in the CSS (not * recommended for Java2D usage).

* *

IMPORTANT: This method is not recommended for use with Java2D. * To add fonts for use by Java2D, SVG, etc see: * {@link #useFont(File, String, Integer, FontStyle, boolean, Set)}

* *

For gotchas related to font handling please see: * Wiki: Fonts

* * @return this for method chaining */ public TFinalClass useFont( FSSupplier supplier, String fontFamily, Integer fontWeight, FontStyle fontStyle, boolean subset, Set useFontFlags) { state._fonts.add(new AddedFont(supplier, null, fontWeight, fontFamily, subset, fontStyle, useFontFlags)); return (TFinalClass) this; } /** * Simpler overload for * {@link #useFont(FSSupplier, String, Integer, FontStyle, boolean)} * * @return this for method chaining */ public TFinalClass useFont(FSSupplier supplier, String fontFamily) { return this.useFont(supplier, fontFamily, 400, FontStyle.NORMAL, true); } public TFinalClass withDiagnosticConsumer(Consumer diagnosticConsumer) { state._diagnosticConsumer = diagnosticConsumer; return (TFinalClass) this; } protected Closeable applyDiagnosticConsumer() { return ThreadCtx.applyDiagnosticConsumer(state._diagnosticConsumer); } /** * Allows to set one external access controller to run * before the uri resolver and one to run after the uri resolver. * * The predicate will receive the uri and the resource type. If it returns * false, the resource will not be loaded but the rendering process will * attempt to continue without the resource. * * A default controller is registered that allows everything except file * embed resources. To override the default controller, register a controller * with after priority. */ public TFinalClass useExternalResourceAccessControl( BiPredicate allowExternalResource, ExternalResourceControlPriority priority) { if (priority == null) { // Default is after as safest. priority = ExternalResourceControlPriority.RUN_AFTER_RESOLVING_URI; } switch (priority) { case RUN_AFTER_RESOLVING_URI: state._afterAccessController = allowExternalResource; break; case RUN_BEFORE_RESOLVING_URI: state._beforeAccessController = allowExternalResource; break; } return (TFinalClass) this; } /** * Allows the setting of the initial page number to use with the * page and pages CSS counters. * Useful when appending to an existing document. * Must be one or greater. * * @return this for method chaining. */ public TFinalClass useInitialPageNumber(int initialPageNumber) { state._initialPageNumber = initialPageNumber; return (TFinalClass) this; } public enum TextDirection { RTL, LTR } public enum PageSizeUnits { MM, INCHES } public enum FontStyle { NORMAL, ITALIC, OBLIQUE } /** * Use cases for fonts. */ public enum FSFontUseCase { /** Main document (PDF or Java2D) */ DOCUMENT, SVG, MATHML, /** * Use as a fallback font after all supplied fonts have been tried but before * the built-in fonts have been attempted. */ FALLBACK_PRE, /** * Use as a fallback fonts after all supplied fonts and the built-in fonts have been * tried. The same font should not be registered with both FALLBACK_PRE * and FALLBACK_FINAL. */ FALLBACK_FINAL; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy