deweese 2003/02/20 03:15:47 Modified: samples/extensions flowText.svg sources/org/apache/batik/extension/svg BatikExtConstants.java SVGFlowTextElementBridge.java sources/org/apache/batik/gvt/text GlyphIterator.java GlyphLayout.java LineInfo.java MarginInfo.java Added: samples/extensions flowTextAlign.svg sources/org/apache/batik/gvt/text RegionInfo.java Log: Flow text syntax is now brought up to date with SVG Drafts (see examples) Flow text now supports vertical-align attribute on flowRegion elements. New (boring) test for vertical align property. Revision Changes Path 1.8 +15 -15 xml-batik/samples/extensions/flowText.svg Index: flowText.svg =================================================================== RCS file: /home/cvs/xml-batik/samples/extensions/flowText.svg,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- flowText.svg 15 Nov 2002 15:46:50 -0000 1.7 +++ flowText.svg 20 Feb 2003 11:15:46 -0000 1.8 @@ -34,20 +34,20 @@ <line x1="243" y1="70" x2="243" y2="490" stroke="grey" fill="none"/> <line x1="423" y1="70" x2="423" y2="490" stroke="grey" fill="none"/> - <batik:flowText xmlns:batik="http://xml.apache.org/batik/ext" - font-size="20" xml:space="preserve"> - <batik:flowLayout> - <batik:flowRegion x="17" y="80" width="200" height="400"/> - <batik:flowRegion x="233" y="80" width="200" height="400"/> - </batik:flowLayout> + <flowText font-size="20" xml:space="preserve" + xmlns="http://xml.apache.org/batik/ext"> + <flowRegion> + <rect x="17" y="80" width="200" height="400"/> + <rect x="233" y="80" width="200" height="400"/> + </flowRegion> - <batik:flowDiv> - <batik:flowPara first-line-left-margin="20" bottom-margin="10" >This is an <batik:flowSpan font-size="40" fill="crimson">ex­ample</batik:flowSpan> of a very long string that is split ‍across multi­ple lines via text wrap­ping.</batik:flowPara> - <batik:flowPara justification="middle" top-margin="10" left-margin="10" right-margin="10" bottom-margin="10"><batik:flowLine>Now check if text wrapping handles a number of tricky</batik:flowLine> situations: averylongrunonwordthatspansmultiplelines<batik:flowSpan font-weight="bold">with<batik:flowSpan fill="crimson">embedded</batik:flowSpan>span</batik:flowSpan>elements & <batik:flowSpan fill="green" dy="-.3em" font-size="80%">super</batik:flowSpan><batik:flowSpan dy=".3em"> or </batik:flowSpan><batik:flowSpan fill="darkgreen" dy=".3em" font-size="80%">sub</batik:flowSpan><batik:flowSpan dy="-.3em"> scripts.</batik:flowSpan></batik:flowPara> - <batik:flowPara top-margin="10" justification="end">Now we are just <batik:flowSpan font-size="30" fill="blue">about</batik:flowSpan> to go to the next flow rect <batik:flowSpan font-size="10">(note if the 'about' were included on the last line of the previous flow rect the line would not have fit and the whole line would have moved here).</batik:flowSpan></batik:flowPara> - <batik:flowPara margin="10" justification="full"> I'll keep going because I want to make sure that it properly stops when it hits the end of all of the the flow regions defined. Also the last line includes text in a larger font size so it will not fit. Thus the end of this sentence will be cut off because the line size gets <batik:flowSpan font-size="35">tall</batik:flowSpan>er</batik:flowPara> - </batik:flowDiv> - </batik:flowText> + <flowDiv> + <flowPara indent="20" bottom-margin="10" >This is an <flowSpan font-size="40" fill="crimson">ex­ample</flowSpan> of a very long string that is split ‍across multi­ple lines via text wrap­ping.</flowPara> + <flowPara justification="middle" top-margin="10" left-margin="10" right-margin="10" bottom-margin="10"><flowLine>Now check if text wrapping handles a number of tricky</flowLine> situations: averylongrunonwordthatspansmultiplelines<flowSpan font-weight="bold">with<flowSpan fill="crimson">embedded</flowSpan>span</flowSpan>elements & <flowSpan fill="green" dy="-.3em" font-size="80%">super</flowSpan><flowSpan dy=".3em"> or </flowSpan><flowSpan fill="darkgreen" dy=".3em" font-size="80%">sub</flowSpan><flowSpan dy="-.3em"> scripts.</flowSpan></flowPara> + <flowPara top-margin="10" justification="end">Now we are just <flowSpan font-size="30" fill="blue">about</flowSpan> to go to the next flow rect <flowSpan font-size="10">(note if the 'about' were included on the last line of the previous flow rect the line would not have fit and the whole line would have moved here).</flowSpan></flowPara> + <flowPara margin="10" justification="full"> I'll keep going because I want to make sure that it properly stops when it hits the end of all of the the flow regions defined. Also the last line includes text in a larger font size so it will not fit. Thus the end of this sentence will be cut off because the line size gets <flowSpan font-size="35">tall</flowSpan>er</flowPara> + </flowDiv> + </flowText> </g> <!-- ============================================================= --> 1.1 xml-batik/samples/extensions/flowTextAlign.svg Index: flowTextAlign.svg =================================================================== <?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> <!-- ====================================================================== --> <!-- Copyright (C) The Apache Software Foundation. All rights reserved. --> <!-- --> <!-- This software is published under the terms of the Apache Software --> <!-- License version 1.1, a copy of which has been included with this --> <!-- distribution in the LICENSE file. --> <!-- ====================================================================== --> <!-- ====================================================================== --> <!-- Tests various text on a path --> <!-- --> <!-- @author [EMAIL PROTECTED] --> <!-- @version $Id: flowTextAlign.svg,v 1.1 2003/02/20 11:15:46 deweese Exp $ --> <!-- ====================================================================== --> <?xml-stylesheet type="text/css" href="extension.css" ?> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="body" width="450" height="500" viewBox="0 0 450 500"> <title>Test of Text vertical-align.</title> <g id="content" > <text class="title" x="50%" y="40">Test of Text vertical-align</text> <g font-family="serif" transform="translate(0,60)"> <g fill="rgb(220,220,255)"> <rect x="12.5" y="0" width="125" height="36"/> <rect x="162.5" y="0" width="125" height="36"/> <rect x="312.5" y="0" width="125" height="36"/> </g> <flowText xmlns="http://xml.apache.org/batik/ext" font-size="24" xml:space="preserve"> <flowRegion vertical-align="top"> <rect x="12.5" y="0" width="125" height="36"/> </flowRegion> <flowRegion vertical-align="middle"> <rect x="162.5" y="0" width="125" height="36"/> </flowRegion> <flowRegion vertical-align="bottom"> <rect x="312.5" y="0" width="125" height="36"/> </flowRegion> <flowDiv> <flowRegionBreak justification="middle" >Try top</flowRegionBreak> <flowRegionBreak justification="middle" >Try middle</flowRegionBreak> <flowRegionBreak justification="middle" >Try bottom</flowRegionBreak> </flowDiv> </flowText> </g> <g font-family="serif" transform="translate(0,120)" > <g fill="rgb(220,220,255)"> <rect x="12.5" y="0" width="125" height="36"/> <rect x="12.5" y="40" width="125" height="36"/> <rect x="162.5" y="0" width="125" height="36"/> <rect x="162.5" y="40" width="125" height="36"/> <rect x="312.5" y="0" width="125" height="36"/> <rect x="312.5" y="40" width="125" height="36"/> </g> <flowText xmlns="http://xml.apache.org/batik/ext" font-size="24" xml:space="preserve"> <flowRegion vertical-align="top"> <rect x="12.5" y="0" width="125" height="36"/> <rect x="12.5" y="40" width="125" height="36"/> </flowRegion> <flowRegion vertical-align="middle"> <rect x="162.5" y="0" width="125" height="36"/> <rect x="162.5" y="40" width="125" height="36"/> </flowRegion> <flowRegion vertical-align="bottom"> <rect x="312.5" y="0" width="125" height="36"/> <rect x="312.5" y="40" width="125" height="36"/> </flowRegion> <flowDiv> <flowRegionBreak justification="middle" >Try top two lines</flowRegionBreak> <flowRegionBreak justification="middle" >Middle two lines</flowRegionBreak> <flowRegionBreak justification="middle" >Bottom two lines</flowRegionBreak> </flowDiv> </flowText> </g> <g font-family="serif" transform="translate(0,220)" > <g fill="rgb(220,220,255)"> <rect x="12.5" y="0" width="125" height="72"/> <rect x="162.5" y="0" width="125" height="72"/> <rect x="312.5" y="0" width="125" height="72"/> </g> <flowText xmlns="http://xml.apache.org/batik/ext" font-size="24" xml:space="preserve"> <flowRegion vertical-align="top"> <rect x="12.5" y="0" width="125" height="72"/> </flowRegion> <flowRegion vertical-align="middle"> <rect x="162.5" y="0" width="125" height="72"/> </flowRegion> <flowRegion vertical-align="bottom"> <rect x="312.5" y="0" width="125" height="72"/> </flowRegion> <flowDiv> <flowRegionBreak justification="middle" >Try top two lines</flowRegionBreak> <flowRegionBreak justification="middle" >Middle two lines</flowRegionBreak> <flowRegionBreak justification="middle" >Bottom two lines</flowRegionBreak> </flowDiv> </flowText> </g> <g font-family="serif" transform="translate(0,320)" > <g fill="rgb(220,220,255)"> <rect x="12.5" y="0" width="125" height="72"/> <rect x="162.5" y="0" width="125" height="72"/> <rect x="312.5" y="0" width="125" height="72"/> </g> <flowText xmlns="http://xml.apache.org/batik/ext" font-size="24" xml:space="preserve"> <flowRegion vertical-align="top"> <rect x="12.5" y="0" width="125" height="72"/> </flowRegion> <flowRegion vertical-align="middle"> <rect x="162.5" y="0" width="125" height="72"/> </flowRegion> <flowRegion vertical-align="bottom"> <rect x="312.5" y="0" width="125" height="72"/> </flowRegion> <flowDiv> <flowPara justification="middle" >Try top</flowPara> <flowRegionBreak justification="middle" >two lines</flowRegionBreak> <flowPara justification="middle" >Middle</flowPara> <flowRegionBreak justification="middle" >two lines</flowRegionBreak> <flowPara justification="middle" >Bottom</flowPara> <flowRegionBreak justification="middle" >two lines</flowRegionBreak> </flowDiv> </flowText> </g> </g> <!-- ============================================================= --> <!-- Batik sample mark --> <!-- ============================================================= --> <use xlink:href="../batikLogo.svg#Batik_Tag_Box" /> </svg> 1.15 +70 -51 xml-batik/sources/org/apache/batik/extension/svg/BatikExtConstants.java Index: BatikExtConstants.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/extension/svg/BatikExtConstants.java,v retrieving revision 1.14 retrieving revision 1.15 diff -u -r1.14 -r1.15 --- BatikExtConstants.java 25 Nov 2002 16:14:15 -0000 1.14 +++ BatikExtConstants.java 20 Feb 2003 11:15:47 -0000 1.15 @@ -23,17 +23,59 @@ public static final String BATIK_EXT_STAR_TAG = "star"; - /** Tag name for Batik's flowText extension (SVG 1.1). */ + /** Tag name for Batik's flowText extension (SVG 1.2). */ public static final String BATIK_EXT_FLOW_TEXT_TAG = "flowText"; - /** Tag name for Batik's flowText extension Region element (SVG 1.1). */ - public static final String BATIK_EXT_FLOW_LAYOUT_TAG = - "flowLayout"; - /** Tag name for Batik's flowText extension Region element (SVG 1.1). */ + /** Tag name for Batik's flowText extension Region element (SVG 1.2). */ public static final String BATIK_EXT_FLOW_REGION_TAG = "flowRegion"; + /** Tag name for Batik's flowText extension Region element (SVG 1.2). */ + public static final String BATIK_EXT_FLOW_REGION_EXCLUDE_TAG = + "flowRegionExclude"; + + /** Tag name for Batik's flowText extension div element SVG 1.2). */ + public static final String BATIK_EXT_FLOW_DIV_TAG = + "flowDiv"; + + /** Tag name for Batik's flowText extension p element SVG 1.2). */ + public static final String BATIK_EXT_FLOW_PARA_TAG = + "flowPara"; + + /** Tag name for Batik's flowText extension flow Region break + * element SVG 1.2). */ + public static final String BATIK_EXT_FLOW_REGION_BREAK_TAG = + "flowRegionBreak"; + + /** Tag name for Batik's flowText extension line element SVG 1.2). */ + public static final String BATIK_EXT_FLOW_LINE_TAG = + "flowLine"; + + /** Tag name for Batik's flowText extension span element SVG 1.2). */ + public static final String BATIK_EXT_FLOW_SPAN_TAG = + "flowSpan"; + + /** Tag name for Batik's solid color extension (SVG 1.2). */ + public static final String BATIK_EXT_SOLID_COLOR_TAG = + "solidColor"; + + /** Tag name for Batik's color switch extension. */ + public static final String BATIK_EXT_COLOR_SWITCH_TAG = + "colorSwitch"; + + /** Tag name for Batik's histogram normalization extension. */ + public static final String BATIK_EXT_HISTOGRAM_NORMALIZATION_TAG = + "histogramNormalization"; + + /** Tag name for Batik's multiImage extension. */ + public static final String BATIK_EXT_MULTI_IMAGE_TAG = + "multiImage"; + + /** Tag name for Batik's subImage multiImage extension. */ + public static final String BATIK_EXT_SUB_IMAGE_TAG = + "subImage"; + /** Attribute name for dx attribute */ public static final String BATIK_EXT_DX_ATRIBUTE = "dx"; @@ -86,59 +128,36 @@ /** Attribute name for left-margin attribute */ public static final String BATIK_EXT_LEFT_MARGIN_ATTRIBUTE = "left-margin"; - /** Attribute name for first-line-left-margin attribute */ - public static final String BATIK_EXT_FIRST_LINE_LEFT_MARGIN_ATTRIBUTE = - "first-line-left-margin"; - /** Attribute name for first-line-right-margin attribute */ - public static final String BATIK_EXT_FIRST_LINE_RIGHT_MARGIN_ATTRIBUTE = - "first-line-right-margin"; + /** Attribute name for indent attribute/property */ + public static final String BATIK_EXT_INDENT_ATTRIBUTE = + "indent"; /** Attribute name for justification */ public static final String BATIK_EXT_JUSTIFICATION_ATTRIBUTE = "justification"; + /** Value for justification to start of region */ + public static final String BATIK_EXT_JUSTIFICATION_START_VALUE = "start"; + /** Value for justification to middle of region */ + public static final String BATIK_EXT_JUSTIFICATION_MIDDLE_VALUE = "middle"; + /** Value for justification to end of region */ + public static final String BATIK_EXT_JUSTIFICATION_END_VALUE = "end"; + /** Value for justification to both edges of region */ + public static final String BATIK_EXT_JUSTIFICATION_FULL_VALUE = "full"; + + /** Attribute name for preformated data */ public static final String BATIK_EXT_PREFORMATTED_ATTRIBUTE = "preformatted"; - /** Tag name for Batik's flowText extension div element SVG 1.1). */ - public static final String BATIK_EXT_FLOW_DIV_TAG = - "flowDiv"; - - /** Tag name for Batik's flowText extension p element SVG 1.1). */ - public static final String BATIK_EXT_FLOW_PARA_TAG = - "flowPara"; - - /** Tag name for Batik's flowText extension flow Region break - * element SVG 1.1). */ - public static final String BATIK_EXT_FLOW_REGION_BREAK_TAG = - "flowRegionBreak"; - - /** Tag name for Batik's flowText extension line element SVG 1.1). */ - public static final String BATIK_EXT_FLOW_LINE_TAG = - "flowLine"; - - /** Tag name for Batik's flowText extension span element SVG 1.1). */ - public static final String BATIK_EXT_FLOW_SPAN_TAG = - "flowSpan"; - - /** Tag name for Batik's solid color extension (SVG 1.1). */ - public static final String BATIK_EXT_SOLID_COLOR_TAG = - "solidColor"; - - /** Tag name for Batik's color switch extension. */ - public static final String BATIK_EXT_COLOR_SWITCH_TAG = - "colorSwitch"; - - /** Tag name for Batik's histogram normalization extension. */ - public static final String BATIK_EXT_HISTOGRAM_NORMALIZATION_TAG = - "histogramNormalization"; - - /** Tag name for Batik's multiImage extension. */ - public static final String BATIK_EXT_MULTI_IMAGE_TAG = - "multiImage"; - - /** Tag name for Batik's subImage multiImage extension. */ - public static final String BATIK_EXT_SUB_IMAGE_TAG = - "subImage"; + /** Attribute name for preformated data */ + public static final String BATIK_EXT_VERTICAL_ALIGN_ATTRIBUTE = + "vertical-align"; + + /** Value for vertical-align to top of region */ + public static final String BATIK_EXT_ALIGN_TOP_VALUE = "top"; + /** Value for vertical-align to middle of region */ + public static final String BATIK_EXT_ALIGN_MIDDLE_VALUE = "middle"; + /** Value for vertical-align to bottom of region */ + public static final String BATIK_EXT_ALIGN_BOTTOM_VALUE = "bottom"; /** Attribute name for sides attribute */ public static final String BATIK_EXT_SIDES_ATTRIBUTE = 1.8 +62 -46 xml-batik/sources/org/apache/batik/extension/svg/SVGFlowTextElementBridge.java Index: SVGFlowTextElementBridge.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/extension/svg/SVGFlowTextElementBridge.java,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- SVGFlowTextElementBridge.java 15 Nov 2002 15:46:50 -0000 1.7 +++ SVGFlowTextElementBridge.java 20 Feb 2003 11:15:47 -0000 1.8 @@ -39,6 +39,9 @@ import org.apache.batik.gvt.text.GVTAttributedCharacterIterator; import org.apache.batik.gvt.text.MarginInfo; import org.apache.batik.gvt.text.TextPath; +import org.apache.batik.gvt.text.RegionInfo; + +import org.apache.batik.util.SVGConstants; /** * Bridge class for the <flowText> element. @@ -338,47 +341,71 @@ } protected List getRegions(BridgeContext ctx, Element element) { + List ret = new LinkedList(); for (Node n = element.getFirstChild(); n != null; n = n.getNextSibling()) { if (n.getNodeType() != Node.ELEMENT_NODE) continue; if (n.getNamespaceURI() != getNamespaceURI()) continue; + Element e = (Element)n; - String ln = n.getLocalName(); - if (ln.equals(BATIK_EXT_FLOW_LAYOUT_TAG)) { - return gatherRects(ctx, e); + String ln = e.getLocalName(); + if (BATIK_EXT_FLOW_REGION_TAG.equals(ln)) { + // our default alignment is to the top of the flow rect. + float verticalAlignment = 0.0f; + String verticalAlignmentAttribute + = e.getAttribute(BATIK_EXT_VERTICAL_ALIGN_ATTRIBUTE); + + if ((verticalAlignmentAttribute != null) && + (verticalAlignmentAttribute.length() > 0)) { + if (BATIK_EXT_ALIGN_TOP_VALUE.equals + (verticalAlignmentAttribute)) { + verticalAlignment = 0.0f; + } else if (BATIK_EXT_ALIGN_MIDDLE_VALUE.equals + (verticalAlignmentAttribute)) { + verticalAlignment = 0.5f; + } else if (BATIK_EXT_ALIGN_BOTTOM_VALUE.equals + (verticalAlignmentAttribute)) { + verticalAlignment = 1.0f; + } + } + + gatherRegionInfo(ctx, e, verticalAlignment, ret); } } - return null; + + return ret; } - protected List gatherRects(BridgeContext ctx, Element rgn) { - List ret = new LinkedList(); + protected void gatherRegionInfo(BridgeContext ctx, Element rgn, + float verticalAlign, List regions) { + for (Node n = rgn.getFirstChild(); n != null; n = n.getNextSibling()) { + if (n.getNodeType() != Node.ELEMENT_NODE) continue; if (n.getNamespaceURI() != getNamespaceURI()) continue; Element e = (Element)n; String ln = n.getLocalName(); - if (ln.equals(BATIK_EXT_FLOW_REGION_TAG)) { + if (ln.equals(SVGConstants.SVG_RECT_TAG)) { UnitProcessor.Context uctx; uctx = UnitProcessor.createContext(ctx, e); - Rectangle2D r2d = buildRect(uctx, e); - if (r2d != null) - ret.add(r2d); + + RegionInfo ri = buildRegion(uctx, e, verticalAlign); + if (ri != null) + regions.add(ri); } } - - return ret; } - protected Rectangle2D buildRect(UnitProcessor.Context uctx, - Element e) { + protected RegionInfo buildRegion(UnitProcessor.Context uctx, + Element e, + float verticalAlignment) { String s; // 'x' attribute - default is 0 - s = e.getAttributeNS(null, BATIK_EXT_X_ATTRIBUTE); + s = e.getAttribute(BATIK_EXT_X_ATTRIBUTE); float x = 0; if (s.length() != 0) { x = UnitProcessor.svgHorizontalCoordinateToUserSpace @@ -386,7 +413,7 @@ } // 'y' attribute - default is 0 - s = e.getAttributeNS(null, BATIK_EXT_Y_ATTRIBUTE); + s = e.getAttribute(BATIK_EXT_Y_ATTRIBUTE); float y = 0; if (s.length() != 0) { y = UnitProcessor.svgVerticalCoordinateToUserSpace @@ -394,7 +421,7 @@ } // 'width' attribute - required - s = e.getAttributeNS(null, BATIK_EXT_WIDTH_ATTRIBUTE); + s = e.getAttribute(BATIK_EXT_WIDTH_ATTRIBUTE); float w; if (s.length() != 0) { w = UnitProcessor.svgHorizontalLengthToUserSpace @@ -410,7 +437,7 @@ } // 'height' attribute - required - s = e.getAttributeNS(null, BATIK_EXT_HEIGHT_ATTRIBUTE); + s = e.getAttribute(BATIK_EXT_HEIGHT_ATTRIBUTE); float h; if (s.length() != 0) { h = UnitProcessor.svgVerticalLengthToUserSpace @@ -425,7 +452,7 @@ return null; } - return new Rectangle2D.Float(x,y,w,h); + return new RegionInfo(x,y,w,h,verticalAlignment); } /** @@ -544,7 +571,7 @@ TextPath textPath) { Map result = super.getAttributeMap(ctx, element, textPath); String s; - s = element.getAttributeNS(null, BATIK_EXT_PREFORMATTED_ATTRIBUTE); + s = element.getAttribute(BATIK_EXT_PREFORMATTED_ATTRIBUTE); if (s.length() != 0) { if (s.equals("true")) { result.put(PREFORMATTED, Boolean.TRUE); @@ -620,7 +647,7 @@ String s; float top=0, right=0, bottom=0, left=0; - s = e.getAttributeNS(null, BATIK_EXT_MARGIN_ATTRIBUTE); + s = e.getAttribute(BATIK_EXT_MARGIN_ATTRIBUTE); try { if (s.length() != 0) { float f = Float.parseFloat(s); @@ -628,28 +655,28 @@ } } catch(NumberFormatException nfe) { /* nothing */ } - s = e.getAttributeNS(null, BATIK_EXT_TOP_MARGIN_ATTRIBUTE); + s = e.getAttribute(BATIK_EXT_TOP_MARGIN_ATTRIBUTE); try { if (s.length() != 0) { float f = Float.parseFloat(s); top = f; } } catch(NumberFormatException nfe) { /* nothing */ } - s = e.getAttributeNS(null, BATIK_EXT_RIGHT_MARGIN_ATTRIBUTE); + s = e.getAttribute(BATIK_EXT_RIGHT_MARGIN_ATTRIBUTE); try { if (s.length() != 0) { float f = Float.parseFloat(s); right = f; } } catch(NumberFormatException nfe) { /* nothing */ } - s = e.getAttributeNS(null, BATIK_EXT_BOTTOM_MARGIN_ATTRIBUTE); + s = e.getAttribute(BATIK_EXT_BOTTOM_MARGIN_ATTRIBUTE); try { if (s.length() != 0) { float f = Float.parseFloat(s); bottom = f; } } catch(NumberFormatException nfe) { /* nothing */ } - s = e.getAttributeNS(null, BATIK_EXT_LEFT_MARGIN_ATTRIBUTE); + s = e.getAttribute(BATIK_EXT_LEFT_MARGIN_ATTRIBUTE); try { if (s.length() != 0) { float f = Float.parseFloat(s); @@ -657,37 +684,26 @@ } } catch(NumberFormatException nfe) { /* nothing */ } - float flLeft = left; - float flRight = right; - - s = e.getAttributeNS(null, BATIK_EXT_FIRST_LINE_LEFT_MARGIN_ATTRIBUTE); - try { - if (s.length() != 0) { - float f = Float.parseFloat(s); - flLeft = f; - } - } catch(NumberFormatException nfe) { /* nothing */ } - - s = e.getAttributeNS(null,BATIK_EXT_FIRST_LINE_RIGHT_MARGIN_ATTRIBUTE); + float indent = 0; + s = e.getAttribute(BATIK_EXT_INDENT_ATTRIBUTE); try { if (s.length() != 0) { float f = Float.parseFloat(s); - flRight = f; + indent = f; } } catch(NumberFormatException nfe) { /* nothing */ } - int justification = MarginInfo.JUSTIFY_START; - s = e.getAttributeNS(null, BATIK_EXT_JUSTIFICATION_ATTRIBUTE); + s = e.getAttribute(BATIK_EXT_JUSTIFICATION_ATTRIBUTE); try { if (s.length() != 0) { - if (s.equals("start")) { + if (BATIK_EXT_JUSTIFICATION_START_VALUE.equals(s)) { justification = MarginInfo.JUSTIFY_START; - } else if (s.equals("middle")) { + } else if (BATIK_EXT_JUSTIFICATION_MIDDLE_VALUE.equals(s)) { justification = MarginInfo.JUSTIFY_MIDDLE; - } else if (s.equals("end")) { + } else if (BATIK_EXT_JUSTIFICATION_END_VALUE.equals(s)) { justification = MarginInfo.JUSTIFY_END; - } else if (s.equals("full")) { + } else if (BATIK_EXT_JUSTIFICATION_FULL_VALUE.equals(s)) { justification = MarginInfo.JUSTIFY_FULL; } } @@ -695,8 +711,8 @@ String ln = e.getLocalName(); boolean rgnBr = ln.equals(BATIK_EXT_FLOW_REGION_BREAK_TAG); - return new MarginInfo(top, right, bottom, left, flLeft, flRight, - justification, rgnBr); + return new MarginInfo(top, right, bottom, left, + indent, justification, rgnBr); } 1.8 +3 -2 xml-batik/sources/org/apache/batik/gvt/text/GlyphIterator.java Index: GlyphIterator.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/gvt/text/GlyphIterator.java,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- GlyphIterator.java 22 May 2002 21:50:40 -0000 1.7 +++ GlyphIterator.java 20 Feb 2003 11:15:47 -0000 1.8 @@ -348,7 +348,8 @@ public LineInfo newLine(Point2D.Float loc, float lineWidth, - boolean partial) { + boolean partial, + Point2D.Float verticalAlignOffset) { if (ch == SOFT_HYPHEN) { gv.setGlyphVisible(idx, true); } @@ -410,7 +411,7 @@ maxFontSize = -Float.MAX_VALUE; LineInfo ret = new LineInfo(loc, aci, gv, lineIdx, lineInfoIdx, lineInfoAdj, lineInfoAdv, lineInfoChW, - lineWidth, partial); + lineWidth, partial, verticalAlignOffset); lineIdx = idx; return ret; 1.48 +147 -56 xml-batik/sources/org/apache/batik/gvt/text/GlyphLayout.java Index: GlyphLayout.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/gvt/text/GlyphLayout.java,v retrieving revision 1.47 retrieving revision 1.48 diff -u -r1.47 -r1.48 --- GlyphLayout.java 19 Feb 2003 02:50:57 -0000 1.47 +++ GlyphLayout.java 20 Feb 2003 11:15:47 -0000 1.48 @@ -87,7 +87,6 @@ private boolean pathApplied = false; - public static final AttributedCharacterIterator.Attribute FLOW_LINE_BREAK = GVTAttributedCharacterIterator.TextAttribute.FLOW_LINE_BREAK; @@ -159,7 +158,6 @@ } - /** * Creates the specified text layout using the * specified AttributedCharacterIterator and rendering context. @@ -2010,7 +2008,7 @@ * text to wrap. There is one aci per text chunk * (which maps to flowPara elements. Used to access * font, paragraph, and line break info. - * @param ChunkLayouts A List of List of GlyphLayout objects. There + * @param chunkLayouts A List of List of GlyphLayout objects. There * is a List of GlyphLayout objects for each * flowPara element. There is a GlyphLayout * for approximately each sub element in the @@ -2021,7 +2019,6 @@ public static void textWrapTextChunk(AttributedCharacterIterator [] acis, List chunkLayouts, List flowRects) { - int justification; int numChunks = acis.length; // System.out.println("Len: " + acis.length + " Size: " + // chunkLayouts.size()); @@ -2029,27 +2026,36 @@ // Make a list of the GlyphVectors so we can construct a // multiGlyphVector that makes them all look like one big // glyphVector - GVTGlyphVector [] gvs = new GVTGlyphVector [acis.length]; + GVTGlyphVector [] gvs = new GVTGlyphVector[acis.length]; + List [] chunkLineInfos = new List [acis.length]; + GlyphIterator [] gis = new GlyphIterator [acis.length]; Iterator clIter = chunkLayouts.iterator(); // Get an iterator for the flow rects. Iterator flowRectsIter = flowRects.iterator(); // Get info for new flow rect. - Rectangle2D cRect = (Rectangle2D)flowRectsIter.next(); - float y0, x0, width, height; - height = (float)cRect.getHeight(); + RegionInfo currentRegion = null; + float y0, x0, width, height=0; + if (flowRectsIter.hasNext()) { + currentRegion = (RegionInfo) flowRectsIter.next(); + height = (float) currentRegion.getHeight(); + } boolean lineHeightRelative = true; float lineHeight = 1.0f; float nextLineMult = 0.0f; float dy = 0.0f; + // + Point2D.Float verticalAlignOffset = new Point2D.Float(0,0); + //System.out.println("Chunks: " + numChunks); float prevBotMargin = 0; for (int chunk=0; clIter.hasNext(); chunk++) { // System.out.println("Chunk: " + chunk); AttributedCharacterIterator aci = acis[chunk]; + if (currentRegion != null) { List extraP = (List)aci.getAttribute(FLOW_EMPTY_PARAGRAPH); if (extraP != null) { @@ -2065,12 +2071,15 @@ } else { // Move to next flow region.. if (!flowRectsIter.hasNext()) { - cRect = null; + currentRegion = null; break; // No flow rect stop layout here... } - cRect = (Rectangle2D)flowRectsIter.next(); - height = (float)cRect.getHeight(); + // NEXT FLOW REGION + currentRegion = (RegionInfo) flowRectsIter.next(); + height = (float) currentRegion.getHeight(); + // start a new alignment offset for this flow rect. + verticalAlignOffset = new Point2D.Float(0,0); // New rect so no previous row to consider... dy = emi.getTopMargin(); @@ -2078,7 +2087,7 @@ prevBotMargin = emi.getBottomMargin(); } - if (cRect == null) break; + if (currentRegion == null) break; } } @@ -2100,9 +2109,9 @@ if (mi == null) { continue; } - justification = mi.getJustification(); + int justification = mi.getJustification(); - if (cRect == null) { + if (currentRegion == null) { for(int idx=0; idx <numGlyphs; idx++) gv.setGlyphVisible(idx, false); continue; @@ -2114,39 +2123,57 @@ dy += inc; } else { // Move to next flow region.. + // NEXT FLOW REGION if (!flowRectsIter.hasNext()) { - cRect = null; + currentRegion = null; break; // No flow rect stop layout here... } - cRect = (Rectangle2D)flowRectsIter.next(); - height = (float)cRect.getHeight(); + // NEXT FLOW REGION + currentRegion = (RegionInfo) flowRectsIter.next(); + height = (float) currentRegion.getHeight(); + // start a new alignment offset for this flow rect.. + verticalAlignOffset = new Point2D.Float(0,0); // New rect so no previous row to consider... dy = mi.getTopMargin(); } prevBotMargin = mi.getBottomMargin(); - float leftMargin = mi.getFirstLineLeftMargin(); - float rightMargin = mi.getFirstLineRightMargin(); + float leftMargin = mi.getLeftMargin(); + float rightMargin = mi.getRightMargin(); + if (((GlyphLayout)layouts.get(0)).isLeftToRight()) { + leftMargin += mi.getIndent(); + } else { + rightMargin += mi.getIndent(); + } - x0 = (float)cRect.getX() + leftMargin; - y0 = (float)cRect.getY(); - width = (float)(cRect.getWidth() - (leftMargin+rightMargin)); - height = (float)cRect.getHeight(); + x0 = (float) currentRegion.getX() + leftMargin; + y0 = (float) currentRegion.getY(); + width = (float) (currentRegion.getWidth() - + (leftMargin + rightMargin)); + height = (float) currentRegion.getHeight(); List lineInfos = new LinkedList(); + chunkLineInfos[chunk] = lineInfos; float prevDesc = 0.0f; GlyphIterator gi = new GlyphIterator(aci, gv); + gis[chunk] = gi; + GlyphIterator breakGI = null, newBreakGI = null; if (!gi.done() && !gi.isPrinting()) { - // This will place any preceeding whitespace on an imaginary - // line that preceeds the real first line of the paragraph. - lineInfos.add(gi.newLine - (new Point2D.Float(x0, y0+dy), - width, true)); + // This will place any preceeding whitespace on an + // imaginary line that preceeds the real first line of + // the paragraph, also calculate the vertical + // alignment offset, this will be repeated until the + // last line in the flow rect. + updateVerticalAlignOffset(verticalAlignOffset, + currentRegion, dy); + lineInfos.add(gi.newLine + (new Point2D.Float(x0, y0+dy), + width, true, verticalAlignOffset)); } @@ -2161,20 +2188,24 @@ // first char on line didn't fit. // move to next flow rect. if (!flowRectsIter.hasNext()) { - cRect = null; + currentRegion = null; gi = lineGI.copy(gi); break; // No flow rect stop layout here... } - cRect = (Rectangle2D)flowRectsIter.next(); - x0 = (float) cRect.getX() + leftMargin; - y0 = (float) cRect.getY(); - width = (float)(cRect.getWidth() - + // NEXT FLOW REGION + currentRegion = (RegionInfo) flowRectsIter.next(); + x0 = (float) currentRegion.getX() + leftMargin; + y0 = (float) currentRegion.getY(); + width = (float) (currentRegion.getWidth() - (leftMargin+rightMargin)); - height = (float)cRect.getHeight(); + height = (float) currentRegion.getHeight(); + // start a new alignment offset for this flow rect.. + verticalAlignOffset = new Point2D.Float(0,0); // New rect so no previous row to consider... - dy = firstLine?mi.getTopMargin():0; ; + dy = firstLine ? mi.getTopMargin() : 0; + ; prevDesc = 0; gi = lineGI.copy(gi); continue; @@ -2259,7 +2290,7 @@ // System.out.println("Doesn't Fit: " + dy); if (!flowRectsIter.hasNext()) { - cRect = null; + currentRegion = null; gi = lineGI.copy(gi); break; // No flow rect stop layout here... } @@ -2268,15 +2299,18 @@ float oldWidth = width; // Get info for new flow rect. - cRect = (Rectangle2D)flowRectsIter.next(); - x0 = (float) cRect.getX() + leftMargin; - y0 = (float) cRect.getY(); - width = (float)(cRect.getWidth() - - (leftMargin+rightMargin)); - height = (float)cRect.getHeight(); + currentRegion = (RegionInfo) flowRectsIter.next(); + x0 = (float) currentRegion.getX() + leftMargin; + y0 = (float) currentRegion.getY(); + width = (float)(currentRegion.getWidth() - + (leftMargin+rightMargin)); + height = (float) currentRegion.getHeight(); + // start a new alignment offset for this flow rect.. + verticalAlignOffset = new Point2D.Float(0,0); // New rect so no previous row to consider... - dy = firstLine?mi.getTopMargin():0; ; + dy = firstLine ? mi.getTopMargin() : 0; + ; prevDesc = 0; // previous flows? @@ -2289,8 +2323,11 @@ prevDesc = newDesc + (nextLineMult-1)*lineBoxHeight; nextLineMult = 0f; + updateVerticalAlignOffset(verticalAlignOffset, + currentRegion, dy + bottomEdge); lineInfos.add(gi.newLine - (new Point2D.Float(x0, y0+dy), width, partial)); + (new Point2D.Float(x0, y0 + dy), width, partial, + verticalAlignOffset)); // System.out.println("Fit: " + dy); x0 -= leftMargin; @@ -2312,22 +2349,69 @@ while(idx <numGlyphs) gv.setGlyphVisible(idx++, false); - layoutChunk(aci, gv, gi.getOrigin(), justification, lineInfos); - if (mi.isFlowRegionBreak()) { // Move to next flow region.. - cRect = null; + currentRegion = null; if (flowRectsIter.hasNext()) { - cRect = (Rectangle2D)flowRectsIter.next(); - height = (float)cRect.getHeight(); + currentRegion = (RegionInfo) flowRectsIter.next(); + height = (float) currentRegion.getHeight(); dy = mi.getTopMargin(); + verticalAlignOffset = new Point2D.Float(0,0); } } } + + for (int chunk=0; chunk < acis.length; chunk++) { + List lineInfos = chunkLineInfos[chunk]; + if (lineInfos == null) continue; + + AttributedCharacterIterator aci = acis[chunk]; + aci.first(); + MarginInfo mi = (MarginInfo)aci.getAttribute(FLOW_PARAGRAPH); + if (mi == null) { + continue; + } + int justification = mi.getJustification(); + + GVTGlyphVector gv = gvs[chunk]; + if (gv == null) break; + + GlyphIterator gi = gis[chunk]; + + layoutChunk(gv, gi.getOrigin(), justification, lineInfos); + } } - public static void layoutChunk(AttributedCharacterIterator aci, - GVTGlyphVector gv, Point2D origin, + + /** + * Updates the specified verticalAlignmentOffset using the current + * alignment rule and the heights of the flow rect and the maximum + * descent of the text. This method gets for called every line, + * but only the value that is calculated for the last line of the + * flow rect is used by the glyph rendering. This is achieved by + * creating a new verticalAlignOffset object everytime a new flow + * rect is encountered, thus a single verticalAlignmentOffset is + * shared for all {@link LineInfo} objects created for a given + * flow rect. The value is calculated by determining the left + * over space in the flow rect and scaling that value by 1.0 to + * align to the bottom, 0.5 for middle and 0.0 for top. + * + * @param verticalAlignOffset the {@link Point2D.Float} object that + * is storing the alignment offset. + * @param currentRegion the {@link RegionInfo} object that we + * are rendering into. + * @param maxDescent the very lowest point this line reaches. + */ + public static void updateVerticalAlignOffset + (Point2D.Float verticalAlignOffset, + RegionInfo region, float maxDescent) + { + float freeSpace = (float)region.getHeight() - maxDescent; + verticalAlignOffset.setLocation + (0, region.getVerticalAlignment() * freeSpace); + } + + public static void layoutChunk(GVTGlyphVector gv, Point2D origin, int justification, List lineInfos) { Iterator lInfoIter = lineInfos.iterator(); @@ -2345,6 +2429,7 @@ float charW=0; float lineWidth=0; boolean partial = false; + float verticalAlignOffset = 0; // This loop goes through and puts glyphs where they belong // based on info collected in first trip through glyphVector... @@ -2370,14 +2455,19 @@ charW = li.getLastCharWidth(); lineWidth = li.getLineWidth(); partial = li.isPartialLine(); + verticalAlignOffset = li.getVerticalAlignOffset().y; xAdj = 0; xScale = 1; // Recalc justification info. switch (justification) { case 0: default: break; // Left - case 1: xAdj = (lineWidth-lineVAdv)/2; break; // Center - case 2: xAdj = lineWidth-lineVAdv; break; // Right + case 1: // Center + xAdj = (lineWidth - lineVAdv) / 2; + break; + case 2: // Right + xAdj = lineWidth - lineVAdv; + break; case 3: // Full if ((!partial) && (lineEnd != i+1)) { // More than one char on line... @@ -2388,7 +2478,8 @@ } } float x = lineLoc.x + (gp[2*i] -xOrig)*xScale+xAdj; - float y = lineLoc.y + (gp[2*i+1]-yOrig); + float y = lineLoc.y + ((gp[2 * i + 1] - yOrig) + + verticalAlignOffset); gv.setGlyphPosition(i, new Point2D.Float(x, y)); } @@ -2396,7 +2487,7 @@ float y = yOrig; if (lineLoc != null) { x = lineLoc.x + (gp[2*i] -xOrig)*xScale+xAdj; - y = lineLoc.y + (gp[2*i+1]-yOrig); + y = lineLoc.y + (gp[2 * i + 1] - yOrig) + verticalAlignOffset; } gv.setGlyphPosition(i, new Point2D.Float(x, y)); } 1.4 +7 -2 xml-batik/sources/org/apache/batik/gvt/text/LineInfo.java Index: LineInfo.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/gvt/text/LineInfo.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- LineInfo.java 8 May 2002 09:42:47 -0000 1.3 +++ LineInfo.java 20 Feb 2003 11:15:47 -0000 1.4 @@ -28,6 +28,7 @@ float lastCharWidth; float lineWidth; boolean partial; + Point2D.Float verticalAlignOffset; /** * @@ -40,7 +41,8 @@ float visualAdvance, float lastCharWidth, float lineWidth, - boolean partial) { + boolean partial, + Point2D.Float verticalAlignOffset) { this.loc = loc; this.aci = aci; this.gv = gv; @@ -51,6 +53,7 @@ this.lastCharWidth = lastCharWidth; this.lineWidth = lineWidth; this.partial = partial; + this.verticalAlignOffset = verticalAlignOffset; } public Point2D.Float getLocation() { return loc; } @@ -63,6 +66,7 @@ public float getLastCharWidth() { return lastCharWidth; } public float getLineWidth() { return lineWidth; } public boolean isPartialLine() { return partial; } + public Point2D.Float getVerticalAlignOffset() { return verticalAlignOffset; } public String toString() { return ("[LineInfo loc: " + loc + @@ -70,7 +74,8 @@ " LWidth: " + lineWidth + " Adv: " + advance + " VAdv: " + visualAdvance + " LCW: " + lastCharWidth + - " Partial: " + partial); + " Partial: " + partial + + " verticalAlignOffset: " + verticalAlignOffset); } } 1.4 +13 -16 xml-batik/sources/org/apache/batik/gvt/text/MarginInfo.java Index: MarginInfo.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/gvt/text/MarginInfo.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- MarginInfo.java 30 Apr 2002 19:08:48 -0000 1.3 +++ MarginInfo.java 20 Feb 2003 11:15:47 -0000 1.4 @@ -19,23 +19,21 @@ protected float bottom; protected float left; - protected float firstLineLeft; - protected float firstLineRight; + protected float indent; protected int justification; protected boolean flowRegionBreak; public MarginInfo(float top, float right, float bottom, float left, - float firstLineLeft, float firstLineRight, - int justification, boolean flowRegionBreak) { + float indent, int justification, + boolean flowRegionBreak) { this.top = top; this.right = right; this.bottom = bottom; this.left = left; - this.firstLineLeft = firstLineLeft; - this.firstLineRight = firstLineRight; + this.indent = indent; this.justification = justification; this.flowRegionBreak = flowRegionBreak; @@ -43,6 +41,7 @@ public MarginInfo(float margin, int justification) { setMargin(margin); + this.indent = 0; this.justification = justification; this.flowRegionBreak = false; } @@ -52,17 +51,15 @@ this.right = margin; this.bottom = margin; this.left = margin; - this.firstLineLeft = margin; - this.firstLineRight = margin; } - public float getTopMargin() { return top; } - public float getRightMargin() { return right; } - public float getBottomMargin() { return bottom; } - public float getLeftMargin() { return left; } - public float getFirstLineLeftMargin() { return firstLineLeft; } - public float getFirstLineRightMargin() { return firstLineLeft; } + public float getTopMargin() { return top; } + public float getRightMargin() { return right; } + public float getBottomMargin() { return bottom; } + public float getLeftMargin() { return left; } - public int getJustification() { return justification; } - public boolean isFlowRegionBreak() { return flowRegionBreak; } + public float getIndent() { return indent; } + + public int getJustification() { return justification; } + public boolean isFlowRegionBreak() { return flowRegionBreak; } } 1.1 xml-batik/sources/org/apache/batik/gvt/text/RegionInfo.java Index: RegionInfo.java =================================================================== /***************************************************************************** * Copyright (C) The Apache Software Foundation. All rights reserved. * * ------------------------------------------------------------------------- * * This software is published under the terms of the Apache Software License * * version 1.1, a copy of which has been included with this distribution in * * the LICENSE file. * *****************************************************************************/ package org.apache.batik.gvt.text; import java.awt.geom.Rectangle2D; /** * This class holds the neccessary information to render a * <batik:regin> that is defined within the <batik:flowRegion> * element. Namely it holds the bounds of the region and the desired * vertical alignment. */ public class RegionInfo extends Rectangle2D.Float { private float verticalAlignment = 0.0f; public RegionInfo(float x, float y, float w, float h, float verticalAlignment) { super(x, y, w, h); this.verticalAlignment = verticalAlignment; } /** * Gets the vertical alignment for this flow region. * @return the vertical alignment for this flow region. * It will be 0.0 for top, 0.5 for middle and 1.0 for bottom. */ public float getVerticalAlignment() { return verticalAlignment; } /** * Sets the alignment position of the text within this flow region. * The value must be 0.0 for top, 0.5 for middle and 1.0 for bottom. * @param verticalAlignment the vertical alignment of the text. */ public void setVerticalAlignment(float verticalAlignment) { this.verticalAlignment = verticalAlignment; } }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]