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

com.openhtmltopdf.layout.SharedContext 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
/*
 * {{{ header & license
 * Copyright (c) 2004, 2005 Joshua Marinacci
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 * }}}
 */
package com.openhtmltopdf.layout;

import com.openhtmltopdf.context.StyleReference;
import com.openhtmltopdf.css.style.CalculatedStyle;
import com.openhtmltopdf.css.style.EmptyStyle;
import com.openhtmltopdf.css.value.FontSpecification;
import com.openhtmltopdf.extend.*;
import com.openhtmltopdf.layout.counter.RootCounterContext;
import com.openhtmltopdf.render.Box;
import com.openhtmltopdf.render.FSFont;
import com.openhtmltopdf.render.FSFontMetrics;
import com.openhtmltopdf.render.RenderingContext;
import com.openhtmltopdf.util.ThreadCtx;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import java.awt.*;
import java.text.BreakIterator;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

/**
 * The SharedContext stores pseudo global variables.
 * Originally, it was reusable, but it is now recommended that the developer
 * use a new instance for every run.
 */
public class SharedContext {

    /**
     * @deprecated Belongs in Java2D renderer.
     */
    @Deprecated
    private final static int DEFAULT_DOTS_PER_PIXEL = 1;

    /**
     * @deprecated Belongs in Java2D renderer.
     */
    @Deprecated
    private final static boolean DEFAULT_INTERACTIVE = true;

    private final static int MM__PER__CM = 10;
    private final static float CM__PER__IN = 2.54F;
    
	private TextRenderer textRenderer;
    private String media;
    private UserAgentCallback uac;
    private boolean interactive = DEFAULT_INTERACTIVE;

    private Map idMap;

    /**
     * Used to adjust fonts, ems, points, into screen resolution.
     * Internal program dots per inch.
     */
    private float dpi;

    /**
     * Internal program dots per pixel.
     */
    private int dotsPerPixel = DEFAULT_DOTS_PER_PIXEL;
    
    /**
     * dpi in a more usable way
     * Internal program dots per mm (probably a fraction).
     */
    private float mmPerDot;

    private boolean print;
    private final Map styleMap = new HashMap<>(1024, 0.75f);
    private ReplacedElementFactory replacedElementFactory;
    private Rectangle tempCanvas;
    
    protected FontResolver fontResolver;
    protected StyleReference css;
    
    protected boolean debug_draw_boxes;
    protected boolean debug_draw_line_boxes;
    protected boolean debug_draw_inline_boxes;
    protected boolean debug_draw_font_metrics;

    protected FSCanvas canvas;

    private NamespaceHandler namespaceHandler;
    
	private Float defaultPageHeight;
	private Float defaultPageWidth;
	private boolean defaultPageSizeIsInches;

	private String replacementText = "#";
	private FSTextBreaker lineBreaker = new UrlAwareLineBreakIterator(BreakIterator.getLineInstance(Locale.US));
	private FSTextBreaker characterBreaker = new TextUtil.DefaultCharacterBreaker(BreakIterator.getCharacterInstance(Locale.US));

	private FSTextTransformer _unicodeToLowerTransformer = new TextUtil.DefaultToLowerTransformer(Locale.US);
	private FSTextTransformer _unicodeToUpperTransformer = new TextUtil.DefaultToUpperTransformer(Locale.US);
	private FSTextTransformer _unicodeToTitleTransformer = new TextUtil.DefaultToTitleTransformer();

	public String _preferredTransformerFactoryImplementationClass = null;
	public String _preferredDocumentBuilderFactoryImplementationClass = null;

    private final RootCounterContext _rootCounterContext = new RootCounterContext();

    public SharedContext() {
    }

    public LayoutContext newLayoutContextInstance() {
        LayoutContext c = new LayoutContext(this);
        return c;
    }

    public RenderingContext newRenderingContextInstance() {
        RenderingContext c = new RenderingContext(this);
        return c;
    }

    /* =========== Font stuff ============== */

    /**
     * Gets the fontResolver attribute of the Context object
     *
     * @return The fontResolver value
     */
    public FontResolver getFontResolver() {
        return fontResolver;
    }

    /**
     * The media for this context
     */
    public String getMedia() {
        return media;
    }

    public TextRenderer getTextRenderer() {
        return textRenderer;
    }

    public boolean debugDrawBoxes() {
        return debug_draw_boxes;
    }

    public boolean debugDrawLineBoxes() {
        return debug_draw_line_boxes;
    }

    public boolean debugDrawInlineBoxes() {
        return debug_draw_inline_boxes;
    }

    public boolean debugDrawFontMetrics() {
        return debug_draw_font_metrics;
    }

    public void setDebug_draw_boxes(boolean debug_draw_boxes) {
        this.debug_draw_boxes = debug_draw_boxes;
    }

    public void setDebug_draw_line_boxes(boolean debug_draw_line_boxes) {
        this.debug_draw_line_boxes = debug_draw_line_boxes;
    }

    public void setDebug_draw_inline_boxes(boolean debug_draw_inline_boxes) {
        this.debug_draw_inline_boxes = debug_draw_inline_boxes;
    }

    public void setDebug_draw_font_metrics(boolean debug_draw_font_metrics) {
        this.debug_draw_font_metrics = debug_draw_font_metrics;
    }

    public StyleReference getCss() {
        return css;
    }

    public void setCss(StyleReference css) {
        this.css = css;
    }

    public FSCanvas getCanvas() {
        return canvas;
    }

    public void setCanvas(FSCanvas canvas) {
        this.canvas = canvas;
    }

    public void setTempCanvas(Rectangle rect) {
        this.tempCanvas = rect;
    }

    public Rectangle getFixedRectangle() {
        //Uu.p("this = " + canvas);
        if (getCanvas() == null) {
            return this.tempCanvas;
        } else {
            Rectangle rect = getCanvas().getFixedRectangle();
            rect.translate(getCanvas().getX(), getCanvas().getY());
            return rect;
        }
    }

    public void setNamespaceHandler(NamespaceHandler nh) {
        namespaceHandler = nh;
    }

    public NamespaceHandler getNamespaceHandler() {
        return namespaceHandler;
    }

    public void addBoxId(String id, Box box) {
        if (idMap == null) {
            idMap = new HashMap<>();
        }
        idMap.put(id, box);
    }

    public Box getBoxById(String id) {
        if (idMap == null) {
            idMap = new HashMap<>();
        }
        return idMap.get(id);
    }

    public void removeBoxId(String id) {
        if (idMap != null) {
            idMap.remove(id);
        }
    }

    public Map getIdMap() {
        return idMap;
    }

    /**
     * Sets the textRenderer attribute of the RenderingContext object
     *
     * @param textRenderer The new textRenderer value
     */
    public void setTextRenderer(TextRenderer textRenderer) {
        this.textRenderer = textRenderer;
    }

    /**
     * Set the current media type. This is usually something like screen
     * or print . See the 
     * media section of the CSS 2.1 spec for more information on media
     * types.
     *
     * @param media The new media value
     */
    public void setMedia(String media) {
        this.media = media;
    }

    /**
     * Gets the uac attribute of the RenderingContext object
     *
     * @return The uac value (user agent).
     * @deprecated Use getUserAgentCallback instead for clearer code.
     */
    @Deprecated
    public UserAgentCallback getUac() {
        return uac;
    }

    public UserAgentCallback getUserAgentCallback() {
        return uac;
    }

    public void setUserAgentCallback(UserAgentCallback userAgentCallback) {
        StyleReference styleReference = getCss();
        if (styleReference != null) {
            styleReference.setUserAgentCallback(userAgentCallback);
        }
        uac = userAgentCallback;
    }

    /**
     * Gets the dPI attribute of the RenderingContext object
     *
     * @return The dPI value
     */
    public float getDPI() {
        return this.dpi;
    }

    /**
     * Sets the effective DPI (Dots Per Inch) of the screen. You should normally
     * never need to override the dpi, as it is already set to the system
     * default by Toolkit.getDefaultToolkit().getScreenResolution()
     * You can override the value if you want to scale EVERYTHING.
     *
     * @param dpi The new dPI value
     */
    public void setDPI(float dpi) {
        this.dpi = dpi;
        this.mmPerDot = (CM__PER__IN * MM__PER__CM) / dpi;
    }

    /**
     * Gets the dPI attribute in a more useful form of the RenderingContext object
     *
     * @return The dPI value
     */
    public float getMmPerDotParent() {
        return this.mmPerDot;
    }

    public FSFont getFont(FontSpecification spec) {
        return getFontResolver().resolveFont(this, spec);
    }

    //strike-through offset should always be half of the height of lowercase x...
    //and it is defined even for fonts without 'x'!
    public float getXHeight(FontContext fontContext, FontSpecification fs) {
        FSFont font = getFontResolver().resolveFont(this, fs);
        FSFontMetrics fm = getTextRenderer().getFSFontMetrics(fontContext, font, " ");
        float sto = fm.getStrikethroughOffset();
        return fm.getAscent() - 2 * Math.abs(sto) + fm.getStrikethroughThickness();
    }

    /**
     * Gets the baseURL attribute of the RenderingContext object
     *
     * @return The baseURL value
     */
    public String getBaseURL() {
        return uac.getBaseURL();
    }

    /**
     * Sets the baseURL attribute of the RenderingContext object
     *
     * @param url The new baseURL value
     */
    public void setBaseURL(String url) {
        uac.setBaseURL(url);
    }

    /**
     * Returns true if the currently set media type is paged. Currently returns
     * true only for print , projection , and embossed ,
     * handheld , and tv . See the media section of the CSS
     * 2.1 spec for more information on media types.
     *
     * @return The paged value
     */
    public boolean isPaged() {
        if (media.equals("print")) {
            return true;
        }
        if (media.equals("projection")) {
            return true;
        }
        if (media.equals("embossed")) {
            return true;
        }
        if (media.equals("handheld")) {
            return true;
        }
        if (media.equals("tv")) {
            return true;
        }
        return false;
    }

    public boolean isInteractive() {
        return interactive;
    }

    public void setInteractive(boolean interactive) {
        this.interactive = interactive;
    }

    public boolean isPrint() {
        return print;
    }

    public void setPrint(boolean print) {
        this.print = print;
        if (print) {
            setMedia("print");
        } else {
            setMedia("screen");
        }
    }

    public void setFontResolver(FontResolver resolver) {
        fontResolver = resolver;
    }

    /**
     * Get the internal dots measurement per CSS pixel.
     */
    public int getDotsPerPixel() {
        return dotsPerPixel;
    }

    /**
     * Set the internal dots measurement per CSS pixel.
     * @param dotsPerPixel
     */
    public void setDotsPerPixel(int dotsPerPixel) {
        this.dotsPerPixel = dotsPerPixel;
    }

    /**
     * Gets the resolved style for an element. All primitive properties will
     * have values.
     * 

* This method uses a cache. *

* If the parent element's style is not cached this method will recursively * work up the ancestor list until it styles the document with the initial values * of CSS properties. */ public CalculatedStyle getStyle(Element e) { CalculatedStyle result = styleMap.get(e); if (result == null) { Node parent = e.getParentNode(); CalculatedStyle parentCalculatedStyle = parent instanceof Document ? new EmptyStyle() : getStyle((Element) parent); result = parentCalculatedStyle.deriveStyle(getCss().getCascadedStyle(e, false)); styleMap.put(e, result); } return result; } public ReplacedElementFactory getReplacedElementFactory() { return replacedElementFactory; } public void setReplacedElementFactory(ReplacedElementFactory ref) { if (ref == null) { throw new NullPointerException("replacedElementFactory may not be null"); } this.replacedElementFactory = ref; } /** * Stores a default page width. * @return default page width or null. * @see #isDefaultPageSizeInches() */ public Float getDefaultPageWidth() { return this.defaultPageWidth; } /** * Stores a default page height. * @return default page height or null. * @see #isDefaultPageSizeInches() */ public Float getDefaultPageHeight() { return this.defaultPageHeight; } /** * If not, consider it as mm. * @return true if the page size is in inches, false if it is in mm. */ public boolean isDefaultPageSizeInches() { return this.defaultPageSizeIsInches; } /** * The replacement text to be used if a character cannot be * renderered by the current or fallback fonts. * @return the current replacement text, "#" by default */ public String getReplacementText() { return this.replacementText; } public void setReplacementText(String replacement) { this.replacementText = replacement; } /** * Set the default page dimensions. These may be overridden in CSS. * If not set in CSS and null here, A4 will be used. * @param pageWidth * @param pageHeight */ public void setDefaultPageSize(Float pageWidth, Float pageHeight, boolean isInches) { this.defaultPageWidth = pageWidth; this.defaultPageHeight = pageHeight; this.defaultPageSizeIsInches = isInches; } public FSTextBreaker getLineBreaker() { return lineBreaker; } public void setLineBreaker(FSTextBreaker breaker) { this.lineBreaker = breaker; } public FSTextBreaker getCharacterBreaker() { return characterBreaker; } public void setCharacterBreaker(FSTextBreaker breaker) { this.characterBreaker = breaker; } /** * This registers the shared context with a thread local so it * can be used anywhere. It should be matched with a call to * {@link #removeFromThread()} when the run is complete. */ public void registerWithThread() { ThreadCtx.get().setSharedContext(this); } /** * This removes the shared context from a thread local to avoid memory leaks. */ public void removeFromThread() { ThreadCtx.get().setSharedContext(null); } public FSTextTransformer getUnicodeToLowerTransformer() { return this._unicodeToLowerTransformer; } public FSTextTransformer getUnicodeToUpperTransformer() { return this._unicodeToUpperTransformer; } public FSTextTransformer getUnicodeToTitleTransformer() { return this._unicodeToTitleTransformer; } public void setUnicodeToLowerTransformer(FSTextTransformer tr) { this._unicodeToLowerTransformer = tr; } public void setUnicodeToUpperTransformer(FSTextTransformer tr) { this._unicodeToUpperTransformer = tr; } public void setUnicodeToTitleTransformer(FSTextTransformer tr) { this._unicodeToTitleTransformer = tr; } public RootCounterContext getGlobalCounterContext() { return _rootCounterContext; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy