ASF Bugzilla – Attachment 14426 Details for
Bug 33760
[Patch] current AWTRenderer
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
patch agains head for AWTRenderer
Java2DRenderer.patch (text/plain), 72.10 KB, created by
renaud richardet
on 2005-03-08 03:25:02 UTC
(
hide
)
Description:
patch agains head for AWTRenderer
Filename:
MIME Type:
Creator:
renaud richardet
Created:
2005-03-08 03:25:02 UTC
Size:
72.10 KB
patch
obsolete
>Index: src/java/org/apache/fop/render/awt/AWTRenderer.java >=================================================================== >RCS file: /home/cvspublic/xml-fop/src/java/org/apache/fop/render/awt/AWTRenderer.java,v >retrieving revision 1.33 >diff -u -r1.33 AWTRenderer.java >--- src/java/org/apache/fop/render/awt/AWTRenderer.java 24 Nov 2004 21:07:30 -0000 1.33 >+++ src/java/org/apache/fop/render/awt/AWTRenderer.java 8 Mar 2005 02:00:45 -0000 >@@ -1,6 +1,6 @@ > /* >- * Copyright 1999-2004 The Apache Software Foundation. >- * >+ * Copyright 1999-2005 The Apache Software Foundation. >+ * > * Licensed under the Apache License, Version 2.0 (the "License"); > * you may not use this file except in compliance with the License. > * You may obtain a copy of the License at >@@ -27,6 +27,8 @@ > > // Java > import java.awt.Color; >+import java.awt.Component; >+import java.awt.Container; > import java.awt.Dimension; > import java.awt.Graphics; > import java.awt.Graphics2D; >@@ -35,70 +37,136 @@ > import java.awt.event.WindowAdapter; > import java.awt.event.WindowEvent; > import java.awt.geom.AffineTransform; >+import java.awt.geom.Line2D; >+import java.awt.geom.NoninvertibleTransformException; > import java.awt.geom.Rectangle2D; > import java.awt.image.BufferedImage; >+import java.awt.image.ColorModel; >+import java.awt.image.MemoryImageSource; > import java.awt.print.PageFormat; > import java.awt.print.Pageable; > import java.awt.print.Printable; > import java.io.IOException; > import java.io.OutputStream; >+import java.util.Iterator; >+import java.util.List; > import java.util.Map; > import java.util.Vector; > >-import org.apache.fop.fonts.FontInfo; >+import org.apache.batik.bridge.BridgeContext; >+import org.apache.batik.bridge.GVTBuilder; >+import org.apache.batik.bridge.ViewBox; >+import org.apache.batik.gvt.GraphicsNode; > import org.apache.fop.apps.FOPException; > import org.apache.fop.apps.FOUserAgent; > import org.apache.fop.area.Area; >+import org.apache.fop.area.Block; >+import org.apache.fop.area.BlockViewport; >+import org.apache.fop.area.CTM; > import org.apache.fop.area.Page; > import org.apache.fop.area.PageViewport; >-import org.apache.fop.area.RegionViewport; > import org.apache.fop.area.Trait; >+import org.apache.fop.area.inline.Character; >+import org.apache.fop.area.inline.ForeignObject; >+import org.apache.fop.area.inline.Image; >+import org.apache.fop.area.inline.InlineArea; >+import org.apache.fop.area.inline.Leader; > import org.apache.fop.area.inline.TextArea; > import org.apache.fop.datatypes.ColorType; >+import org.apache.fop.fo.Constants; >+import org.apache.fop.fo.properties.ColorTypeProperty; >+import org.apache.fop.fonts.Font; >+import org.apache.fop.fonts.FontInfo; >+import org.apache.fop.fonts.FontMetrics; > import org.apache.fop.image.FopImage; > import org.apache.fop.image.ImageFactory; >+import org.apache.fop.image.XMLImage; > import org.apache.fop.render.AbstractRenderer; >-import org.apache.fop.traits.BorderProps; >-import org.apache.fop.render.awt.FontMetricsMapper; >+import org.apache.fop.render.RendererContext; > import org.apache.fop.render.awt.viewer.PreviewDialog; > import org.apache.fop.render.awt.viewer.Translator; >+import org.apache.fop.render.pdf.CTMHelper; >+import org.apache.fop.svg.SVGUserAgent; >+import org.apache.fop.traits.BorderProps; >+import org.w3c.dom.Document; >+import org.w3c.dom.svg.SVGDocument; >+import org.w3c.dom.svg.SVGSVGElement; > > /** >- * This is FOP's AWT renderer. >+ * The <code>Java2DRenderer</code> class provides the abstract technical >+ * foundation for all rendering with the Java2D API. Renderers like >+ * <code>AWTRenderer</code> subclass it and provide the concrete output paths. >+ * <p> >+ * A lot of the logic is performed by <code>AbstractRenderer</code>. The >+ * class-variables <code>currentIPPosition</code> and >+ * <code>currentBPPosition</code> hold the position of the currently rendered >+ * area. >+ * <p> >+ * <code>AWTGraphicsState state</code> holds the <code>Graphics2D</code>, >+ * which is used along the whole rendering. <code>state</code> also acts as a >+ * stack (<code>state.push()</code> and <code>state.pop()</code>). >+ * <p> >+ * The rendering process is basically always the same: >+ * <p> >+ * <code>void renderXXXXX(Area area) { >+ * //calculate the currentPosition >+ * state.updateFont(name, size, null); >+ * state.updateColor(ct, false, null); >+ * state.getGraph.draw(new Shape(args)); >+ * }</code> >+ * > */ >-public class AWTRenderer extends AbstractRenderer implements Printable, Pageable { >+public class AWTRenderer extends AbstractRenderer implements Printable, >+ Pageable { > >- /** The MIME type for PostScript */ >+ /** The MIME type for AWT-Rendering */ > public static final String MIME_TYPE = "application/awt"; > > protected double scaleFactor = 100.0; >+ > protected int pageNumber = 0; >+ > private int pageWidth = 0; >+ > private int pageHeight = 0; >+ > private Vector pageViewportList = new java.util.Vector(); >+ > private Vector pageList = new java.util.Vector(); >+ > private Vector bufferedImageList = new java.util.Vector(); >- private BufferedImage currentPageImage = null; >- >+ >+ protected BufferedImage currentPageImage = null; >+ >+ protected boolean antialiasing = true; >+ >+ protected boolean qualityRendering = true; >+ >+ /** The current state, holds a Graphics2D and its context */ >+ protected AWTGraphicsState state; >+ >+ /** a Line2D.Float used to draw text decorations and leaders */ >+ protected Line2D.Float line = new Line2D.Float(); >+ > /** Font configuration */ > protected FontInfo fontInfo; > >- /** >- * The resource bundle used for AWT messages. >- */ >+ /** The resource bundle used for AWT messages. */ > protected Translator translator = null; > > private Map fontNames = new java.util.Hashtable(); >+ > private Map fontStyles = new java.util.Hashtable(); >- private Color saveColor = null; > > /** >- * The preview dialog frame used for display of the documents. >- * Also used as the AWT Component for FontSetup in generating >- * valid font measures. >+ * The preview dialog frame used for display of the documents. Also used as >+ * the AWT Component for FontSetup in generating valid font measures. > */ > protected PreviewDialog frame; > >+ /** Flag for visual-debugging */ >+ public boolean debug = false; >+ > public AWTRenderer() { > translator = new Translator(); > } >@@ -124,11 +192,16 @@ > return translator; > } > >+ /** @see org.apache.fop.render.AbstractRenderer */ >+ public String getMimeType() { >+ return MIME_TYPE; >+ } >+ > public void setupFontInfo(FontInfo inFontInfo) { > // create a temp Image to test font metrics on > fontInfo = inFontInfo; >- BufferedImage fontImage = >- new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB); >+ BufferedImage fontImage = new BufferedImage(100, 100, >+ BufferedImage.TYPE_INT_RGB); > FontSetup.setup(fontInfo, fontImage.createGraphics()); > } > >@@ -148,19 +221,19 @@ > return scaleFactor; > } > >- public void startRenderer(OutputStream out) >- throws IOException { >+ public void startRenderer(OutputStream out) throws IOException { > // empty pageViewportList, in case of a reload from PreviewDialog > pageViewportList.removeAllElements(); > pageList.removeAllElements(); > bufferedImageList.removeAllElements(); >- System.out.println("\nRegion Types: 0-Before/Top, 1-Start/Left, 2-Body, 3-End/Right, 4-After/Bottom"); >+ System.out.println("\nRegion Types: 0-Before/Top, 1-Start/Left," >+ + " 2-Body, 3-End/Right, 4-After/Bottom"); > } > >- public void stopRenderer() >- throws IOException { >+ public void stopRenderer() throws IOException { > frame.setStatus(translator.getString("Status.Show")); > frame.showPage(); >+ // TODO set all vars to null for gc > } > > // Printable Interface >@@ -188,7 +261,7 @@ > } > }); > >- //Centers the window >+ // Centers the window > Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); > Dimension frameSize = frame.getSize(); > if (frameSize.height > screenSize.height) { >@@ -198,52 +271,68 @@ > frameSize.width = screenSize.width; > } > frame.setLocation((screenSize.width - frameSize.width) / 2, >- (screenSize.height - frameSize.height) / 2); >+ (screenSize.height - frameSize.height) / 2); > frame.setVisible(true); > frame.setStatus(translator.getString("Status.Build.FO.tree")); > return frame; > } > >- /** This method override only stores the PageViewport in a vector. >- * No actual rendering performed -- this is done by getPageImage(pageNum) instead. >- * @param pageViewport the <code>PageViewport</code> object supplied by the Area Tree >- * @see org.apache.fop.render.Renderer >- */ >- public void renderPage(PageViewport pageViewport) throws IOException, FOPException { >+ /** >+ * This method override only stores the PageViewport in a vector. No actual >+ * rendering performed -- this is done by getPageImage(pageNum) instead. >+ * >+ * @param pageViewport the <code>PageViewport</code> object supplied by >+ * the Area Tree >+ * @see org.apache.fop.render.Renderer >+ */ >+ public void renderPage(PageViewport pageViewport) throws IOException, >+ FOPException { > pageViewportList.add(pageViewport); > pageList.add(pageViewport.getPage().clone()); >- bufferedImageList.add(getPageImage(pageViewport)); >+ bufferedImageList >+ .add(getPageImage(pageViewport, pageViewport.getPage())); > } > > public BufferedImage getBufferedPageImage(int pageNum) throws FOPException { > return (BufferedImage) bufferedImageList.get(pageNum); > } > >- /** Generates a desired page from the renderer's page viewport vector. >+ /** >+ * Generates a desired page from the renderer's page viewport vector. >+ * > * @param pageNum the 0-based page number to generate >- * @return the <code>java.awt.image.BufferedImage</code> corresponding to the page >- * @throws FOPException in case of an out-of-range page number requested >- */ >- public BufferedImage getPageImage(PageViewport pageViewport) throws FOPException { >- Page page = pageViewport.getPage(); >+ * @return the <code>java.awt.image.BufferedImage</code> corresponding to >+ * the page >+ * @throws FOPException in case of an out-of-range page number requested >+ */ >+ public BufferedImage getPageImage(PageViewport pageViewport, Page page) >+ throws FOPException { > > Rectangle2D bounds = pageViewport.getViewArea(); >- pageWidth = (int) Math.round(bounds.getWidth() / 1000f ); >- pageHeight = (int) Math.round(bounds.getHeight() / 1000f ); >-/* >- System.out.println("(Page) X, Y, Width, Height: " + bounds.getX() >- + " " + bounds.getY() >- + " " + bounds.getWidth() >- + " " + bounds.getHeight()); >-*/ >- currentPageImage = >- new BufferedImage((int)((pageWidth * (int)scaleFactor) / 100), >- (int)((pageHeight * (int)scaleFactor) / 100), >- BufferedImage.TYPE_INT_RGB); >+ pageWidth = (int) Math.round(bounds.getWidth() / 1000f); >+ pageHeight = (int) Math.round(bounds.getHeight() / 1000f); >+ >+ getLogger().info( >+ "Rendering Page " + pageViewport.getPageNumberString() >+ + " (pageWidth " + pageWidth + ", pageHeight " >+ + pageHeight + ")"); >+ >+ currentPageImage = new BufferedImage( >+ (int) ((pageWidth * (int) scaleFactor) / 100), >+ (int) ((pageHeight * (int) scaleFactor) / 100), >+ BufferedImage.TYPE_INT_RGB); > > Graphics2D graphics = currentPageImage.createGraphics(); >- graphics.setRenderingHint (RenderingHints.KEY_FRACTIONALMETRICS, >- RenderingHints.VALUE_FRACTIONALMETRICS_ON); >+ graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, >+ RenderingHints.VALUE_FRACTIONALMETRICS_ON); >+ if (antialiasing) { >+ graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, >+ RenderingHints.VALUE_TEXT_ANTIALIAS_ON); >+ } >+ if (qualityRendering) { >+ graphics.setRenderingHint(RenderingHints.KEY_RENDERING, >+ RenderingHints.VALUE_RENDER_QUALITY); >+ } > > // transform page based on scale factor supplied > AffineTransform at = graphics.getTransform(); >@@ -260,98 +349,243 @@ > graphics.drawLine(0, pageHeight + 2, pageWidth + 2, pageHeight + 2); > graphics.drawLine(1, pageHeight + 3, pageWidth + 3, pageHeight + 3); > >+ state = new AWTGraphicsState(graphics, this.fontInfo); >+ >+ // reset the current Positions >+ currentBPPosition = 0; >+ currentIPPosition = 0; >+ >+ // this toggles the rendering of all areas > renderPageAreas(page); > return currentPageImage; > } > >- /** Generates a desired page from the renderer's page viewport vector. >+ /** >+ * Generates a desired page from the renderer's page viewport vector. >+ * > * @param pageNum the 0-based page number to generate >- * @return the <code>java.awt.image.BufferedImage</code> corresponding to the page >- * @throws FOPException in case of an out-of-range page number requested >- */ >+ * @return the <code>java.awt.image.BufferedImage</code> corresponding to >+ * the page >+ * @throws FOPException in case of an out-of-range page number requested >+ */ > public BufferedImage getPageImage(int pageNum) throws FOPException { > if (pageNum < 0 || pageNum >= pageViewportList.size()) { > throw new FOPException("out-of-range page number (" + pageNum >- + ") requested; only " + pageViewportList.size() >- + " page(s) available."); >+ + ") requested; only " + pageViewportList.size() >+ + " page(s) available."); > } >- PageViewport pageViewport = (PageViewport) pageViewportList.get(pageNum); >+ PageViewport pageViewport = (PageViewport) pageViewportList >+ .get(pageNum); > Page page = (Page) pageList.get(pageNum); >+ return getPageImage(pageViewport, page); >+ } > >- Rectangle2D bounds = pageViewport.getViewArea(); >- pageWidth = (int) Math.round(bounds.getWidth() / 1000f ); >- pageHeight = (int) Math.round(bounds.getHeight() / 1000f ); >-/* >- System.out.println("(Page) X, Y, Width, Height: " + bounds.getX() >- + " " + bounds.getY() >- + " " + bounds.getWidth() >- + " " + bounds.getHeight()); >-*/ >- currentPageImage = >- new BufferedImage((int)((pageWidth * (int)scaleFactor) / 100), >- (int)((pageHeight * (int)scaleFactor) / 100), >- BufferedImage.TYPE_INT_RGB); >+ /** >+ * @see org.apache.fop.render.AbstractRenderer#startVParea(CTM) >+ */ >+ protected void startVParea(CTM ctm) { > >- Graphics2D graphics = currentPageImage.createGraphics(); >- graphics.setRenderingHint (RenderingHints.KEY_FRACTIONALMETRICS, >- RenderingHints.VALUE_FRACTIONALMETRICS_ON); >+ // push (and save) the current graphics state >+ state.push(); > >- // transform page based on scale factor supplied >- AffineTransform at = graphics.getTransform(); >- at.scale(scaleFactor / 100.0, scaleFactor / 100.0); >- graphics.setTransform(at); >+ // Set the given CTM in the graphics state >+ state.setTransform(new AffineTransform(CTMHelper.toPDFArray(ctm))); > >- // draw page frame >- graphics.setColor(Color.white); >- graphics.fillRect(0, 0, pageWidth, pageHeight); >- graphics.setColor(Color.black); >- graphics.drawRect(-1, -1, pageWidth + 2, pageHeight + 2); >- graphics.drawLine(pageWidth + 2, 0, pageWidth + 2, pageHeight + 2); >- graphics.drawLine(pageWidth + 3, 1, pageWidth + 3, pageHeight + 3); >- graphics.drawLine(0, pageHeight + 2, pageWidth + 2, pageHeight + 2); >- graphics.drawLine(1, pageHeight + 3, pageWidth + 3, pageHeight + 3); >+ // TODO Set clip? >+ } > >- renderPageAreas(page); >- return currentPageImage; >+ /** >+ * @see org.apache.fop.render.AbstractRenderer#endVParea() >+ */ >+ protected void endVParea() { >+ state.pop(); >+ } >+ >+ /** >+ * @see org.apache.fop.render.AbstractRenderer#renderBlockViewport(BlockViewport, >+ * List) >+ */ >+ protected void renderBlockViewport(BlockViewport bv, List children) { >+ // clip and position viewport if necessary >+ >+ // save positions >+ int saveIP = currentIPPosition; >+ int saveBP = currentBPPosition; >+ >+ CTM ctm = bv.getCTM(); >+ int borderPaddingStart = bv.getBorderAndPaddingWidthStart(); >+ int borderPaddingBefore = bv.getBorderAndPaddingWidthBefore(); >+ float x, y; >+ x = (float) (bv.getXOffset() + containingIPPosition) / 1000f; >+ y = (float) (bv.getYOffset() + containingBPPosition) / 1000f; >+ >+ if (bv.getPositioning() == Block.ABSOLUTE >+ || bv.getPositioning() == Block.FIXED) { >+ // TODO not tested yet >+ // For FIXED, we need to break out of the current viewports to the >+ // one established by the page. We save the state stack for >+ // restoration >+ // after the block-container has been painted. See below. >+ List breakOutList = null; >+ if (bv.getPositioning() == Block.FIXED) { >+ getLogger().debug("Block.FIXED --> break out"); >+ breakOutList = new java.util.ArrayList(); >+ Graphics2D graph; >+ while (true) { >+ graph = state.getGraph(); >+ if (state.pop() == null) { >+ break; >+ } >+ breakOutList.add(0, graph); // Insert because of >+ // stack-popping >+ getLogger().debug("Adding to break out list: " + graph); >+ } >+ } >+ >+ CTM tempctm = new CTM(containingIPPosition, containingBPPosition); >+ ctm = tempctm.multiply(ctm); >+ >+ // This is the content-rect >+ float width = (float) bv.getIPD() / 1000f; >+ float height = (float) bv.getBPD() / 1000f; >+ >+ // Adjust for spaces (from margin or indirectly by start-indent etc. >+ Integer spaceStart = (Integer) bv.getTrait(Trait.SPACE_START); >+ if (spaceStart != null) { >+ x += spaceStart.floatValue() / 1000; >+ } >+ Integer spaceBefore = (Integer) bv.getTrait(Trait.SPACE_BEFORE); >+ if (spaceBefore != null) { >+ y += spaceBefore.floatValue() / 1000; >+ } >+ >+ float bpwidth = (borderPaddingStart + bv >+ .getBorderAndPaddingWidthEnd()) / 1000f; >+ float bpheight = (borderPaddingBefore + bv >+ .getBorderAndPaddingWidthAfter()) / 1000f; >+ >+ drawBackAndBorders(bv, x, y, width + bpwidth, height + bpheight); >+ >+ // Now adjust for border/padding >+ x += borderPaddingStart / 1000f; >+ y += borderPaddingBefore / 1000f; >+ >+ if (bv.getClip()) { >+ // saves the graphics state in a stack >+ state.push(); >+ >+ clip(x, y, width, height); >+ } >+ >+ startVParea(ctm); >+ >+ renderBlocks(bv, children); >+ endVParea(); >+ >+ if (bv.getClip()) { >+ // restores the last graphics state from the stack >+ state.pop(); >+ } >+ >+ // clip if necessary >+ >+ if (breakOutList != null) { >+ getLogger().debug( >+ "Block.FIXED --> restoring context after break-out"); >+ Graphics2D graph; >+ Iterator i = breakOutList.iterator(); >+ while (i.hasNext()) { >+ graph = (Graphics2D) i.next(); >+ getLogger().debug("Restoring: " + graph); >+ state.push(); >+ } >+ } >+ >+ currentIPPosition = saveIP; >+ currentBPPosition = saveBP; >+ >+ } else { // orientation = Block.STACK or RELATIVE >+ >+ Integer spaceBefore = (Integer) bv.getTrait(Trait.SPACE_BEFORE); >+ if (spaceBefore != null) { >+ currentBPPosition += spaceBefore.intValue(); >+ } >+ >+ // borders and background in the old coordinate system >+ handleBlockTraits(bv); >+ >+ CTM tempctm = new CTM(containingIPPosition, currentBPPosition >+ + containingBPPosition); >+ ctm = tempctm.multiply(ctm); >+ >+ // Now adjust for border/padding >+ x += borderPaddingStart / 1000f; >+ y += borderPaddingBefore / 1000f; >+ >+ // clip if necessary >+ if (bv.getClip()) { >+ // saves the graphics state in a stack >+ state.push(); >+ float width = (float) bv.getIPD() / 1000f; >+ float height = (float) bv.getBPD() / 1000f; >+ clip(x, y, width, height); >+ } >+ >+ if (ctm != null) { >+ startVParea(ctm); >+ } >+ renderBlocks(bv, children); >+ if (ctm != null) { >+ endVParea(); >+ } >+ >+ if (bv.getClip()) { >+ // restores the last graphics state from the stack >+ state.pop(); >+ } >+ >+ currentIPPosition = saveIP; >+ currentBPPosition = saveBP; >+ >+ // Adjust BP position (alloc BPD + spaces) >+ if (spaceBefore != null) { >+ currentBPPosition += spaceBefore.intValue(); >+ } >+ currentBPPosition += (int) (bv.getAllocBPD()); >+ Integer spaceAfter = (Integer) bv.getTrait(Trait.SPACE_AFTER); >+ if (spaceAfter != null) { >+ currentBPPosition += spaceAfter.intValue(); >+ } >+ } > } > > /** >- * Handle the traits for a region >- * This is used to draw the traits for the given page region. >- * (See Sect. 6.4.1.2 of XSL-FO spec.) >- * @param region the RegionViewport whose region is to be drawn >- */ >- protected void handleRegionTraits(RegionViewport region) { >- Rectangle2D viewArea = region.getViewArea(); >- >- int startX = (int) Math.round((viewArea.getX() / 1000f) >- * (scaleFactor / 100f)); >- int startY = (int) Math.round((viewArea.getY() / 1000f) >- * (scaleFactor / 100f)); >- // for rounding to work correctly, need to take into account >- // fractional portion of X and Y. >- int width = (int) Math.round(((viewArea.getX() + viewArea.getWidth()) / 1000f) >- * (scaleFactor / 100f)) - startX; >- int height = (int) Math.round(((viewArea.getY() + viewArea.getHeight()) / 1000f) >- * (scaleFactor / 100f)) - startY; >- >- if (region.getRegion() != null) { >- System.out.print("\nRegion type = " + region.getRegion().getRegionClass()); >- } >- >- System.out.println(" X, Width, Y, Height: " + startX >- + " " + width >- + " " + startY >- + " " + height >- ); >- >- drawBackAndBorders(region, startX, startY, width, height); >+ * Clip an area. >+ */ >+ protected void clip() { >+ // TODO via AWTGraphicsState.updateClip(); >+ // currentStream.add("W\n"); >+ // currentStream.add("n\n"); >+ } >+ >+ /** >+ * Clip an area. write a clipping operation given coordinates in the current >+ * transform. >+ * @param x the x coordinate >+ * @param y the y coordinate >+ * @param width the width of the area >+ * @param height the height of the area >+ */ >+ protected void clip(float x, float y, float width, float height) { >+ // TODO via AWTGraphicsState.updateClip(); >+ // currentStream.add(x + " " + y + " " + width + " " + height + " >+ // re "); >+ clip(); > } > > /** >- * Draw the background and borders. >- * This draws the background and border traits for an area given >- * the position. >+ * Draw the background and borders. This draws the background and border >+ * traits for an area given the position. > * > * @param block the area to get the traits from > * @param startx the start x position >@@ -359,112 +593,595 @@ > * @param width the width of the area > * @param height the height of the area > */ >- protected void drawBackAndBorders(Area block, >- int startx, int starty, >- int width, int height) { >+ protected void drawBackAndBorders(Area area, float startx, float starty, >+ float width, float height) { > >- // draw background then border >- Graphics2D graphics = currentPageImage.createGraphics(); >+ if (debug) { // TODO implement visual-debugging as standalone >+ // Renderer >+ debugBackAndBorders(area, startx, starty, width, height); >+ } >+ >+ BorderProps bpsBefore = (BorderProps) area >+ .getTrait(Trait.BORDER_BEFORE); >+ BorderProps bpsAfter = (BorderProps) area.getTrait(Trait.BORDER_AFTER); >+ BorderProps bpsStart = (BorderProps) area.getTrait(Trait.BORDER_START); >+ BorderProps bpsEnd = (BorderProps) area.getTrait(Trait.BORDER_END); >+ >+ // draw background > Trait.Background back; >- back = (Trait.Background) block.getTrait(Trait.BACKGROUND); >+ back = (Trait.Background) area.getTrait(Trait.BACKGROUND); > if (back != null) { > >+ // Calculate padding rectangle >+ float sx = startx; >+ float sy = starty; >+ float paddRectWidth = width; >+ float paddRectHeight = height; >+ >+ if (bpsStart != null) { >+ sx += bpsStart.width / 1000f; >+ paddRectWidth -= bpsStart.width / 1000f; >+ } >+ if (bpsBefore != null) { >+ sy += bpsBefore.width / 1000f; >+ paddRectHeight -= bpsBefore.width / 1000f; >+ } >+ if (bpsEnd != null) { >+ paddRectWidth -= bpsEnd.width / 1000f; >+ } >+ if (bpsAfter != null) { >+ paddRectHeight -= bpsAfter.width / 1000f; >+ } >+ > if (back.getColor() != null) { >- graphics.setColor(back.getColor().getAWTColor()); >- graphics.fillRect(startx, starty, width, height); >+ drawBackground(back, sx, sy, paddRectWidth, paddRectHeight); > } >- if (back.getURL() != null) { // TODO: implement >- ImageFactory fact = ImageFactory.getInstance(); >- FopImage fopimage = fact.getImage(back.getURL(), userAgent); >+ >+ // background image >+ if (back.getFopImage() != null) { >+ FopImage fopimage = back.getFopImage(); > if (fopimage != null && fopimage.load(FopImage.DIMENSIONS)) { >- if (back.getRepeat() == EN_REPEAT) { >- // create a pattern for the image >- } else { >- // place once >- Rectangle2D pos; >- pos = new Rectangle2D.Float((startx + back.getHoriz()) * 1000, >- (starty + back.getVertical()) * 1000, >- fopimage.getWidth() * 1000, >- fopimage.getHeight() * 1000); >-// putImage(back.getURL(), pos); >+ clip(sx, sy, paddRectWidth, paddRectHeight); >+ int horzCount = (int) ((paddRectWidth * 1000 / fopimage >+ .getIntrinsicWidth()) + 1.0f); >+ int vertCount = (int) ((paddRectHeight * 1000 / fopimage >+ .getIntrinsicHeight()) + 1.0f); >+ if (back.getRepeat() == EN_NOREPEAT) { >+ horzCount = 1; >+ vertCount = 1; >+ } else if (back.getRepeat() == EN_REPEATX) { >+ vertCount = 1; >+ } else if (back.getRepeat() == EN_REPEATY) { >+ horzCount = 1; >+ } >+ // change from points to millipoints >+ sx *= 1000; >+ sy *= 1000; >+ if (horzCount == 1) { >+ sx += back.getHoriz(); > } >+ if (vertCount == 1) { >+ sy += back.getVertical(); >+ } >+ for (int x = 0; x < horzCount; x++) { >+ for (int y = 0; y < vertCount; y++) { >+ // place once >+ Rectangle2D pos; >+ pos = new Rectangle2D.Float(sx >+ + (x * fopimage.getIntrinsicWidth()), sy >+ + (y * fopimage.getIntrinsicHeight()), >+ fopimage.getIntrinsicWidth(), fopimage >+ .getIntrinsicHeight()); >+ putImage(back.getURL(), pos); // TODO test >+ } >+ } >+ >+ } else { >+ getLogger().warn( >+ "Can't find background image: " + back.getURL()); > } > } > } > >- BorderProps bps = (BorderProps) block.getTrait(Trait.BORDER_BEFORE); >- if (bps != null) { >- int borderWidth = (int) Math.round((bps.width / 1000f) * (scaleFactor / 100f)); >- graphics.setColor(bps.color.getAWTColor()); >- graphics.fillRect(startx, starty, width, borderWidth); >- } >- bps = (BorderProps) block.getTrait(Trait.BORDER_AFTER); >- if (bps != null) { >- int borderWidth = (int) Math.round((bps.width / 1000f) * (scaleFactor / 100f)); >- int sy = starty + height; >- graphics.setColor(bps.color.getAWTColor()); >- graphics.fillRect(startx, starty + height - borderWidth, >- width, borderWidth); >- } >- bps = (BorderProps) block.getTrait(Trait.BORDER_START); >- if (bps != null) { >- int borderWidth = (int) Math.round((bps.width / 1000f) * (scaleFactor / 100f)); >- graphics.setColor(bps.color.getAWTColor()); >- graphics.fillRect(startx, starty, borderWidth, height); >- } >- bps = (BorderProps) block.getTrait(Trait.BORDER_END); >- if (bps != null) { >- int borderWidth = (int) Math.round((bps.width / 1000f) * (scaleFactor / 100f)); >- int sx = startx + width; >- graphics.setColor(bps.color.getAWTColor()); >- graphics.fillRect(startx + width - borderWidth, starty, >- borderWidth, height); >+ // draw border >+ // BORDER_BEFORE >+ if (bpsBefore != null) { >+ int borderWidth = (int) Math.round((bpsBefore.width / 1000f) >+ * (scaleFactor / 100f)); >+ state.updateColor(bpsBefore.color); >+ state.getGraph().fillRect((int) startx, (int) starty, (int) width, >+ borderWidth); > } >- >+ // BORDER_AFTER >+ if (bpsAfter != null) { >+ int borderWidth = (int) Math.round((bpsAfter.width / 1000f) >+ * (scaleFactor / 100f)); >+ float sy = starty + height; >+ state.updateColor(bpsAfter.color); >+ state.getGraph().fillRect((int) startx, >+ (int) (starty + height - borderWidth), (int) width, >+ borderWidth); >+ } >+ // BORDER_START >+ if (bpsStart != null) { >+ int borderWidth = (int) Math.round((bpsStart.width / 1000f) >+ * (scaleFactor / 100f)); >+ state.updateColor(bpsStart.color); >+ state.getGraph().fillRect((int) startx, (int) starty, borderWidth, >+ (int) height); >+ } >+ // BORDER_END >+ if (bpsEnd != null) { >+ int borderWidth = (int) Math.round((bpsEnd.width / 1000f) >+ * (scaleFactor / 100f)); >+ float sx = startx + width; >+ state.updateColor(bpsEnd.color); >+ state.getGraph().fillRect((int) (startx + width - borderWidth), >+ (int) starty, borderWidth, (int) height); >+ } >+ >+ } >+ >+ /** Draws a thin border around every area to help debugging */ >+ private void debugBackAndBorders(Area area, float startx, float starty, >+ float width, float height) { >+ >+ // saves the graphics state in a stack >+ state.push(); >+ >+ ColorType ct = new ColorTypeProperty(0.7f, 0.7f, 0.7f); >+ state.updateColor(ct, true, null); >+ state.updateStroke(0.4f, EN_SOLID); >+ state.getGraph().draw( >+ new Rectangle2D.Float(startx, starty, width, height)); >+ >+ // restores the last graphics state from the stack >+ state.pop(); >+ } >+ >+ /** >+ * Draw the Background Rectangle of a given area. >+ * >+ * @param back the Trait.Background >+ * @param sx x coordinate of the rectangle to be filled. >+ * @param sy y the y coordinate of the rectangle to be filled. >+ * @param paddRectWidth the width of the rectangle to be filled. >+ * @param paddRectHeight the height of the rectangle to be filled. >+ */ >+ protected void drawBackground(Trait.Background back, float sx, float sy, >+ float paddRectWidth, float paddRectHeight) { >+ >+ state.updateColor(back.getColor()); >+ state.getGraph().fillRect((int) sx, (int) sy, (int) paddRectWidth, >+ (int) paddRectHeight); >+ } >+ >+ /** >+ * Handle block traits. The block could be any sort of block with any >+ * positioning so this should render the traits such as border and >+ * background in its position. >+ * >+ * @param block the block to render the traits >+ */ >+ protected void handleBlockTraits(Block block) { >+ // copied from pdf >+ int borderPaddingStart = block.getBorderAndPaddingWidthStart(); >+ int borderPaddingBefore = block.getBorderAndPaddingWidthBefore(); >+ >+ float startx = currentIPPosition / 1000f; >+ float starty = currentBPPosition / 1000f; >+ float width = block.getIPD() / 1000f; >+ float height = block.getBPD() / 1000f; >+ >+ startx += block.getStartIndent() / 1000f; >+ startx -= block.getBorderAndPaddingWidthStart() / 1000f; >+ width += borderPaddingStart / 1000f; >+ width += block.getBorderAndPaddingWidthEnd() / 1000f; >+ height += borderPaddingBefore / 1000f; >+ height += block.getBorderAndPaddingWidthAfter() / 1000f; >+ >+ drawBackAndBorders(block, startx, starty, width, height); > } >- >+ > /** > * @see org.apache.fop.render.Renderer#renderText(TextArea) > */ > public void renderText(TextArea text) { >- System.out.println("In render text: " + text.getTextArea()); > >- Graphics2D graphics = currentPageImage.createGraphics(); >- String fontName = (String) text.getTrait(Trait.FONT_NAME); >+ float x = currentIPPosition; >+ float y = currentBPPosition + text.getOffset(); // baseline >+ >+ String name = (String) text.getTrait(Trait.FONT_NAME); > int size = ((Integer) text.getTrait(Trait.FONT_SIZE)).intValue(); >-// Typeface f = (Typeface) fontInfo.getFonts().get(fontName); >+ state.updateFont(name, size, null); >+ > ColorType ct = (ColorType) text.getTrait(Trait.COLOR); >+ state.updateColor(ct, false, null); > >- FontMetricsMapper mapper = (FontMetricsMapper) >- fontInfo.getMetricsFor(fontName); >- if (mapper == null) { >- mapper = new FontMetricsMapper("MonoSpaced", java.awt.Font.PLAIN, >- graphics); >- } >- >-// graphics.setColor(ct.getAWTColor()); >-// graphics.setFont(mapper.getFont(size)); >- graphics.setColor(java.awt.Color.black); >- graphics.setFont(new java.awt.Font("monospaced", java.awt.Font.PLAIN, >- 10)); >- >- int rx = currentIPPosition; >- int bl = currentBPPosition + text.getOffset(); >- >- int newx = (int) (rx + 500) / 1000; >- int newy = (int) (pageHeight - (bl + 500) / 1000); >- > String s = text.getTextArea(); >-// graphics.drawString(s, newx, newy); >- graphics.drawString(s, 220, 200); >+ state.getGraph().drawString(s, x / 1000f, y / 1000f); >+ >+ getLogger().debug( >+ "renderText(): \"" + s + "\", x: " + x + ", y: " + y + state); >+ >+ // rendering text decorations >+ FontMetrics metrics = fontInfo.getMetricsFor(name); >+ Font fs = new Font(name, metrics, size); >+ renderTextDecoration(fs, text, y, x); > >- // TODO: render text decorations >- currentIPPosition += text.getAllocIPD(); >+ super.renderText(text); > } > >- /** @see org.apache.fop.render.AbstractRenderer */ >- public String getMimeType() { >- return MIME_TYPE; >+ /** >+ * @see org.apache.fop.render.Renderer#renderCharacter(Character) >+ */ >+ public void renderCharacter(Character ch) { >+ >+ float x = currentIPPosition; >+ float y = currentBPPosition + ch.getOffset(); // baseline >+ >+ String name = (String) ch.getTrait(Trait.FONT_NAME); >+ int size = ((Integer) ch.getTrait(Trait.FONT_SIZE)).intValue(); >+ state.updateFont(name, size, null); >+ >+ ColorType ct = (ColorType) ch.getTrait(Trait.COLOR); >+ state.updateColor(ct, false, null); >+ >+ String s = ch.getChar(); >+ state.getGraph().drawString(s, x / 1000f, y / 1000f); >+ >+ getLogger().debug( >+ "renderCharacter(): \"" + s + "\", x: " + x + ", y: " + y >+ + state); >+ >+ // rendering text decorations >+ FontMetrics metrics = fontInfo.getMetricsFor(name); >+ Font fs = new Font(name, metrics, size); >+ renderTextDecoration(fs, ch, y, x); >+ >+ super.renderCharacter(ch); >+ } >+ >+ /** >+ * Paints the text decoration marks. >+ * @param fs Current font >+ * @param inline inline area to paint the marks for >+ * @param baseline position of the baseline >+ * @param startIPD start IPD >+ */ >+ protected void renderTextDecoration(Font fs, InlineArea inline, >+ float baseline, float startIPD) { >+ >+ boolean hasTextDeco = inline.hasUnderline() || inline.hasOverline() >+ || inline.hasLineThrough(); >+ >+ if (hasTextDeco) { >+ state.updateStroke((fs.getDescender() / (-8 * 1000f)), >+ Constants.EN_SOLID); >+ float endIPD = startIPD + inline.getIPD(); >+ if (inline.hasUnderline()) { >+ ColorType ct = (ColorType) inline >+ .getTrait(Trait.UNDERLINE_COLOR); >+ state.updateColor(ct, false, null); >+ float y = baseline - fs.getDescender() / 2; >+ line.setLine(startIPD / 1000f, y / 1000f, endIPD / 1000f, >+ y / 1000f); >+ state.getGraph().draw(line); >+ } >+ if (inline.hasOverline()) { >+ ColorType ct = (ColorType) inline >+ .getTrait(Trait.OVERLINE_COLOR); >+ state.updateColor(ct, false, null); >+ float y = (float) (baseline - (1.1 * fs.getCapHeight())); >+ line.setLine(startIPD / 1000f, y / 1000f, endIPD / 1000f, >+ y / 1000f); >+ state.getGraph().draw(line); >+ } >+ if (inline.hasLineThrough()) { >+ ColorType ct = (ColorType) inline >+ .getTrait(Trait.LINETHROUGH_COLOR); >+ state.updateColor(ct, false, null); >+ float y = (float) (baseline - (0.45 * fs.getCapHeight())); >+ line.setLine(startIPD / 1000f, y / 1000f, endIPD / 1000f, >+ y / 1000f); >+ state.getGraph().draw(line); >+ } >+ } >+ } >+ >+ /** >+ * Render leader area. This renders a leader area which is an area with a >+ * rule. >+ * >+ * @param area the leader area to render >+ */ >+ public void renderLeader(Leader area) { >+ >+ // TODO leader-length: 25%, 50%, 75%, 100% not working yet >+ // TODO Colors do not work on Leaders yet >+ >+ float startx = ((float) currentIPPosition) / 1000f; >+ float starty = ((currentBPPosition + area.getOffset()) / 1000f); >+ float endx = (currentIPPosition + area.getIPD()) / 1000f; >+ >+ ColorType ct = (ColorType) area.getTrait(Trait.COLOR); >+ state.updateColor(ct, true, null); >+ >+ line.setLine(startx, starty, endx, starty); >+ float thickness = area.getRuleThickness() / 1000f; >+ >+ int style = area.getRuleStyle(); >+ switch (style) { >+ case EN_SOLID: >+ case EN_DOTTED: >+ case EN_DASHED: >+ state.updateStroke(thickness, style); >+ state.getGraph().draw(line); >+ break; >+ case EN_DOUBLE: >+ >+ state.updateStroke(thickness / 3f, EN_SOLID); // only a third >+ >+ // upper Leader >+ line.setLine(startx, starty, endx, starty); >+ state.getGraph().draw(line); >+ // lower Leader >+ line.setLine(startx, starty + 2 * thickness, endx, starty + 2 >+ * thickness); >+ state.getGraph().draw(line); >+ >+ break; >+ >+ case EN_GROOVE: >+ // The rule looks as though it were carved into the canvas. >+ // (Top/left half of the rule's thickness is the >+ // color specified; the other half is white.) >+ >+ state.updateStroke(thickness / 2f, EN_SOLID); // only the half >+ >+ // upper Leader >+ line.setLine(startx, starty, endx, starty); >+ state.getGraph().draw(line); >+ // lower Leader >+ line.setLine(startx, starty + thickness, endx, starty + thickness); >+ state.getGraph().setColor(Color.WHITE); >+ state.getGraph().draw(line); >+ >+ // TODO the implementation could be nicer, f.eg. with triangles at >+ // the tip of the lines. See also RenderX's implementation (looks >+ // like a button) >+ >+ break; >+ >+ case EN_RIDGE: >+ // The opposite of "groove", the rule looks as though it were >+ // coming out of the canvas. (Bottom/right half of the rule's >+ // thickness is the color specified; the other half is white.) >+ >+ state.updateStroke(thickness / 2f, EN_SOLID); // only the half >+ >+ // lower Leader >+ line.setLine(startx, starty + thickness, endx, starty + thickness); >+ state.getGraph().draw(line); >+ // upperLeader >+ line.setLine(startx, starty, endx, starty); >+ state.getGraph().setColor(Color.WHITE); >+ state.getGraph().draw(line); >+ >+ // TODO the implementation could be nicer, f.eg. with triangles at >+ // the tip of the lines. See also RenderX's implementation (looks >+ // like a button) >+ >+ break; >+ >+ case EN_NONE: >+ // No rule is drawn >+ break; >+ >+ } // end switch >+ >+ super.renderLeader(area); >+ } >+ >+ /** >+ * @see org.apache.fop.render.AbstractRenderer#renderImage(Image, >+ * Rectangle2D) >+ */ >+ public void renderImage(Image image, Rectangle2D pos) { >+ // endTextObject(); >+ String url = image.getURL(); >+ putImage(url, pos); >+ } >+ >+ /** >+ * draws an image >+ * >+ * @param url URL of the bitmap >+ * @param pos Position of the bitmap >+ */ >+ protected void putImage(String pUrl, Rectangle2D pos) { >+ >+ int x = currentIPPosition; // TODO + area.getXOffset(); >+ int y = currentBPPosition; >+ String url = ImageFactory.getURL(pUrl); >+ >+ ImageFactory fact = ImageFactory.getInstance(); >+ FopImage fopimage = fact.getImage(url, userAgent); >+ >+ if (fopimage == null) { >+ return; >+ } >+ if (!fopimage.load(FopImage.DIMENSIONS)) { >+ return; >+ } >+ int w = fopimage.getWidth(); >+ int h = fopimage.getHeight(); >+ String mime = fopimage.getMimeType(); >+ if ("text/xml".equals(mime)) { >+ if (!fopimage.load(FopImage.ORIGINAL_DATA)) { >+ return; >+ } >+ Document doc = ((XMLImage) fopimage).getDocument(); >+ String ns = ((XMLImage) fopimage).getNameSpace(); >+ renderDocument(doc, ns, pos); >+ >+ } else if ("image/svg+xml".equals(mime)) { >+ if (!fopimage.load(FopImage.ORIGINAL_DATA)) { >+ return; >+ } >+ Document doc = ((XMLImage) fopimage).getDocument(); >+ renderSVGDocument(doc, pos); // TODO check if ok. >+ >+ } else if (("image/eps".equals(mime)) || ("image/jpeg".equals(mime))) { >+ if (!fopimage.load(FopImage.ORIGINAL_DATA)) { >+ return; >+ } >+ >+ // TODO >+ url = url.substring(7); >+ url = "C:/eclipse/myWorkbenches/fop4/xml-fop/examples/fo" + url; >+ java.awt.Image awtImage = new javax.swing.ImageIcon(url).getImage(); >+ >+ state.getGraph().drawImage(awtImage, (int) (x / 1000f), >+ (int) (y / 1000f), (int) w, h, null); >+ currentBPPosition += (h * 1000); >+ >+ } else if ("image/bmp".equals(mime)) { >+ if (!fopimage.load(FopImage.BITMAP)) { >+ return; >+ } >+ // TODO >+ currentBPPosition += (h * 1000); >+ >+ } else { >+ if (!fopimage.load(FopImage.BITMAP)) { >+ return; >+ } >+ >+ byte[] raw = fopimage.getRessourceBytes(); >+ ColorModel cm = ColorModel.getRGBdefault(); >+ Component c = new Container(); >+ MemoryImageSource mSource = new MemoryImageSource(w, h, cm, raw, 0, >+ w); >+ // java.awt.Image awtImage = c.createImage(mSource); >+ >+ // TODO >+ url = url.substring(7); >+ url = "C:/eclipse/myWorkbenches/fop4/xml-fop/examples/fo" + url; >+ java.awt.Image awtImage = new javax.swing.ImageIcon(url).getImage(); >+ >+ state.getGraph().drawImage(awtImage, (int) (x / 1000f), >+ (int) (y / 1000f), (int) w, h, null); >+ currentBPPosition += (h * 1000); >+ } >+ } >+ >+ /** >+ * @see org.apache.fop.render.AbstractRenderer#renderForeignObject(ForeignObject, >+ * Rectangle2D) >+ */ >+ public void renderForeignObject(ForeignObject fo, Rectangle2D pos) { >+ Document doc = fo.getDocument(); >+ String ns = fo.getNameSpace(); >+ if (ns.equals("http://www.w3.org/2000/svg")) { >+ renderSVGDocument(doc, pos); >+ } else { >+ renderDocument(doc, ns, pos); >+ } >+ // this.currentXPosition += area.getContentWidth(); > } > >+ /** >+ * Renders an XML document (SVG for example). >+ * >+ * @param doc DOM document representing the XML document >+ * @param ns Namespace for the document >+ * @param pos Position on the page >+ */ >+ public void renderDocument(Document doc, String ns, Rectangle2D pos) { >+ RendererContext context; >+ context = new RendererContext(MIME_TYPE); >+ context.setUserAgent(userAgent); >+ // TODO implement >+ /* >+ * context.setProperty(PDFXMLHandler.PDF_DOCUMENT, pdfDoc); >+ * context.setProperty(PDFXMLHandler.OUTPUT_STREAM, ostream); >+ * context.setProperty(PDFXMLHandler.PDF_STATE, currentState); >+ * context.setProperty(PDFXMLHandler.PDF_PAGE, currentPage); >+ * context.setProperty(PDFXMLHandler.PDF_CONTEXT, currentContext == null ? >+ * currentPage : currentContext); >+ * context.setProperty(PDFXMLHandler.PDF_CONTEXT, currentContext); >+ * context.setProperty(PDFXMLHandler.PDF_STREAM, currentStream); >+ * context.setProperty(PDFXMLHandler.PDF_XPOS, new >+ * Integer(currentIPPosition + (int) pos.getX())); >+ * context.setProperty(PDFXMLHandler.PDF_YPOS, new >+ * Integer(currentBPPosition + (int) pos.getY())); >+ * context.setProperty(PDFXMLHandler.PDF_FONT_INFO, fontInfo); >+ * context.setProperty(PDFXMLHandler.PDF_FONT_NAME, currentFontName); >+ * context.setProperty(PDFXMLHandler.PDF_FONT_SIZE, new >+ * Integer(currentFontSize)); >+ * context.setProperty(PDFXMLHandler.PDF_WIDTH, new Integer((int) >+ * pos.getWidth())); context.setProperty(PDFXMLHandler.PDF_HEIGHT, new >+ * Integer((int) pos.getHeight())); renderXML(userAgent, context, doc, >+ * ns); >+ */ >+ } >+ >+ protected void renderSVGDocument(Document doc, Rectangle2D pos) { >+ >+ int x = currentIPPosition; // TODO + area.getXOffset(); >+ int y = currentBPPosition; >+ >+ RendererContext context; >+ context = new RendererContext(MIME_TYPE); >+ context.setUserAgent(userAgent); >+ >+ SVGUserAgent ua = new SVGUserAgent(context.getUserAgent() >+ .getPixelUnitToMillimeter(), new AffineTransform()); >+ >+ GVTBuilder builder = new GVTBuilder(); >+ BridgeContext ctx = new BridgeContext(ua); >+ >+ GraphicsNode root; >+ try { >+ root = builder.build(ctx, doc); >+ } catch (Exception e) { >+ getLogger().error( >+ "svg graphic could not be built: " + e.getMessage(), e); >+ return; >+ } >+ float w = (float) ctx.getDocumentSize().getWidth() * 1000f; >+ float h = (float) ctx.getDocumentSize().getHeight() * 1000f; >+ >+ // correct integer roundoff >+ state.getGraph().translate(x / 1000, y / 1000); >+ >+ SVGSVGElement svg = ((SVGDocument) doc).getRootElement(); >+ AffineTransform at = ViewBox.getPreserveAspectRatioTransform(svg, >+ w / 1000f, h / 1000f); >+ AffineTransform inverse = null; >+ try { >+ inverse = at.createInverse(); >+ } catch (NoninvertibleTransformException e) { >+ getLogger().warn(e); >+ } >+ if (!at.isIdentity()) { >+ state.getGraph().transform(at); >+ } >+ >+ try { >+ root.paint(state.getGraph()); >+ } catch (Exception e) { >+ e.printStackTrace(); >+ } >+ >+ if (inverse != null && !inverse.isIdentity()) { >+ state.getGraph().transform(inverse); >+ } >+ // correct integer roundoff >+ // currentState.getCurrentGraphics().translate(-x / 1000f, y / 1000f - >+ // pageHeight); >+ state.getGraph().translate(-(x + 500) / 1000, >+ (y + 500) / 1000 - pageHeight); >+ } > } >Index: src/java/org/apache/fop/render/awt/viewer/PreviewDialog.java >=================================================================== >RCS file: /home/cvspublic/xml-fop/src/java/org/apache/fop/render/awt/viewer/PreviewDialog.java,v >retrieving revision 1.7 >diff -u -r1.7 PreviewDialog.java >--- src/java/org/apache/fop/render/awt/viewer/PreviewDialog.java 24 Jul 2004 05:47:45 -0000 1.7 >+++ src/java/org/apache/fop/render/awt/viewer/PreviewDialog.java 8 Mar 2005 02:00:46 -0000 >@@ -1,6 +1,6 @@ > /* >- * Copyright 1999-2004 The Apache Software Foundation. >- * >+ * Copyright 1999-2005 The Apache Software Foundation. >+ * > * Licensed under the Apache License, Version 2.0 (the "License"); > * you may not use this file except in compliance with the License. > * You may obtain a copy of the License at >@@ -19,19 +19,6 @@ > package org.apache.fop.render.awt.viewer; > > //Java >-import javax.swing.BorderFactory; >-import javax.swing.ImageIcon; >-import javax.swing.JComboBox; >-import javax.swing.JFrame; >-import javax.swing.JLabel; >-import javax.swing.JMenu; >-import javax.swing.JMenuBar; >-import javax.swing.JOptionPane; >-import javax.swing.JPanel; >-import javax.swing.JScrollPane; >-import javax.swing.JToolBar; >-import javax.swing.SwingUtilities; >- > import java.awt.BorderLayout; > import java.awt.Color; > import java.awt.Dimension; >@@ -44,13 +31,26 @@ > import java.awt.event.ActionEvent; > import java.awt.event.ActionListener; > import java.awt.image.BufferedImage; >-import java.awt.print.PrinterJob; > import java.awt.print.PrinterException; >+import java.awt.print.PrinterJob; >+ >+import javax.swing.BorderFactory; >+import javax.swing.ImageIcon; >+import javax.swing.JComboBox; >+import javax.swing.JFrame; >+import javax.swing.JLabel; >+import javax.swing.JMenu; >+import javax.swing.JMenuBar; >+import javax.swing.JOptionPane; >+import javax.swing.JPanel; >+import javax.swing.JScrollPane; >+import javax.swing.JToolBar; >+import javax.swing.SwingUtilities; >+import javax.swing.UIManager; > >-//FOP >-import org.apache.fop.apps.Fop; >-import org.apache.fop.apps.FOUserAgent; > import org.apache.fop.apps.FOPException; >+import org.apache.fop.apps.FOUserAgent; >+import org.apache.fop.apps.Fop; > import org.apache.fop.fo.Constants; > import org.apache.fop.render.awt.AWTRenderer; > >@@ -123,6 +123,18 @@ > reload(); > } > }; >+ Command debugAction = new Command(" Debug") { >+ //TODO use Translator >+ public void doit() { >+ debug(); >+ } >+ }; >+ >+ //set the system look&feel >+ try { >+ UIManager.setLookAndFeel( >+ UIManager.getSystemLookAndFeelClassName()); >+ } catch (Exception e) { } > > setTitle("FOP: AWT-" + translator.getString("Title.Preview")); > setDefaultCloseOperation(DISPOSE_ON_CLOSE); >@@ -171,8 +183,9 @@ > toolBar.add(lastPageAction); > toolBar.addSeparator(); > toolBar.add(new JLabel(translator.getString("Menu.Zoom"))); >- toolBar.addSeparator(); > toolBar.add(scale); >+ toolBar.addSeparator(); >+ toolBar.add(debugAction); > getContentPane().add(toolBar, BorderLayout.NORTH); > //Status bar > JPanel statusBar = new JPanel(); >@@ -379,6 +392,14 @@ > } > > /** >+ * Allows a (yet) simple visual debug of the document. >+ */ >+ private void debug(){ >+ renderer.debug = !renderer.debug; >+ showPage(); >+ } >+ >+ /** > * This class is used to reload document in > * a thread safe way. > */ >Index: src/java/org/apache/fop/render/RendererState.java >=================================================================== >RCS file: src/java/org/apache/fop/render/RendererState.java >diff -N src/java/org/apache/fop/render/RendererState.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/java/org/apache/fop/render/RendererState.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,145 @@ >+/* >+ * Copyright 1999-2005 The Apache Software Foundation. >+ * >+ * Licensed under the Apache License, Version 2.0 (the "License"); >+ * you may not use this file except in compliance with the License. >+ * You may obtain a copy of the License at >+ * >+ * http://www.apache.org/licenses/LICENSE-2.0 >+ * >+ * Unless required by applicable law or agreed to in writing, software >+ * distributed under the License is distributed on an "AS IS" BASIS, >+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ * See the License for the specific language governing permissions and >+ * limitations under the License. >+ */ >+ >+/* $Id$ */ >+ >+package org.apache.fop.render; >+ >+import java.awt.Graphics2D; >+import java.awt.Paint; >+import java.awt.Shape; >+import java.awt.geom.AffineTransform; >+ >+import org.apache.fop.datatypes.ColorType; >+ >+/** >+ * An interface for the classes which hold the state of the current graphics context. >+ */ >+public interface RendererState { >+ >+ /** >+ * Push the current state onto the stack. >+ */ >+ public abstract void push(); >+ >+ /** >+ * Pop the state from the stack and restore the graphics context. >+ * @return the restored state, null if the stack is empty. >+ */ >+ public abstract Graphics2D pop(); >+ >+ /** >+ * Get the current stack level. >+ * >+ * @return the current stack level >+ */ >+ public abstract int getStackLevel(); >+ >+ /** >+ * Establishes a new foreground or fill color. >+ * @param col the color to apply (null skips this operation) >+ * @param fill true to set the fill color, false for the foreground color >+ * @param pdf only used by the PDFRenderer, is set to null. >+ * @return true if the new Color changes the current Color >+ */ >+ public abstract boolean updateColor(ColorType col, boolean fill, StringBuffer pdf); >+ >+ /** >+ * Set the current font name. Check if the font name will change and then >+ * set the new name. >+ * >+ * @param name the new font name >+ * @param size >+ * @param pdf >+ * @return true if the new Font changes the current Font >+ */ >+ public abstract boolean updateFont(String name, int size, StringBuffer pdf); >+ >+ /** >+ * Sets the current Stroke. The line width should be set with >+ * updateLineWidth() before calling this method >+ * >+ * @param style the constant for the style of the line as an int >+ * @return true if the new Stroke changes the current Stroke >+ */ >+ public abstract boolean updateStroke(float width, int style); >+ >+ /** >+ * Set the current paint. This checks if the paint will change and then sets >+ * the current paint. >+ * >+ * @param p the new paint >+ * @return true if the new paint changes the current paint >+ */ >+ public abstract boolean updatePaint(Paint p); >+ >+ /** >+ * Check if the clip will change the current state. A clip is assumed to be >+ * used in a situation where it will add to any clip in the current or >+ * parent states. A clip cannot be cleared, this can only be achieved by >+ * going to a parent level with the correct clip. If the clip is different >+ * then it may start a new state so that it can return to the previous clip. >+ * >+ * @param cl the clip shape to check >+ * @return true if the clip will change the current clip. >+ */ >+ // TODO test >+ public abstract boolean checkClip(Shape cl); >+ >+ /** >+ * Set the current clip. This either sets a new clip or sets the clip to the >+ * intersect of the old clip and the new clip. >+ * >+ * @param cl the new clip in the current state >+ */ >+ public abstract boolean updateClip(Shape cl); >+ >+ /** >+ * Check the current transform. The transform for the current state is the >+ * combination of all transforms in the current state. The parameter is >+ * compared against this current transform. >+ * >+ * @param tf the transform to check against >+ * @return true if the new transform is different from the current transform >+ */ >+ public abstract boolean checkTransform(AffineTransform tf); >+ >+ /** >+ * Overwrites the Transform in the Graphics2D context. Use <code>transform()</code> if you >+ * wish to compose with the current Affinetransform instead. >+ * @see java.awt.Graphics2D.setTransform(). >+ * @param tf the transform to concatonate to the current level transform >+ */ >+ public abstract void setTransform(AffineTransform tf); >+ >+ /** >+ * Composes an AffineTransform object with the Transform in this Graphics2D >+ * according to the rule last-specified-first-applied. >+ * @see java.awt.Graphics2D.transform(). >+ * >+ * @param tf the transform to concatonate to the current level transform >+ */ >+ public abstract void transform(AffineTransform tf); >+ >+ /** >+ * Get the current transform. This gets the combination of all transforms in >+ * the current state. >+ * >+ * @return the calculate combined transform for the current state >+ */ >+ public abstract AffineTransform getTransform(); >+ >+} >Index: src/java/org/apache/fop/render/awt/AWTGraphicsState.java >=================================================================== >RCS file: src/java/org/apache/fop/render/awt/AWTGraphicsState.java >diff -N src/java/org/apache/fop/render/awt/AWTGraphicsState.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/java/org/apache/fop/render/awt/AWTGraphicsState.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,333 @@ >+/* >+ * Copyright 1999-2005 The Apache Software Foundation. >+ * >+ * Licensed under the Apache License, Version 2.0 (the "License"); >+ * you may not use this file except in compliance with the License. >+ * You may obtain a copy of the License at >+ * >+ * http://www.apache.org/licenses/LICENSE-2.0 >+ * >+ * Unless required by applicable law or agreed to in writing, software >+ * distributed under the License is distributed on an "AS IS" BASIS, >+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ * See the License for the specific language governing permissions and >+ * limitations under the License. >+ */ >+ >+/* $Id$ */ >+ >+package org.apache.fop.render.awt; >+ >+import java.awt.BasicStroke; >+import java.awt.Color; >+import java.awt.Graphics2D; >+import java.awt.Paint; >+import java.awt.Shape; >+import java.awt.geom.AffineTransform; >+import java.awt.geom.Area; >+import java.awt.geom.GeneralPath; >+import java.util.List; >+ >+import org.apache.fop.datatypes.ColorType; >+import org.apache.fop.fo.Constants; >+import org.apache.fop.fonts.FontInfo; >+import org.apache.fop.render.RendererState; >+ >+/** >+ * Keeps information about the current state of the Graphics2D currentGraphics. >+ * It is also used as a stack to hold a graphics context. >+ * <p> >+ * The graphics context is updated with the updateXXX() methods. >+ */ >+public class AWTGraphicsState implements Constants, RendererState { >+ >+ /** Holds the datas of the current state */ >+ private Graphics2D currentGraphics; >+ >+ private BasicStroke currentStroke; >+ >+ private float currentStrokeWidth; >+ >+ private int currentStrokeStyle; >+ >+ private List stateStack = new java.util.ArrayList(); >+ >+ /** Font configuration, passed from AWTRenderer */ >+ private FontInfo fontInfo; >+ >+ /** State for storing graphics state. */ >+ public AWTGraphicsState(Graphics2D graphics, FontInfo fontInfo) { >+ this.fontInfo = fontInfo; >+ this.currentGraphics = graphics; >+ } >+ >+ /** >+ * @return the currently valid state >+ */ >+ public Graphics2D getGraph() { >+ return currentGraphics; >+ } >+ >+ /** @see org.apache.fop.render.awt.RendererState#push() */ >+ public void push() { >+ Graphics2D tmpGraphics = (Graphics2D) currentGraphics.create(); >+ stateStack.add(tmpGraphics); >+ } >+ >+ /** @see org.apache.fop.render.awt.RendererState#pop() */ >+ public Graphics2D pop() { >+ if (getStackLevel() > 0) { >+ Graphics2D popped = (Graphics2D) stateStack.remove(stateStack >+ .size() - 1); >+ >+ currentGraphics = popped; >+ return popped; >+ } else { >+ return null; >+ } >+ } >+ >+ /** @see org.apache.fop.render.awt.RendererState#getStackLevel() */ >+ public int getStackLevel() { >+ return stateStack.size(); >+ } >+ >+ /** >+ * Restore the state to a particular level. this can be used to restore to a >+ * known level without making multiple pop calls. >+ * >+ * @param stack the level to restore to >+ */ >+ /* >+ * public void restoreLevel(int stack) { int pos = stack; while >+ * (stateStack.size() > pos + 1) { stateStack.remove(stateStack.size() - 1); } >+ * if (stateStack.size() > pos) { pop(); } } >+ */ >+ >+ /** >+ * Set the current background color. Check if the background color will >+ * change and then set the new color. >+ * >+ * @param col the new color as a java.awt.Color >+ * @return true if the background color has changed >+ */ >+ public boolean updateColor(Color col) { >+ if (!col.equals(getGraph().getColor())) { >+ getGraph().setColor(col); >+ return true; >+ } else { >+ return false; >+ } >+ } >+ >+ /** >+ * Converts a ColorType to a java.awt.Color (sRGB). >+ * >+ * @param col the color as a org.apache.fop.datatypes.ColorType >+ * @return the converted color as a java.awt.Color >+ */ >+ public Color toColor(ColorType col) { >+ return new Color(col.getRed(), col.getGreen(), col.getBlue()); >+ } >+ >+ /** >+ * @see org.apache.fop.render.awt.RendererState#updateColor(org.apache.fop.datatypes.ColorType, >+ * boolean, java.lang.StringBuffer) >+ */ >+ public boolean updateColor(ColorType col, boolean fill, StringBuffer pdf) { >+ if (col == null) { >+ return false; >+ } >+ Color newCol = toColor(col); >+ return updateColor(newCol); >+ } >+ >+ /** >+ * Update the current Color >+ * @param col the ColorType >+ */ >+ public void updateColor(ColorType col) { >+ if (col == null) { >+ return; >+ } >+ Color newCol = toColor(col); >+ updateColor(newCol); >+ } >+ >+ /** >+ * @return the current java.awt.Color >+ */ >+ public java.awt.Color getColor() { >+ return currentGraphics.getColor(); >+ } >+ >+ /** >+ * @see org.apache.fop.render.awt.RendererState#updateFont(java.lang.String, >+ * int, java.lang.StringBuffer) >+ */ >+ public boolean updateFont(String name, int size, StringBuffer pdf) { >+ >+ boolean updateName = (!name.equals(getGraph().getFont().getFontName())); >+ boolean updateSize = (size != (getGraph().getFont().getSize())); >+ >+ if (updateName || updateSize) { >+ // the font name and/or the font size have changed >+ FontMetricsMapper mapper = (FontMetricsMapper) fontInfo >+ .getMetricsFor(name); >+ java.awt.Font font = mapper.getFont(size); >+ >+ currentGraphics.setFont(font); >+ return true; >+ } else { >+ return false; >+ } >+ } >+ >+ /** >+ * @return the current java.awt.Font >+ */ >+ public java.awt.Font getFont() { >+ return currentGraphics.getFont(); >+ } >+ >+ /** >+ * @see org.apache.fop.render.awt.RendererState#updateStroke(float, int) >+ */ >+ public boolean updateStroke(float width, int style) { >+ >+ boolean update = false; >+ >+ // only update if necessary >+ if ((width != currentStrokeWidth) || (style != currentStrokeStyle)) { >+ >+ update = true; >+ >+ switch (style) { >+ case EN_DOTTED: >+ >+ currentStroke = new BasicStroke(width, BasicStroke.CAP_BUTT, >+ BasicStroke.JOIN_BEVEL, 0f, new float[] { 2f }, 0f); >+ currentGraphics.setStroke(currentStroke); >+ >+ currentStrokeWidth = width; >+ currentStrokeStyle = style; >+ >+ break; >+ >+ case EN_DASHED: >+ >+ currentStroke = new BasicStroke(width, BasicStroke.CAP_BUTT, >+ BasicStroke.JOIN_BEVEL, 0f, new float[] { 8f, 2f }, 0f); >+ currentGraphics.setStroke(currentStroke); >+ >+ currentStrokeWidth = width; >+ currentStrokeStyle = style; >+ >+ break; >+ >+ default: // EN_SOLID: >+ >+ currentStroke = new BasicStroke(width); >+ currentGraphics.setStroke(currentStroke); >+ >+ currentStrokeWidth = width; >+ currentStrokeStyle = style; >+ >+ break; >+ } >+ } >+ >+ return update; >+ } >+ >+ public BasicStroke getStroke() { >+ return (BasicStroke) currentGraphics.getStroke(); >+ } >+ >+ /** @see org.apache.fop.render.awt.RendererState#updatePaint(java.awt.Paint) */ >+ public boolean updatePaint(Paint p) { >+ if (getGraph().getPaint() == null) { >+ if (p != null) { >+ getGraph().setPaint(p); >+ return true; >+ } >+ } else if (p.equals(getGraph().getPaint())) { >+ getGraph().setPaint(p); >+ return true; >+ } >+ return false; >+ } >+ >+ /** @see org.apache.fop.render.awt.RendererState#checkClip(java.awt.Shape) */ >+ // TODO implement and test >+ public boolean checkClip(Shape cl) { >+ if (getGraph().getClip() == null) { >+ if (cl != null) { >+ return true; >+ } >+ } else if (cl.equals(getGraph().getClip())) { >+ return true; >+ } >+ // TODO check for clips that are larger than the current >+ return false; >+ } >+ >+ /** >+ * @see org.apache.fop.render.awt.RendererState#updateClip(java.awt.Shape) >+ */ >+ public boolean updateClip(Shape cl) { >+ if (getGraph().getClip() != null) { >+ Area newClip = new Area(getGraph().getClip()); >+ newClip.intersect(new Area(cl)); >+ getGraph().setClip(new GeneralPath(newClip)); >+ } else { >+ getGraph().setClip(cl); >+ } >+ return true; // TODO only update if necessary >+ } >+ >+ /** >+ * @see org.apache.fop.render.awt.RendererState#checkTransform(java.awt.geom.AffineTransform) >+ */ >+ public boolean checkTransform(AffineTransform tf) { >+ return !tf.equals(getGraph().getTransform()); >+ } >+ >+ /** >+ * @see org.apache.fop.render.awt.RendererState#setTransform(java.awt.geom.AffineTransform) >+ */ >+ public void setTransform(AffineTransform tf) { >+ getGraph().setTransform(tf); >+ } >+ >+ /** >+ * @see org.apache.fop.render.awt.RendererState#transform(java.awt.geom.AffineTransform) >+ */ >+ public void transform(AffineTransform tf) { >+ getGraph().transform(tf); >+ } >+ >+ /** >+ * @see org.apache.fop.render.awt.RendererState#getTransform() >+ */ >+ public AffineTransform getTransform() { >+ /* >+ * AffineTransform tf; AffineTransform at = new AffineTransform(); for >+ * (Iterator iter = stateStack.iterator(); iter.hasNext();) { Data d = >+ * (Data) iter.next(); tf = d.transform; at.concatenate(tf); } >+ * at.concatenate(getCurrentGraphics().transform); >+ * >+ * return at; >+ */ >+ return getGraph().getTransform(); >+ } >+ >+ /** a verbose description of the current state */ >+ public String toString() { >+ String s = "AWTGraphicsState " + currentGraphics.toString() >+ + ", Stroke (width: " + currentStrokeWidth + " style: " >+ + currentStrokeStyle + "), " + getTransform() >+ + ", StackLevel: " + getStackLevel(); >+ return s; >+ } >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 33760
:
14371
|
14372
|
14426
|
14520
|
15340