org.xhtmlrenderer.swt.BasicRenderer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of core-renderer Show documentation
Show all versions of core-renderer Show documentation
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);
}
}
}