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

org.xhtmlrenderer.swt.BasicRenderer Maven / Gradle / Ivy

Go to download

An XML/XHTML CSS 2.1 Renderer library in pure Java for rendering to PDF, images, and Swing panels.

The newest version!
/*
 * {{{ header & license
 * Copyright (c) 2007 Vianney le Clément
 *
 * 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 org.xhtmlrenderer.swt;

import java.awt.Dimension;
import java.awt.Shape;
import java.awt.geom.Area;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.StringReader;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.*;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xhtmlrenderer.css.style.CalculatedStyle;
import org.xhtmlrenderer.css.style.derived.RectPropertySet;
import org.xhtmlrenderer.event.DocumentListener;
import org.xhtmlrenderer.extend.*;
import org.xhtmlrenderer.layout.BoxBuilder;
import org.xhtmlrenderer.layout.Layer;
import org.xhtmlrenderer.layout.LayoutContext;
import org.xhtmlrenderer.layout.SharedContext;
import org.xhtmlrenderer.render.BlockBox;
import org.xhtmlrenderer.render.Box;
import org.xhtmlrenderer.render.PageBox;
import org.xhtmlrenderer.render.RenderingContext;
import org.xhtmlrenderer.render.ViewportBox;
import org.xhtmlrenderer.resource.XMLResource;
import org.xhtmlrenderer.simple.NoNamespaceHandler;
import org.xhtmlrenderer.util.Configuration;
import org.xhtmlrenderer.util.Uu;
import org.xhtmlrenderer.util.XRLog;
import org.xml.sax.InputSource;

/**
 * Renders XML+CSS using SWT in a widget (a Composite). Scrollbars are handled
 * automatically.
 * 
 * @author Vianney le Clément
 */
public class BasicRenderer extends Canvas implements PaintListener, UserInterface, FSCanvas {
    private static final int PAGE_PAINTING_CLEARANCE = 10;

    private SharedContext _sharedContext;

    // TODO layout_context should not be stored!
    private LayoutContext _layout_context;

    private Image _layout_image = null; // Image and GC used in layout_context

    private GC _layout_gc = null;

    private float _fontScalingFactor = 1.2F;

    private float _minFontScale = 0.50F;

    private float _maxFontScale = 3.0F;

    private Document _doc = null;

    private BlockBox _rootBox = null;

    private Set _documentListeners = new HashSet();

    private boolean _needRelayout = false;

    private boolean _hasFixedContent = false;

    private boolean _noResize = false; // temp. deactivate resize code

    private Point _origin = new Point(0, 0);

    private Point _drawnSize = new Point(0, 0);

    private Image _offscreen = null;

    private SpecialRedraw _specialRedraw = null;

    private static int checkStyle(int style) {
        final int mask = SWT.BORDER;
        return (style & mask) | SWT.NO_REDRAW_RESIZE | SWT.NO_BACKGROUND | SWT.V_SCROLL
                | SWT.H_SCROLL | SWT.NO_RADIO_GROUP;
    }

    public BasicRenderer(Composite parent, int style) {
        this(parent, style, new NaiveUserAgent(parent.getDisplay()));
    }

    /**
     * Construct the BasicRenderer
     * 
     * @param parent
     * @param uac
     */
    public BasicRenderer(Composite parent, int style, UserAgentCallback uac) {
        super(parent, checkStyle(style));
        super.setLayout(null);
        setBackground(getDisplay().getSystemColor(SWT.COLOR_WHITE));
        setBackgroundMode(SWT.INHERIT_FORCE);

        _sharedContext = new SharedContext(uac, new SWTFontResolver(parent.getDisplay()),
                new SWTReplacedElementFactory(), new SWTTextRenderer(), getDisplay().getDPI().y);
        _sharedContext.setCanvas(this);

        getHorizontalBar().addListener(SWT.Selection, new Listener() {
            public void handleEvent(Event event) {
                ScrollBar bar = (ScrollBar) event.widget;
                int hSelection = bar.getSelection();
                scrollTo(new Point(hSelection, _origin.y));
            }
        });
        getVerticalBar().addListener(SWT.Selection, new Listener() {
            public void handleEvent(Event event) {
                ScrollBar bar = (ScrollBar) event.widget;
                int vSelection = bar.getSelection();
                scrollTo(new Point(_origin.x, vSelection));
            }
        });

        addPaintListener(this);
        addDisposeListener(new DisposeListener() {
            public void widgetDisposed(DisposeEvent e) {
                // dispose used fonts
                _sharedContext.flushFonts();
                // clean ReplacedElementFactory
                ReplacedElementFactory ref = _sharedContext.getReplacedElementFactory();
                if (ref instanceof SWTReplacedElementFactory) {
                    ((SWTReplacedElementFactory) ref).clean();
                }
                // dispose images when using NaiveUserAgent
                UserAgentCallback uac = _sharedContext.getUac();
                if (uac instanceof NaiveUserAgent) {
                    ((NaiveUserAgent) uac).disposeCache();
                }
                // dispose offscreen image
                if (_offscreen != null) {
                    _offscreen.dispose();
                }
                // dispose temp Image/GC
                if (_layout_image != null) {
                    _layout_gc.dispose();
                    _layout_image.dispose();
                }
            }
        });
        addListener(SWT.Resize, new Listener() {
            private Point _previousSize = null;

            public void handleEvent(Event event) {
                Point size = getScreenSize();
                if (getRootLayer() != null && !_noResize) {
                    if (!isPrint() && (_previousSize == null || size.x != _previousSize.x)) {
                        // Ask for relayout if the width has changed
                        relayout();
                    } else {
                        // Else, don't relayout, but update scrollbars
                        if (updateScrollBars()) {
                            relayout();
                        } else if (_offscreen != null) {
                            redrawSpecial(new RedrawNewSize(_previousSize));
                        }
                    }
                }
                _previousSize = size;
            }
        });
        addKeyListener(new KeyAdapter() {
            public void keyPressed(KeyEvent e) {
                Point pt = new Point(_origin.x, _origin.y);
                switch (e.keyCode) {
                    case SWT.ARROW_UP:
                        pt.y -= getVerticalBar().getIncrement();
                        break;
                    case SWT.ARROW_DOWN:
                        pt.y += getVerticalBar().getIncrement();
                        break;
                    case SWT.ARROW_LEFT:
                        pt.x -= getHorizontalBar().getIncrement();
                        break;
                    case SWT.ARROW_RIGHT:
                        pt.x += getHorizontalBar().getIncrement();
                        break;
                    case SWT.PAGE_UP:
                        pt.y -= getVerticalBar().getPageIncrement();
                        break;
                    case SWT.PAGE_DOWN:
                        pt.y += getVerticalBar().getPageIncrement();
                        break;
                    case SWT.HOME:
                        pt.x = 0;
                        pt.y = 0;
                        break;
                    case SWT.END:
                        pt.x = 0;
                        pt.y = _drawnSize.y; // will be fixed by setOrigin
                        break;
                }
                setOrigin(pt);
            }
        });

        updateScrollBars();
    }

    public void addDocumentListener(DocumentListener listener) {
        _documentListeners.add(listener);
    }

    public void removeDocumentListener(DocumentListener listener) {
        _documentListeners.remove(listener);
    }

    protected void fireDocumentLoaded() {
        Iterator it = _documentListeners.iterator();
        while (it.hasNext()) {
            ((DocumentListener) it.next()).documentLoaded();
        }
    }

    protected void fireOnLayoutException(Throwable t) {
        Iterator it = _documentListeners.iterator();
        while (it.hasNext()) {
            ((DocumentListener) it.next()).onLayoutException(t);
        }
    }

    protected void fireOnRenderException(Throwable t) {
        Iterator it = _documentListeners.iterator();
        while (it.hasNext()) {
            ((DocumentListener) it.next()).onRenderException(t);
        }
    }

    /**
     * A Renderer has no layout!
     */
    public void setLayout(Layout layout) {
    }

    /**
     * Do a full relayout and redraw
     */
    public void relayout() {
        _needRelayout = true;
        redraw();
    }

    /**
     * Invalidate the whole view. Redraw everything.
     */
    public void invalidate() {
        if (_offscreen != null) {
            _offscreen.dispose();
            _offscreen = null;
        }
        redraw();
    }

    private void redrawSpecial(SpecialRedraw type) {
        if (_hasFixedContent && !type.isForFixedContent()) {
            invalidate();
        } else if (_specialRedraw == null) {
            _specialRedraw = type;
            _specialRedraw.redraw();
        } else if (_specialRedraw.getClass().equals(type.getClass())
                && _specialRedraw.ignoreFurther()) {
            _specialRedraw.redraw();
        } else {
            invalidate();
        }
    }

    /**
     * Redraw only rect.
     * 
     * @param rect
     *            the rectangle
     */
    public void invalidate(Rectangle rect) {
        Rectangle r = getClientArea();
        r.intersect(rect);
        redrawSpecial(new RedrawTarget(r));
    }

    /**
     * @return a new {@link LayoutContext}
     */
    protected LayoutContext newLayoutcontext() {
        LayoutContext result = _sharedContext.newLayoutContextInstance();

        if (_layout_gc == null) {
            _layout_image = new Image(getDisplay(), 1, 1);
            _layout_gc = new GC(_layout_image);
        }

        result.setFontContext(new SWTFontContext(_layout_gc));
        _sharedContext.getTextRenderer().setup(result.getFontContext());

        return result;
    }

    /**
     * @param gc
     * @return a new {@link RenderingContext}
     */
    protected RenderingContext newRenderingContext(GC gc) {
        RenderingContext result = _sharedContext.newRenderingContextInstance();

        result.setFontContext(new SWTFontContext(gc));
        result.setOutputDevice(new SWTOutputDevice(gc));

        _sharedContext.getTextRenderer().setup(result.getFontContext());

        return result;
    }

    protected java.awt.Rectangle getInitialExtents(LayoutContext c) {
        if (!c.isPrint()) {
            Point size = getScreenSize();
            if (size.x == 0 && size.y == 0) {
                size.x = 1;
                size.y = 1;
            }
            return new java.awt.Rectangle(size.x, size.y);
        } else {
            PageBox first = Layer.createPageBox(c, "first");
            return new java.awt.Rectangle(0, 0, first.getContentWidth(c), first.getContentHeight(c));
        }
    }

    /**
     * @return the size of the drawable screen
     */
    public Point getScreenSize() {
        org.eclipse.swt.graphics.Rectangle rect = getClientArea();
        return new Point(rect.width, rect.height);
    }

    public Point computeSize(int wHint, int hHint, boolean changed) {
        return _drawnSize;
    }

    public java.awt.Rectangle getFixedRectangle() {
        Point size = getScreenSize();
        return new java.awt.Rectangle(0, 0, size.x, size.y);
    }

    public int getX() {
        return -_origin.x;
    }

    public int getY() {
        return -_origin.y;
    }

    /**
     * Check (and correct) the point to be within origin bounds.
     */
    private Point checkOrigin(Point pt) {
        Point size = getScreenSize();
        Point p = new Point(pt.x, pt.y);

        if (p.x > _drawnSize.x - size.x) {
            p.x = _drawnSize.x - size.x;
        }
        if (p.x < 0) {
            p.x = 0;
        }

        if (p.y > _drawnSize.y - size.y) {
            p.y = _drawnSize.y - size.y;
        }
        if (p.y < 0) {
            p.y = 0;
        }

        return p;
    }

    /**
     * @return the origin of the view
     */
    public Point getOrigin() {
        return _origin;
    }

    /**
     * Set the origin of the view. NOTE: this won't be done immediately.
     * 
     * @param pt
     */
    public void setOrigin(Point pt) {
        Point p = checkOrigin(pt);
        if (p.equals(_origin))
            return;
        getHorizontalBar().setSelection(p.x);
        getVerticalBar().setSelection(p.y);
        scrollTo(p);
    }

    protected void scrollTo(Point pt) {
        if (_origin.equals(pt)) {
            return;
        }

        if (_offscreen != null) {
            redrawSpecial(new RedrawNewOrigin(_origin));
        }

        Control[] children = getChildren();
        for (int i = 0; i < children.length; i++) {
            Point loc = children[i].getLocation();
            loc.x += _origin.x - pt.x;
            loc.y += _origin.y - pt.y;
            children[i].setLocation(loc);
        }

        _origin = pt;
        redraw();
    }

    /**
     * Update the scrollbars
     * 
     * @return true if we need to relayout the whole thing
     */
    protected boolean updateScrollBars() {
        Point size = getScreenSize();
        ScrollBar hBar = getHorizontalBar(), vBar = getVerticalBar();
        boolean needRelayout = false;

        hBar.setMaximum(_drawnSize.x);
        hBar.setThumb(Math.min(_drawnSize.x, size.x));
        hBar.setIncrement(15); // TODO something meaningful ?
        hBar.setPageIncrement(size.x);
        boolean visible = !(_origin.x == 0 && _drawnSize.x <= size.x);
        hBar.setVisible(visible);

        size = getScreenSize();

        vBar.setMaximum(_drawnSize.y);
        vBar.setThumb(Math.min(_drawnSize.y, size.y));
        vBar.setIncrement(15); // TODO line height here
        vBar.setPageIncrement(size.y);
        visible = !(_origin.y == 0 && _drawnSize.y <= size.y);
        if (!isPrint() && vBar.isVisible() != visible) {
            needRelayout = true;
        }
        vBar.setVisible(visible);

        return needRelayout;
    }

    /**
     * Convert an SWT rectangle into an AWT rectangle.
     * 
     * @param rect
     * @return
     */
    private static java.awt.Rectangle convertRectangle(Rectangle rect) {
        return new java.awt.Rectangle(rect.x, rect.y, rect.width, rect.height);
    }

    public void paintControl(PaintEvent e) {
        if (_doc == null) {
            // just draw background
            e.gc.fillRectangle(getClientArea());
        }

        // if this is the first time painting this document, then calc layout
        Layer root = getRootLayer();
        if (root == null || _needRelayout) {
            doLayout();
            root = getRootLayer();
            if (_offscreen != null) {
                // invalidate offscreen image
                _offscreen.dispose();
                _offscreen = null;
            }
        }
        _needRelayout = false;
        if (root == null) {
            XRLog.render(Level.FINE, "skipping the actual painting");
        } else {
            Point size = getScreenSize();
            // make sure origin is within the bounds
            Point origin = checkOrigin(_origin);
            if (!origin.equals(_origin)) {
                // the origin has been corrected
                if (_offscreen != null) {
                    if (_hasFixedContent
                            || (_specialRedraw != null && !(_specialRedraw instanceof RedrawNewOrigin))) {
                        _offscreen.dispose();
                        _offscreen = null;
                    } else if (_specialRedraw == null) {
                        _specialRedraw = new RedrawNewOrigin(_origin);
                    }
                }
            }
            _origin = origin;
            // redraw offscreen if needed
            if (_offscreen == null) { // full redraw
                _offscreen = new Image(getDisplay(), size.x, size.y);
                GC gc = new GC(_offscreen);
                RenderingContext c = newRenderingContext(gc);
                c.getOutputDevice().setClip(new java.awt.Rectangle(0, 0, size.x, size.y));
                doRender(c);
                gc.dispose();
            } else if (_specialRedraw instanceof RedrawTarget) { // targetted
                Rectangle target = ((RedrawTarget) _specialRedraw)._target;
                GC gc = new GC(_offscreen);
                RenderingContext c = newRenderingContext(gc);
                c.getOutputDevice().setClip(convertRectangle(target));
                doRender(c);
                gc.dispose();
            } else if (_specialRedraw instanceof RedrawNewOrigin) { // scroll
                Point previousOrigin = ((RedrawNewOrigin) _specialRedraw)._previousOrigin;
                Image img = new Image(getDisplay(), size.x, size.y);
                GC gc = new GC(img);
                gc.drawImage(_offscreen, previousOrigin.x - _origin.x, previousOrigin.y
                                - _origin.y);
                Area a = new Area();
                if (_origin.x < previousOrigin.x) {
                    int width = Math.min(size.x, previousOrigin.x - _origin.x);
                    a.add(new Area(new java.awt.Rectangle(0, 0, width, size.y)));
                } else if (_origin.x > previousOrigin.x) {
                    int width = Math.min(size.x, _origin.x - previousOrigin.x);
                    a.add(new Area(new java.awt.Rectangle(size.x - width, 0, width, size.y)));
                }
                if (_origin.y < previousOrigin.y) {
                    int height = Math.min(size.y, previousOrigin.y - _origin.y);
                    a.add(new Area(new java.awt.Rectangle(0, 0, size.x, height)));
                } else if (_origin.y > previousOrigin.y) {
                    int height = Math.min(size.y, _origin.y - previousOrigin.y);
                    a.add(new Area(new java.awt.Rectangle(0, size.y - height, size.x, height)));
                }
                RenderingContext c = newRenderingContext(gc);
                c.getOutputDevice().setClip(a);
                doRender(c);
                gc.dispose();
                _offscreen.dispose();
                _offscreen = img;
            } else if (_specialRedraw instanceof RedrawNewSize) { // adjust
                // size
                Point previousSize = ((RedrawNewSize) _specialRedraw)._previousSize;
                Image img = new Image(getDisplay(), size.x, size.y);
                GC gc = new GC(img);
                gc.drawImage(_offscreen, 0, 0);
                if (size.x > previousSize.x || size.y > previousSize.y) {
                    Area a = new Area();
                    if (size.x > previousSize.x) {
                        a.add(new Area(new java.awt.Rectangle(previousSize.x, 0, size.x
                                - previousSize.x, size.y)));
                    }
                    if (size.y > previousSize.y) {
                        a.add(new Area(new java.awt.Rectangle(0, previousSize.y, size.x, size.y
                                - previousSize.y)));
                    }
                    RenderingContext c = newRenderingContext(gc);
                    c.getOutputDevice().setClip(a);
                    doRender(c);
                    gc.setClipping((Rectangle) null);
                }
                gc.dispose();
                _offscreen.dispose();
                _offscreen = img;
            }
            // draw on screen
            e.gc.drawImage(_offscreen, 0, 0);
        }
        _specialRedraw = null;
    }

    protected void doLayout() {
        if (_doc == null) {
            return;
        }

        _layout_context = newLayoutcontext();

        try {
            long start = System.currentTimeMillis();

            if (_rootBox != null && _needRelayout) {
                _rootBox.reset(_layout_context);
            } else {
                _rootBox = BoxBuilder.createRootBox(_layout_context, _doc);
            }

            _rootBox.setContainingBlock(new ViewportBox(getInitialExtents(_layout_context)));
            _rootBox.layout(_layout_context);

            long end = System.currentTimeMillis();
            XRLog.layout(Level.INFO, "Layout took " + (end - start) + "ms");
        } catch (Throwable e) {
            XRLog.exception(e.getMessage(), e);
            e.printStackTrace();
        }

        Layer rootLayer = _rootBox.getLayer();
        _hasFixedContent = rootLayer.containsFixedContent();

        XRLog.layout(Level.FINEST, "after layout: " + _rootBox);

        // update scrollbars
        Dimension intrinsic_size = rootLayer.getPaintingDimension(_layout_context);
        if (_layout_context.isPrint()) {
            rootLayer.trimEmptyPages(_layout_context, intrinsic_size.height);
            if (rootLayer.getLastPage() != null) {
                rootLayer.assignPagePaintingPositions(_layout_context, Layer.PAGED_MODE_SCREEN,
                        PAGE_PAINTING_CLEARANCE);
                _drawnSize = new Point(rootLayer.getMaxPageWidth(_layout_context,
                        PAGE_PAINTING_CLEARANCE), rootLayer.getLastPage().getPaintingBottom()
                        + PAGE_PAINTING_CLEARANCE);
            } else {
                _drawnSize = new Point(0, 0);
            }
        } else {
            _drawnSize = new Point(intrinsic_size.width, intrinsic_size.height);
        }

        _noResize = true;
        if (updateScrollBars()) {
            doLayout();
        }
        _noResize = false;

        // TODO call only once? in display.asyncExec?
        fireDocumentLoaded();
    }

    protected void doRender(RenderingContext c) {
        try {
            c.getOutputDevice().translate(-_origin.x, -_origin.y);
            long start = System.currentTimeMillis();
            if (c.isPrint()) {
                paintPagedView(c, _rootBox.getLayer());
            } else {
                _rootBox.getLayer().paint(c);
            }
            long after = System.currentTimeMillis();
            if (Configuration.isTrue("xr.incremental.repaint.print-timing", false)) {
                Uu.p("repaint took ms: " + (after - start));
            }
        } catch (Throwable e) {
            XRLog.exception(e.getMessage(), e);
        }
        ((SWTOutputDevice) c.getOutputDevice()).clean();
    }

    private void paintPagedView(RenderingContext c, Layer root) {
        if (root.getLastPage() == null) {
            return;
        }

        SWTOutputDevice out = (SWTOutputDevice) c.getOutputDevice();
        GC gc = out.getGC();
        Shape working = out.getClip();

        List pages = root.getPages();
        c.setPageCount(pages.size());
        for (int i = 0; i < pages.size(); i++) {
            PageBox page = (PageBox) pages.get(i);
            c.setPage(i, page);

            java.awt.Rectangle overall = page.getScreenPaintingBounds(c, PAGE_PAINTING_CLEARANCE);
            overall.x -= 1;
            overall.y -= 1;
            overall.width += 1;
            overall.height += 1;

            java.awt.Rectangle bounds = new java.awt.Rectangle(overall);
            bounds.width += 1;
            bounds.height += 1;
            if (working.intersects(bounds)) {
                page.paintBackground(c, PAGE_PAINTING_CLEARANCE, Layer.PAGED_MODE_SCREEN);
                page.paintMarginAreas(c, PAGE_PAINTING_CLEARANCE, Layer.PAGED_MODE_SCREEN);
                page.paintBorder(c, PAGE_PAINTING_CLEARANCE, Layer.PAGED_MODE_SCREEN);

                Color old = gc.getForeground();
                gc.setForeground(gc.getDevice().getSystemColor(SWT.COLOR_BLACK));
                gc.drawRectangle(overall.x, overall.y, overall.width, overall.height);
                gc.setForeground(old);

                java.awt.Rectangle content = page.getPagedViewClippingBounds(c,
                        PAGE_PAINTING_CLEARANCE);
                out.clip(content);

                int left = PAGE_PAINTING_CLEARANCE
                        + page.getMarginBorderPadding(c, CalculatedStyle.LEFT);
                int top = page.getPaintingTop()
                        + page.getMarginBorderPadding(c, CalculatedStyle.TOP) - page.getTop();

                out.translate(left, top);
                root.paint(c);
                out.translate(-left, -top);

                out.setClip(working);
            }
        }

        out.setClip(working);
    }

    public Document getDocument() {
        return _doc;
    }

    /**
     * Reload the current document.
     */
    public void reload() {
        if (_doc == null) {
            return;
        }
        _rootBox = null;
        _active_element = null;
        _hovered_element = null;
        _focus_element = null;
        if (Configuration.isTrue("xr.cache.stylesheets", true)) {
            _sharedContext.getCss().flushStyleSheets();
        } else {
            _sharedContext.getCss().flushAllStyleSheets();
        }

        setCursor(null);
        _sharedContext.reset();
        if (_offscreen != null) {
            _offscreen.dispose();
            _offscreen = null;
        }
        _origin = new Point(0, 0);
        getHorizontalBar().setSelection(0);
        getVerticalBar().setSelection(0);
        redraw();
    }

    public void setDocument(Document doc, String url, NamespaceHandler nsh) {
        _rootBox = null;
        _doc = doc;

        _active_element = null;
        _hovered_element = null;
        _focus_element = null;

        // have to do this first
        if (Configuration.isTrue("xr.cache.stylesheets", true)) {
            _sharedContext.getCss().flushStyleSheets();
        } else {
            _sharedContext.getCss().flushAllStyleSheets();
        }

        setCursor(null);
        _sharedContext.reset();
        if (_offscreen != null) {
            _offscreen.dispose();
            _offscreen = null;
        }
        _origin = new Point(0, 0);
        getHorizontalBar().setSelection(0);
        getVerticalBar().setSelection(0);

        if (doc == null) {
            _drawnSize = new Point(1, 1);
            updateScrollBars();
        } else {
            _sharedContext.setBaseURL(url);
            _sharedContext.setNamespaceHandler(nsh);
            _sharedContext.getCss().setDocumentContext(_sharedContext,
                    _sharedContext.getNamespaceHandler(), doc, this);
        }

        redraw();
    }

    public void setDocument(InputStream stream, String url, NamespaceHandler nsh) {
        Document dom = XMLResource.load(stream).getDocument();

        setDocument(dom, url, nsh);
    }

    public void setDocumentFromString(String content, String url, NamespaceHandler nsh) {
        InputSource is = new InputSource(new BufferedReader(new StringReader(content)));
        Document dom = XMLResource.load(is).getDocument();

        setDocument(dom, url, nsh);
    }

    public void setDocument(Document doc, String url) {
        setDocument(doc, url, new NoNamespaceHandler());
    }

    public void setDocument(String url) {
        setDocument(loadDocument(url), url, new NoNamespaceHandler());
    }

    public void setDocument(String url, NamespaceHandler nsh) {
        setDocument(loadDocument(url), url, nsh);
    }

    public void setDocument(InputStream stream, String url) {
        setDocument(stream, url, new NoNamespaceHandler());
    }

    private boolean isAnchorInCurrentDocument(String str) {
        return str.charAt(0) == '#';
    }

    private String getAnchorId(String url) {
        return url.substring(1, url.length());
    }

    /**
     * Sets the new current document, where the new document is located
     * relative, e.g using a relative URL.
     * 
     * @param filename
     *            The new document to load
     */
    protected void setDocumentRelative(String filename) {
        String url = _sharedContext.getUac().resolveURI(filename);
        if (isAnchorInCurrentDocument(filename)) {
            String id = getAnchorId(filename);
            Box box = _sharedContext.getBoxById(id);
            if (box != null) {
                Point pt;
                if (box.getStyle().isInline()) {
                    pt = new Point(0 /* box.getAbsX() */, box.getAbsY());
                } else {
                    RectPropertySet margin = box.getMargin(_layout_context);
                    pt = new Point(0 /* box.getAbsX() + (int) margin.left() */, box.getAbsY()
                            + (int) margin.top());
                }
                setOrigin(pt);
                return;
            }
        }
        Document dom = loadDocument(url);
        setDocument(dom, url);
    }

    protected Document loadDocument(final String uri) {
        XMLResource xmlResource = _sharedContext.getUac().getXMLResource(uri);
        if (xmlResource == null) {
            return null;
        }
        return xmlResource.getDocument();
    }

    public String getDocumentTitle() {
        if (_doc == null) {
            return null;
        }
        NamespaceHandler nsh = getSharedContext().getNamespaceHandler();
        if (nsh == null) {
            return null;
        }
        return nsh.getDocumentTitle(_doc);
    }

    public Box getRootBox() {
        return _rootBox;
    }

    public Layer getRootLayer() {
        return getRootBox() == null ? null : getRootBox().getLayer();
    }

    public SharedContext getSharedContext() {
        return _sharedContext;
    }

    public LayoutContext getLayoutContext() {
        return _layout_context;
    }

    public Box find(int x, int y) {
        Layer l = getRootLayer();
        if (l != null) {
            return l.find(_layout_context, x + _origin.x, y + _origin.y, false);
        }
        return null;
    }

    private Element _hovered_element = null;

    private Element _active_element = null;

    private Element _focus_element = null;

    public boolean isHover(org.w3c.dom.Element e) {
        if (e == _hovered_element) {
            return true;
        }
        return false;
    }

    public Element getHovered_element() {
        return _hovered_element;
    }

    public void setHovered_element(Element hovered_element) {
        _hovered_element = hovered_element;
    }

    public boolean isActive(org.w3c.dom.Element e) {
        if (e == _active_element) {
            return true;
        }
        return false;
    }

    public Element getActive_element() {
        return _active_element;
    }

    public void setActive_element(Element active_element) {
        _active_element = active_element;
    }

    public boolean isFocus(org.w3c.dom.Element e) {
        if (e == _focus_element) {
            return true;
        }
        return false;
    }

    public Element getFocus_element() {
        return _focus_element;
    }

    public void setFocus_element(Element focus_element) {
        _focus_element = focus_element;
    }

    public boolean isPrint() {
        return _sharedContext.isPrint();
    }

    public void setPrint(boolean print) {
        _sharedContext.setPrint(print);
        _sharedContext.setInteractive(!print);
        _sharedContext.getReplacedElementFactory().reset();
        reload();
    }

    /**
     * Sets the scaling factor used by {@link #incrementFontSize()} and
     * {@link #decrementFontSize()}--both scale the font up or down by this
     * scaling factor. The scaling roughly modifies the font size as a
     * multiplier or divisor. A scaling factor of 1.2 applied against a font
     * size of 10pt results in a scaled font of 12pt. The default scaling factor
     * is 1.2F.
     */
    public void setFontScalingFactor(float scaling) {
        _fontScalingFactor = scaling;
    }

    /**
     * Increments all rendered fonts on the current document by the current
     * scaling factor for the panel. Scaling applies culmulatively, which means
     * that multiple calls to this method scale fonts larger and larger by
     * applying the current scaling factor against itself. You can modify the
     * scaling factor by {@link #setFontScalingFactor(float)}, and reset to the
     * document's specified font size with {@link #resetFontSize()}.
     */
    public void incrementFontSize() {
        scaleFont(_fontScalingFactor);
    }

    /**
     * Resets all rendered fonts on the current document to the font size
     * specified in the document's styling instructions.
     */
    public void resetFontSize() {
        getSharedContext().getTextRenderer().setFontScale(1f);
        reload();
    }

    /**
     * Decrements all rendered fonts on the current document by the current
     * scaling factor for the panel. Scaling applies culmulatively, which means
     * that multiple calls to this method scale fonts smaller and smaller by
     * applying the current scaling factor against itself. You can modify the
     * scaling factor by {@link #setFontScalingFactor(float)}, and reset to the
     * document's specified font size with {@link #resetFontSize()}.
     */
    public void decrementFontSize() {
        scaleFont(1 / _fontScalingFactor);
    }

    /**
     * Applies a change in scale for fonts using the rendering context's text
     * renderer.
     */
    private void scaleFont(float scaleBy) {
        TextRenderer tr = getSharedContext().getTextRenderer();
        float fs = tr.getFontScale() * scaleBy;
        if (fs < _minFontScale || fs > _maxFontScale) {
            return;
        }
        tr.setFontScale(fs);
        reload();
    }

    /**
     * Returns the maximum font scaling that may be applied, e.g. 3 times
     * assigned font size.
     */
    public float getMaxFontScale() {
        return _maxFontScale;
    }

    /**
     * Returns the minimum font scaling that may be applied, e.g. 0.5 times
     * assigned font size.
     */
    public float getMinFontScale() {
        return _minFontScale;
    }

    /**
     * Sets the maximum font scaling that may be applied, e.g. 3 times assigned
     * font size. Calling incrementFontSize() after this scale has been reached
     * doesn't have an effect.
     */
    public void setMaxFontScale(float f) {
        _maxFontScale = f;
    }

    /**
     * Sets the minimum font scaling that may be applied, e.g. 3 times assigned
     * font size. Calling decrementFontSize() after this scale has been reached
     * doesn't have an effect.
     */
    public void setMinFontScale(float f) {
        _minFontScale = f;
    }

    /**
     * Information about a special way of redrawing.
     */
    private abstract class SpecialRedraw {
        /**
         * @return true if this special redraw method can also be
         *         applied when there is fixed content
         */
        abstract boolean isForFixedContent();

        /**
         * @return true if special redraws of the same kind (but
         *         with other parameters) should be ignored
         */
        abstract boolean ignoreFurther();

        /**
         * Trigger redraw
         */
        void redraw() {
            BasicRenderer.this.redraw();
        }
    }

    private class RedrawNewSize extends SpecialRedraw {
        final Point _previousSize;

        RedrawNewSize(Point previousSize) {
            _previousSize = previousSize;
        }

        boolean isForFixedContent() {
            return false;
        }

        boolean ignoreFurther() {
            return true;
        }
    }

    private class RedrawNewOrigin extends SpecialRedraw {
        final Point _previousOrigin;

        RedrawNewOrigin(Point previousOrigin) {
            _previousOrigin = previousOrigin;
        }

        boolean isForFixedContent() {
            return false;
        }

        boolean ignoreFurther() {
            return true;
        }
    }

    private class RedrawTarget extends SpecialRedraw {
        final Rectangle _target;

        RedrawTarget(Rectangle target) {
            _target = target;
        }

        boolean isForFixedContent() {
            return true;
        }

        boolean ignoreFurther() {
            return false;
        }

        void redraw() {
            BasicRenderer.this.redraw(_target.x, _target.y, _target.width, _target.height, true);
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy