--- src/java/org/apache/fop/render/xml/XMLRenderer.java (revision 919765) +++ src/java/org/apache/fop/render/xml/XMLRenderer.java (working copy) @@ -27,6 +27,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Vector; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.sax.SAXTransformerFactory; @@ -84,6 +85,7 @@ import org.apache.fop.fo.extensions.ExtensionAttachment; import org.apache.fop.fo.extensions.ExtensionElementMapping; import org.apache.fop.fo.extensions.InternalElementMapping; +import org.apache.fop.fo.flow.ChangeBar; import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontTriplet; import org.apache.fop.render.Renderer; @@ -181,6 +183,22 @@ + area.getBorderAndPaddingWidthEnd() + " " + area.getBorderAndPaddingWidthBefore() + " " + area.getBorderAndPaddingWidthAfter()); + + Vector v = area.getChangeBars(); + + if (null != v && v.size() > 0) { + StringBuffer buf = new StringBuffer(); + + for (int idx = 0; idx < v.size(); idx++) { + ChangeBar cb = (ChangeBar)v.get(idx); + + if (0 != idx) { + buf.append(","); + } + buf.append(cb.getCBClass()); + } + addAttribute("change-bars", buf.toString()); + } } } @@ -517,6 +535,8 @@ addAreaAttributes(region); addTraitAttributes(region); addAttribute("name", region.getRegionName()); + addAttribute("writingMode", region.getWritingMode()); + addAttribute("referenceOrientation", region.getReferenceOrientation()); addAttribute("ctm", region.getCTM().toString()); if (region.getRegionClass() == FO_REGION_BEFORE) { startElement("regionBefore", atts); --- src/java/org/apache/fop/render/pdf/PDFEventProducer.xml (revision 919765) +++ src/java/org/apache/fop/render/pdf/PDFEventProducer.xml (working copy) @@ -1,5 +1,5 @@ {count} link target{count,equals,1,,s} could not be fully resolved and now point{count,equals,1,,s} to the top of the page or {count,equals,1,is,are} dysfunctional. - ‘{type}’ is not a standard structure type defined by the PDF Reference. Falling back to ‘{fallback}’. + ???{type}??? is not a standard structure type defined by the PDF Reference. Falling back to ???{fallback}???. --- src/java/org/apache/fop/render/AbstractRenderer.java (revision 919765) +++ src/java/org/apache/fop/render/AbstractRenderer.java (working copy) @@ -28,6 +28,7 @@ import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.Vector; import org.w3c.dom.Document; @@ -68,7 +69,9 @@ import org.apache.fop.area.inline.WordArea; import org.apache.fop.events.ResourceEventProducer; import org.apache.fop.fo.Constants; +import org.apache.fop.fo.flow.ChangeBar; import org.apache.fop.fonts.FontInfo; +import org.apache.fop.traits.BorderProps; /** * Abstract base class for all renderers. The Abstract renderer does all the @@ -108,6 +111,48 @@ */ protected int containingIPPosition = 0; + /** + * The "start edge" IP Position of the current column (for change bars) + */ + protected int columnStartIPPosition = 0; + + /** + * The "end edge" IP Position of the current column (for change bars) + */ + protected int columnEndIPPosition = 0; + + /** + * The "left" position of the current column (for change bars) + */ + protected int columnLeftIPPosition = 0; + + /** + * The "right" position of the current column (for change bars) + */ + protected int columnRightIPPosition = 0; + + /** + * The number of columns in the span (for change bars) + */ + protected int columnCount = 0; + + /** + * The index number of the current column (for change bars) + */ + protected int columnNumber = 0; + + /** + * Is binding on start edge of column? + */ + protected boolean bindingOnStartEdge = false; + + /** + * Is binding on end edge of column? + */ + protected boolean bindingOnEndEdge = false; + + + /** the currently active PageViewport */ protected PageViewport currentPageViewport; @@ -403,10 +448,60 @@ int saveSpanBPPos = saveBPPos; for (int count = 0; count < spans.size(); count++) { span = (Span) spans.get(count); + columnCount = span.getColumnCount(); + for (int c = 0; c < span.getColumnCount(); c++) { + columnNumber = c; + NormalFlow flow = span.getNormalFlow(c); + int writingMode = mr.getParent().getWritingMode(); + int referenceOrientation = mr.getParent().getReferenceOrientation(); + + + if (flow != null) { + columnStartIPPosition = currentIPPosition; + columnEndIPPosition = currentIPPosition + flow.getIPD() + mr.getColumnGap(); + + // if direction is right to left, then end is left, else end is right edge + // if orientation is portrait, then binding edge is on left edge for odd pages + // and on right edge for even pages + int pageIndex = currentPageViewport.getPageIndex(); + CTM trans = currentPageViewport.getBodyRegion().getCTM(); + + bindingOnStartEdge = false; + bindingOnEndEdge = false; + + if (writingMode == Constants.EN_RL_TB) { + columnLeftIPPosition = columnEndIPPosition; + columnRightIPPosition = columnStartIPPosition; + if (0 == referenceOrientation) { + if (pageIndex % 2 == 0 ) { + bindingOnEndEdge = true; + } + else { + bindingOnStartEdge = true; + } + } + } + else { + columnLeftIPPosition = columnStartIPPosition; + columnRightIPPosition = columnEndIPPosition; + if (0 == referenceOrientation) { + if (pageIndex % 2 == 0 ) { + bindingOnStartEdge = true; + } + else { + bindingOnEndEdge = true; + } + } + } + + + + + currentBPPosition = saveSpanBPPos; renderFlow(flow); currentIPPosition += flow.getIPD(); @@ -555,6 +650,19 @@ * @param block The block area */ protected void renderBlock(Block block) { + Vector changeBars = block.getChangeBars(); + + if (null != changeBars && !changeBars.isEmpty()) { + // this block has change bars attached to it + int saveIP = currentIPPosition; + int saveBP = currentBPPosition; + + drawChangeBars(block, changeBars); + + currentIPPosition = saveIP; + currentBPPosition = saveBP; + } + List children = block.getChildAreas(); if (block instanceof BlockViewport) { if (children != null) { @@ -616,6 +724,13 @@ * @param inlineArea inline area text to render */ protected void renderInlineArea(InlineArea inlineArea) { + Vector changeBars = inlineArea.getChangeBars(); + + if (null != changeBars && !changeBars.isEmpty()) { + // area has change bar, handle + drawChangeBars(inlineArea, changeBars); + } + if (inlineArea instanceof TextArea) { renderText((TextArea) inlineArea); //} else if (inlineArea instanceof Character) { @@ -758,6 +873,12 @@ * (todo) Make renderImage() protected */ public void renderImage(Image image, Rectangle2D pos) { + // handle change bars + Vector changeBars = image.getChangeBars(); + + if (null != changeBars && !changeBars.isEmpty()) { + drawChangeBars(image, changeBars); + } // Default: do nothing. // Some renderers (ex. Text) don't support images. } @@ -784,6 +905,13 @@ * (todo) Make renderForeignObject() protected */ protected void renderForeignObject(ForeignObject fo, Rectangle2D pos) { + // handle change bars + Vector changeBars = fo.getChangeBars(); + + if (null != changeBars && !changeBars.isEmpty()) { + drawChangeBars(fo, changeBars); + } + // Default: do nothing. // Some renderers (ex. Text) don't support foreign objects. } @@ -856,4 +984,123 @@ matrix[5] = Math.round(matrix[5] * 1000); return new AffineTransform(matrix); } + + /** + * Draw all change bars associated with an area + * + * @param block The area to draw change bars for + * @param changeBars The list of change bars affecting the area + */ + private void drawChangeBars(Area block, Vector changeBars) { + Block cbArea; + + int saveIP = currentIPPosition; + int saveBP = currentBPPosition; + + for (int idx = 0; idx < changeBars.size(); idx++) { + ChangeBar bar = (ChangeBar)changeBars.get(idx); + cbArea = new Block(); + + currentIPPosition = 0; + currentBPPosition = saveBP; + + // offset by default is negative width for change bars placed on the start edge + // this will be overriden if placement is at the end edge + // xScale is for adding or subtracting the offset of the change bar depending on + // placing the bar towards or away from the edge it is bound to + int xOffset = -bar.getWidth().getValue(); + int xScale = 1; + + // determine currentIPPosition based on placement + switch (bar.getPlacement()) { + case EN_START: + xOffset += columnStartIPPosition; + xScale = -1; + break; + case EN_END: + xOffset = columnEndIPPosition; + break; + case EN_LEFT: + xOffset += columnLeftIPPosition; + xScale = -1; + break; + case EN_RIGHT: + xOffset = columnRightIPPosition; + break; + case EN_INSIDE: + if (bindingOnStartEdge) { + xOffset += columnStartIPPosition; + xScale = -1; + } + else if (bindingOnEndEdge) { + xOffset = columnEndIPPosition; + } + else { + xOffset += columnStartIPPosition; + xScale = -1; + } + break; + case EN_OUTSIDE: + if (bindingOnStartEdge) { + xOffset = columnEndIPPosition; + } + else if (bindingOnEndEdge) { + xOffset += columnStartIPPosition; + xScale = -1; + } + else { + xOffset += columnStartIPPosition; + xScale = -1; + } + break; + case EN_ALTERNATE: + if (2 == columnCount) { + if ( 0 == columnNumber) { + xOffset += columnStartIPPosition; + xScale = -1; + } + else { + xOffset = columnEndIPPosition; + } + } + else { + if (bindingOnStartEdge) { + xOffset = columnEndIPPosition; + } + else if (bindingOnEndEdge) { + xOffset += columnStartIPPosition; + xScale = -1; + } + else { + xOffset = columnStartIPPosition; + xScale = -1; + } + } + break; + default: + // Cannot happen + break; + } + + // Change bar area has 0 ipd, class xsl-absolute, no margin or padding + cbArea.setAreaClass(Area.CLASS_ABSOLUTE); + cbArea.setIPD(0); + cbArea.setPositioning(Block.ABSOLUTE); + cbArea.setBPD(block.getBPD()); + BorderProps props = new BorderProps(bar.getStyle(), bar.getWidth().getValue(), + bar.getColor(), BorderProps.SEPARATE); + + cbArea.addTrait(Trait.BORDER_END, props); + + cbArea.setXOffset(xOffset + xScale * bar.getOffset().getValue()); + cbArea.setYOffset(block.getSpaceBefore()); + + renderBlock(cbArea); + + // restore position on page + currentIPPosition = saveIP; + currentBPPosition = saveBP; + + } + } } --- src/java/org/apache/fop/layoutmgr/ExternalDocumentLayoutManager.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/ExternalDocumentLayoutManager.java (working copy) @@ -178,9 +178,11 @@ Dimension imageSize = this.imageLayout.getViewportSize(); Block blockArea = new Block(); + blockArea.setChangeBars(getChangeBars()); + blockArea.setIPD(imageSize.width); LineArea lineArea = new LineArea(); - + Image imageArea = new Image(uri); TraitSetter.setProducerID(imageArea, fobj.getId()); transferForeignAttributes(imageArea); @@ -246,7 +248,8 @@ rv.setClip(true); BodyRegion body = new BodyRegion(Constants.FO_REGION_BODY, - "fop-image-region", rv, 1, 0); + "fop-image-region", rv, 1, 0, + pageSeq.getReferenceOrientation(), pageSeq.getReferenceOrientation()); body.setIPD(imageSize.width); body.setBPD(imageSize.height); body.setCTM(pageCTM); --- src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java (working copy) @@ -418,6 +418,7 @@ public Area getParentArea(Area childArea) { if (curBlockArea == null) { curBlockArea = new Block(); + curBlockArea.setChangeBars(getChangeBars()); curBlockArea.setIPD(super.getContentAreaIPD()); --- src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java (working copy) @@ -38,6 +38,8 @@ import org.apache.fop.fo.flow.BidiOverride; import org.apache.fop.fo.flow.Block; import org.apache.fop.fo.flow.BlockContainer; +import org.apache.fop.fo.flow.ChangeBarBegin; +import org.apache.fop.fo.flow.ChangeBarEnd; import org.apache.fop.fo.flow.Character; import org.apache.fop.fo.flow.ExternalGraphic; import org.apache.fop.fo.flow.Footnote; @@ -141,6 +143,8 @@ registerMaker(TableHeader.class, new Maker()); registerMaker(Wrapper.class, new WrapperLayoutManagerMaker()); registerMaker(Title.class, new InlineLayoutManagerMaker()); + registerMaker(ChangeBarBegin.class, new Maker()); + registerMaker(ChangeBarEnd.class, new Maker()); } /** --- src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java (working copy) @@ -238,6 +238,7 @@ public Area getParentArea(Area childArea) { if (curBlockArea == null) { curBlockArea = new Block(); + curBlockArea.setChangeBars(getChangeBars()); // Set up dimensions // Must get dimensions from parent area --- src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java (working copy) @@ -602,6 +602,7 @@ public Area getParentArea(Area childArea) { if (curBlockArea == null) { curBlockArea = new Block(); + curBlockArea.setChangeBars(getChangeBars()); // Set up dimensions /*Area parentArea =*/ parentLayoutManager.getParentArea(curBlockArea); --- src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java (working copy) @@ -192,6 +192,8 @@ public Area getParentArea(Area childArea) { if (curBlockArea == null) { curBlockArea = new Block(); + curBlockArea.setChangeBars(getChangeBars()); + curBlockArea.setPositioning(Block.ABSOLUTE); // set position curBlockArea.setXOffset(xoffset); --- src/java/org/apache/fop/layoutmgr/inline/ContentLayoutManager.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/inline/ContentLayoutManager.java (working copy) @@ -85,6 +85,7 @@ // get breaks then add areas to title this.parentLM = pslm; holder = new LineArea(); + holder.setChangeBars(getChangeBars()); // setUserAgent(foTitle.getUserAgent()); @@ -161,6 +162,7 @@ childContext.setIPDAdjust(0.0); childLM.addAreas(posIter, childContext); ((InlineArea)holder).setIPD(savedIPD); + } public int getStackingSize() { --- src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java (working copy) @@ -201,9 +201,11 @@ InlineArea area; if (hasInlineParent) { area = new InlineParent(); + area.setChangeBars(getChangeBars()); area.setOffset(0); } else { area = new InlineBlockParent(); + area.setChangeBars(getChangeBars()); } if (fobj instanceof Inline) { TraitSetter.setProducerID(area, getInlineFO().getId()); @@ -518,6 +520,7 @@ context.setFlags(LayoutContext.LAST_AREA, isLast); areaCreated = true; checkEndOfLayout(lastPos); + } /** {@inheritDoc} */ --- src/java/org/apache/fop/layoutmgr/inline/WrapperLayoutManager.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/inline/WrapperLayoutManager.java (working copy) @@ -68,16 +68,19 @@ if (parentLayoutManager instanceof BlockStackingLayoutManager && !(parentLayoutManager instanceof BlockLayoutManager)) { Block helperBlock = new Block(); + helperBlock.setChangeBars(getChangeBars()); TraitSetter.setProducerID(helperBlock, fobj.getId()); parentLayoutManager.addChildArea(helperBlock); } else { InlineArea area = getEffectiveArea(); + area.setChangeBars(getChangeBars()); parentLayoutManager.addChildArea(area); } } while (posIter.hasNext()) { posIter.next(); } + } /** {@inheritDoc} */ --- src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLayoutManager.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLayoutManager.java (working copy) @@ -70,6 +70,8 @@ int width = getStringWidth(str); text.setIPD(width); } + + text.setChangeBars(getChangeBars()); updateTextAreaTraits(text); return text; --- src/java/org/apache/fop/layoutmgr/inline/ExternalGraphicLayoutManager.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/inline/ExternalGraphicLayoutManager.java (working copy) @@ -42,8 +42,10 @@ /** {@inheritDoc} */ protected Area getChildArea() { - return new Image(((ExternalGraphic) fobj).getSrc()); - } + Image im = new Image(((ExternalGraphic) fobj).getSrc()); + im.setChangeBars(getChangeBars()); + return im; + } } --- src/java/org/apache/fop/layoutmgr/inline/InstreamForeignObjectLM.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/inline/InstreamForeignObjectLM.java (working copy) @@ -46,7 +46,9 @@ org.w3c.dom.Document doc = child.getDOMDocument(); String ns = child.getNamespaceURI(); - return new ForeignObject(doc, ns); + ForeignObject obj = new ForeignObject(doc, ns); + obj.setChangeBars(getChangeBars()); + return obj; } } --- src/java/org/apache/fop/layoutmgr/inline/PageNumberLayoutManager.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/inline/PageNumberLayoutManager.java (working copy) @@ -77,6 +77,8 @@ public InlineArea get(LayoutContext context) { // get page string from parent, build area TextArea text = new TextArea(); + text.setChangeBars(getChangeBars()); + String str = getCurrentPV().getPageNumberString(); int width = getStringWidth(str); text.addWord(str, 0); @@ -98,6 +100,8 @@ //TODO or even better: delay area creation until addAreas() stage //TextArea is cloned because the LM is reused in static areas and the area can't be. TextArea ta = new TextArea(); + ta.setChangeBars(getChangeBars()); + TraitSetter.setProducerID(ta, fobj.getId()); ta.setIPD(baseArea.getIPD()); ta.setBPD(baseArea.getBPD()); --- src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java (working copy) @@ -1451,6 +1451,7 @@ } } setCurrentArea(null); // ?? necessary + } /** @@ -1471,6 +1472,8 @@ LineArea lineArea = new LineArea( (lbp.getLeafPos() < seq.size() - 1 ? textAlignment : textAlignmentLast), lbp.difference, lbp.availableStretch, lbp.availableShrink); + lineArea.setChangeBars(getChangeBars()); + if (lbp.startIndent != 0) { lineArea.addTrait(Trait.START_INDENT, new Integer(lbp.startIndent)); } @@ -1609,6 +1612,8 @@ } LineArea lineArea = new LineArea(); + lineArea.setChangeBars(getChangeBars()); + setCurrentArea(lineArea); LayoutContext lc = new LayoutContext(0); lc.setAlignmentContext(alignmentContext); --- src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java (working copy) @@ -75,6 +75,8 @@ private TextArea getCharacterInlineArea(Character node) { TextArea text = new TextArea(); + text.setChangeBars(getChangeBars()); + char ch = node.getCharacter(); if (CharUtilities.isAnySpace(ch)) { // add space unless it's zero-width: --- src/java/org/apache/fop/layoutmgr/inline/LeaderLayoutManager.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/inline/LeaderLayoutManager.java (working copy) @@ -201,6 +201,9 @@ leaderArea.setBPD(fobj.getRuleThickness().getValue(this)); } } + + leaderArea.setChangeBars(getChangeBars()); + TraitSetter.setProducerID(leaderArea, fobj.getId()); return leaderArea; } @@ -233,6 +236,7 @@ posIter.next(); } } + } /** {@inheritDoc} */ --- src/java/org/apache/fop/layoutmgr/inline/InlineStackingLayoutManager.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/inline/InlineStackingLayoutManager.java (working copy) @@ -198,6 +198,7 @@ if (iAdjust != 0) { //getLogger().debug("Add leading space: " + iAdjust); Space ls = new Space(); + ls.setChangeBars(getChangeBars()); ls.setIPD(iAdjust); parentArea.addChildArea(ls); } --- src/java/org/apache/fop/layoutmgr/inline/AbstractPageNumberCitationLayoutManager.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/inline/AbstractPageNumberCitationLayoutManager.java (working copy) @@ -96,6 +96,7 @@ if (!resolved) { getPSLM().addUnresolvedArea(fobj.getRefId(), (Resolvable) curArea); } + } /** @@ -112,6 +113,8 @@ String str = page.getPageNumberString(); // get page string from parent, build area text = new TextArea(); + text.setChangeBars(getChangeBars()); + int width = getStringWidth(str); text.addWord(str, 0); text.setIPD(width); @@ -119,6 +122,8 @@ } else { resolved = false; text = new UnresolvedPageNumber(fobj.getRefId(), font); + text.setChangeBars(getChangeBars()); + String str = "MMM"; // reserve three spaces for page number int width = getStringWidth(str); text.setIPD(width); --- src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java (working copy) @@ -297,6 +297,7 @@ addAreaInfoAreas(lastAreaInfo, wordSpaceCount, letterSpaceCount, firstAreaInfoIndex, lastAreaInfoIndex, realWidth, context); } + } private void addAreaInfoAreas(AreaInfo areaInfo, int wordSpaceCount, int letterSpaceCount, @@ -367,7 +368,8 @@ TextArea textArea = new TextAreaBuilder(realWidth, totalAdjust, context, firstAreaInfoIndex, lastAreaInfoIndex, context.isLastArea(), areaInfo.font).build(); - + textArea.setChangeBars(getChangeBars()); + // wordSpaceDim is computed in relation to wordSpaceIPD.opt // but the renderer needs to know the adjustment in relation // to the size of the space character in the current font; @@ -459,6 +461,8 @@ textArea = new TextArea(width.getStretch(), width.getShrink(), adjust); } + + textArea.setChangeBars(getChangeBars()); } private void setInlineProgressionDimension() { --- src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLastLayoutManager.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLastLayoutManager.java (working copy) @@ -75,6 +75,7 @@ resolved = true; } + text.setChangeBars(getChangeBars()); updateTextAreaTraits(text); return text; --- src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java (working copy) @@ -127,6 +127,8 @@ int sp = TraitSetter.getEffectiveSpace(adjust, minoptmax); if (sp != 0) { Block spacer = new Block(); + spacer.setChangeBars(getChangeBars()); + spacer.setBPD(sp); parentLayoutManager.addChildArea(spacer); } --- src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java (working copy) @@ -405,10 +405,14 @@ if (usedBPD < cellBPD) { if (getTableCell().getDisplayAlign() == EN_CENTER) { Block space = new Block(); + space.setChangeBars(getChangeBars()); + space.setBPD((cellBPD - usedBPD) / 2); curBlockArea.addBlock(space); } else if (getTableCell().getDisplayAlign() == EN_AFTER) { Block space = new Block(); + space.setChangeBars(getChangeBars()); + space.setBPD(cellBPD - usedBPD); curBlockArea.addBlock(space); } @@ -463,6 +467,8 @@ boolean outer) { if (blocks[i][j] == null) { blocks[i][j] = new Block(); + blocks[i][j].setChangeBars(getChangeBars()); + blocks[i][j].addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE); blocks[i][j].setPositioning(Block.ABSOLUTE); } @@ -493,6 +499,8 @@ int paddingEnd = padding.getPaddingEnd(false, this); Block block = new Block(); + block.setChangeBars(getChangeBars()); + TraitSetter.setProducerID(block, getTable().getId()); block.setPositioning(Block.ABSOLUTE); block.setIPD(cellIPD + paddingStart + paddingEnd); @@ -518,6 +526,8 @@ public Area getParentArea(Area childArea) { if (curBlockArea == null) { curBlockArea = new Block(); + curBlockArea.setChangeBars(getChangeBars()); + curBlockArea.addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE); TraitSetter.setProducerID(curBlockArea, getTableCell().getId()); curBlockArea.setPositioning(Block.ABSOLUTE); --- src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java (working copy) @@ -402,6 +402,8 @@ public Area getParentArea(Area childArea) { if (curBlockArea == null) { curBlockArea = new Block(); + curBlockArea.setChangeBars(getChangeBars()); + // Set up dimensions // Must get dimensions from parent area /*Area parentArea =*/ parentLayoutManager.getParentArea(curBlockArea); --- src/java/org/apache/fop/layoutmgr/table/TableAndCaptionLayoutManager.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/table/TableAndCaptionLayoutManager.java (working copy) @@ -179,6 +179,8 @@ public Area getParentArea(Area childArea) { if (curBlockArea == null) { curBlockArea = new Block(); + curBlockArea.setChangeBars(getChangeBars()); + // Set up dimensions // Must get dimensions from parent area Area parentArea = parentLayoutManager.getParentArea(curBlockArea); --- src/java/org/apache/fop/layoutmgr/table/RowPainter.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/table/RowPainter.java (working copy) @@ -465,6 +465,8 @@ //generate the block area Block block = new Block(); + block.setChangeBars(tclm.getTableLM().getFObj().getChangeBars()); + block.setPositioning(Block.ABSOLUTE); block.addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE); block.setIPD(ipd); --- src/java/org/apache/fop/layoutmgr/table/TableCaptionLayoutManager.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/table/TableCaptionLayoutManager.java (working copy) @@ -175,6 +175,8 @@ public Area getParentArea(Area childArea) { if (curBlockArea == null) { curBlockArea = new Block(); + curBlockArea.setChangeBars(getChangeBars()); + // Set up dimensions // Must get dimensions from parent area Area parentArea = parentLayoutManager.getParentArea(curBlockArea); --- src/java/org/apache/fop/layoutmgr/PageBreaker.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/PageBreaker.java (working copy) @@ -470,6 +470,7 @@ parentArea.setTop(topOffset); parentArea.setSeparator(separatorArea); } + pslm.getCurrentPV().getCurrentSpan().notifyFlowsFinished(); } --- src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java (working copy) @@ -1184,6 +1184,8 @@ boolean allowBPDUpdate = autoHeight && !switchedProgressionDirection; viewportBlockArea = new BlockViewport(allowBPDUpdate); + viewportBlockArea.setChangeBars(getChangeBars()); + viewportBlockArea.addTrait(Trait.IS_VIEWPORT_AREA, Boolean.TRUE); viewportBlockArea.setIPD(getContentAreaIPD()); @@ -1229,6 +1231,8 @@ } referenceArea = new Block(); + referenceArea.setChangeBars(getChangeBars()); + referenceArea.addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE); TraitSetter.setProducerID(referenceArea, getBlockContainerFO().getId()); --- src/java/org/apache/fop/layoutmgr/AbstractBaseLayoutManager.java (revision 919765) +++ src/java/org/apache/fop/layoutmgr/AbstractBaseLayoutManager.java (working copy) @@ -21,6 +21,7 @@ import java.util.List; import java.util.Stack; +import java.util.Vector; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -257,6 +258,19 @@ return fobj; } + /** + * Obtain vector of change bars affecting object in this layout. + * @return Vector of all change bars affecting this or null + */ + public Vector/**/ getChangeBars() { + if (null == fobj) { + return null; + } else { + return fobj.getChangeBars(); + } + } + + /** {@inheritDoc} */ public void reset() { throw new UnsupportedOperationException("Not implemented"); --- src/java/org/apache/fop/apps/FOUserAgent.java (revision 919765) +++ src/java/org/apache/fop/apps/FOUserAgent.java (working copy) @@ -24,6 +24,7 @@ import java.net.MalformedURLException; import java.util.Date; import java.util.Map; +import java.util.Vector; import javax.xml.transform.Source; import javax.xml.transform.TransformerException; @@ -46,6 +47,7 @@ import org.apache.fop.events.FOPEventListenerProxy; import org.apache.fop.events.LoggingEventListener; import org.apache.fop.fo.FOEventHandler; +import org.apache.fop.fo.flow.ChangeBar; import org.apache.fop.fonts.FontManager; import org.apache.fop.render.Renderer; import org.apache.fop.render.RendererFactory; @@ -81,7 +83,13 @@ private static Log log = LogFactory.getLog("FOP"); private FopFactory factory; + + /** + * The change bars encountered + */ + private static Vector stackedChangeBars = new Vector(); + /** * The base URL for all URL resolutions, especially for * external-graphics. @@ -692,5 +700,52 @@ public StructureTree getStructureTree() { return this.structureTree; } + + /** + * Add another change bar to the stack of active change bars + * @param bar The change bar top add + */ + public void pushChangeBar(ChangeBar bar) { + stackedChangeBars.addElement(bar); + } + + + /** + * Remove top level change bar from stack + */ + public void popChangeBar() { + stackedChangeBars.removeElementAt(stackedChangeBars.size() - 1); + } + + /** + * Return the nearest change bar in effect, i.e. the youngest one + * + * @return youngest change bar in effect or null + */ + public ChangeBar topChangeBar() { + if (stackedChangeBars.isEmpty()) { + return null; + } + else { + return (ChangeBar)stackedChangeBars.lastElement(); + } + } + + /** + * Return the list of change bars in effect currently + * @return The vector of change bars in effect currently + */ + public Vector getChangeBars() { + return stackedChangeBars; + } + + + /** + * Copy the change bars in affect currently + * @return A copy of the change bars in effect currently + */ + public Vector copyChangeBars() { + return (Vector)(stackedChangeBars.clone()); + } } --- src/java/org/apache/fop/events/EventFormatter.xml (revision 919765) +++ src/java/org/apache/fop/events/EventFormatter.xml (working copy) @@ -58,6 +58,9 @@ First element must be the fo:root formatting object. Found {elementName} instead. Please make sure you're producing a valid XSL-FO document. Document is empty (something might be wrong with your XSLT stylesheet). Unknown formatting object "{offendingNode}" encountered (a child of {elementName}}.{{locator}} + End class "{endName}" of {elementName} does not match latest starting class {beginName}.{{locator}} + An {elementName} without an fo:change-bar-begin found.{{locator}} + Element {elementName} not descendant of fo:flow or fo:static-content.{{locator}} Only a value of "auto" for block-progression-dimension has a well-specified behavior on fo:table. Falling back to "auto".{{locator}} In collapsing border model a table does not have padding (see http://www.w3.org/TR/REC-CSS2/tables.html#collapsing-borders), but a non-zero value for padding was found. The padding will be ignored.{{locator}} Either fo:table-rows or fo:table-cells may be children of an {elementName} but not both.{{locator}} --- src/java/org/apache/fop/fo/FOText.java (revision 919765) +++ src/java/org/apache/fop/fo/FOText.java (working copy) @@ -28,6 +28,7 @@ import org.apache.fop.apps.FOPException; import org.apache.fop.datatypes.Length; import org.apache.fop.fo.flow.Block; +import org.apache.fop.fo.flow.ChangeBar; import org.apache.fop.fo.properties.CommonFont; import org.apache.fop.fo.properties.CommonHyphenation; import org.apache.fop.fo.properties.CommonTextDecoration; @@ -90,6 +91,11 @@ */ public FOText(FONode parent) { super(parent); + // check if we are under the influence of change bars + if (null != getUserAgent().topChangeBar()) { + // OK, so copy over the stack of change bars + affectedByChangeBars = getUserAgent().copyChangeBars(); + } } /** {@inheritDoc} */ --- src/java/org/apache/fop/fo/FONode.java (revision 919765) +++ src/java/org/apache/fop/fo/FONode.java (working copy) @@ -22,6 +22,7 @@ // Java import java.util.ListIterator; import java.util.Map; +import java.util.Vector; import org.xml.sax.Attributes; import org.xml.sax.Locator; @@ -59,6 +60,9 @@ /** pointer to the sibling nodes */ protected FONode[] siblings; + /** list of change bars affecting the FObj */ + protected Vector affectedByChangeBars = null; + /** * Marks the location of this object from the input FO *
Call locator.getSystemId(), @@ -170,6 +174,18 @@ } /** + * Convenience function to check if this element is a change bar element + * @param namespaceURI The name space of the element + * @param localName The local name of the element + * @return true if a member, false if not + */ + public boolean isChangeBarElement(String namespaceURI, String localName) { + return FO_URI.equals(namespaceURI) && + ( "change-bar-begin".equals(localName) || + "change-bar-end".equals(localName) ); + } + + /** * Returns the user agent that is associated with the * tree's FOEventHandler. * @@ -244,6 +260,9 @@ //nop } + + + /** * Static version of {@link FONode#validateChildNode(Locator, String, String)} that * can be used by subclasses that need to validate children against a different node @@ -252,8 +271,8 @@ * * @param fo the {@link FONode} to validate against * @param loc location in the source file - * @param namespaceURI namespace of the incoming node - * @param localName name of the incoming node (without namespace prefix) + * @param namespaceURI name space of the incoming node + * @param localName name of the incoming node (without name space prefix) * @throws ValidationException if the incoming node is not a valid child for the given FO */ protected static void validateChildNode( @@ -861,6 +880,8 @@ followingSibling.siblings[0] = precedingSibling; } + + /** * Base iterator interface over a FO's children */ --- src/java/org/apache/fop/fo/FObj.java (revision 919765) +++ src/java/org/apache/fop/fo/FObj.java (working copy) @@ -26,6 +26,7 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; +import java.util.Vector; import org.xml.sax.Attributes; import org.xml.sax.Locator; @@ -36,6 +37,7 @@ import org.apache.fop.fo.extensions.ExtensionAttachment; import org.apache.fop.fo.flow.Marker; import org.apache.fop.fo.properties.PropertyMaker; +import org.apache.fop.fo.flow.ChangeBar; /** * Base class for representation of formatting objects and their processing. @@ -68,7 +70,8 @@ // The value of properties relevant for all fo objects private String id = null; - // End of property values + + /** * Create a new formatting object. @@ -118,9 +121,11 @@ setLocator(locator); pList.addAttributesToList(attlist); if (!inMarker() - || "marker".equals(elementName)) { + || "marker".equals(elementName) ) { pList.setWritingMode(); bind(pList); + } else if (elementName.startsWith("change-bar")) { + bind(pList); } } @@ -152,9 +157,24 @@ if (id != null) { checkId(id); } + } /** + * {@inheritDoc} + * @throws FOPException FOP Exception + */ + protected void endOfNode() throws FOPException { + // check if we are under the influence of change bars + if (null != getUserAgent().topChangeBar()) { + // OK, so copy over the stack of change bars + affectedByChangeBars = getUserAgent().copyChangeBars(); + } + + super.endOfNode(); + } + + /** * Setup the id for this formatting object. * Most formatting objects can have an id that can be referenced. * This methods checks that the id isn't already used by another FO @@ -417,7 +437,9 @@ } } - /** + + + /** * Convenience method for validity checking. Checks if the * incoming node is a member of the "%block;" parameter entity * as defined in Sect. 6.2 of the XSL 1.0 & 1.1 Recommendations @@ -610,6 +632,12 @@ return (super.toString() + "[@id=" + this.id + "]"); } + public Vector/**/getChangeBars() + { + return affectedByChangeBars; + } + + /** Basic {@link FONodeIterator} implementation */ public class FObjIterator implements FONodeIterator { --- src/java/org/apache/fop/fo/flow/ChangeBar.java (revision 0) +++ src/java/org/apache/fop/fo/flow/ChangeBar.java (revision 0) @@ -0,0 +1,195 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.fo.flow; + +import java.awt.Color; + +import org.xml.sax.Attributes; +import org.xml.sax.Locator; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.fo.FONode; +import org.apache.fop.fo.FObj; +import org.apache.fop.fo.PropertyList; +import org.apache.fop.fo.ValidationException; +import org.apache.fop.fo.properties.Property; +import org.apache.fop.datatypes.Length; + +/** Common change bar base class. Handles properties and local child validation */ +public abstract class ChangeBar extends FObj { + + + /** + * Create a new ChangeBar object + * @param parent The parent FObj + */ + public ChangeBar(FONode parent) { + super(parent); + } + + + /** + * The class of the change bar, must be provided + */ + protected String cbClass = null; + + /** + * The color of the change bar + */ + protected Color color = null; + + /** + * The offset of the bar from the column + */ + protected Length offset = null; + + /** + * The placement of the bar + */ + protected int placement = -1; + + /** + * The style of the bar + */ + protected int style = -1; + + /** + * The width of the bar + */ + protected Length width = null; + + + /** {@inheritDoc} */ + public void bind(PropertyList pList) throws FOPException { + super.bind(pList); + + Property classProperty = pList.get(PR_CHANGE_BAR_CLASS); + if (null == classProperty) { + cbClass = "inMarker"; + } + else { + cbClass = classProperty.getString(); + } + + + Property colorProperty = pList.get(PR_CHANGE_BAR_COLOR, true, false); + if (null == colorProperty) { + colorProperty = pList.get(PR_COLOR); + } + color = colorProperty.getColor(getUserAgent()); + offset = pList.get(PR_CHANGE_BAR_OFFSET).getLength(); + placement = pList.get(PR_CHANGE_BAR_PLACEMENT).getEnum(); + style = pList.get(PR_CHANGE_BAR_STYLE).getEnum(); + width = pList.get(PR_CHANGE_BAR_WIDTH).getLength(); + } + + + /** + * @return the class of the change bar + */ + public String getCBClass() { + return cbClass; + } + + /** {@inheritDoc} */ + protected void validateChildNode( + Locator loc, + String namespaceURI, + String localName) + throws ValidationException { + // no children allowed + invalidChildError(loc, namespaceURI, localName); + } + + /** {@inheritDoc} */ + public void processNode(String elementName, Locator locator, + Attributes attlist, PropertyList pList) throws FOPException { + super.processNode(elementName, locator, attlist, pList); + + if (cbClass == null || "".equals(cbClass)) { + missingPropertyError("change-bar-class"); + } + + if ( -1 == findAncestor(FO_FLOW) + && -1 == findAncestor(FO_STATIC_CONTENT) ) { + getFOValidationEventProducer().changeBarWrongAncestor(this, getName(), locator); + } + } + + + /** + * Push the current change bar on the stack + */ + protected void push() { + getUserAgent().pushChangeBar(this); + } + + /** + * Remove top level change bar from stack + */ + protected void pop() { + getUserAgent().popChangeBar(); + + } + + /** + * Retrieve youngest open change bar element + * + * @return null, if no change bar is open, otherwise the youngest change bar + */ + protected ChangeBar top() { + return getUserAgent().topChangeBar(); + } + + /** + * @return the color + */ + public Color getColor() { + return color; + } + + /** + * @return the offset + */ + public Length getOffset() { + return offset; + } + + /** + * @return the placement + */ + public int getPlacement() { + return placement; + } + + /** + * @return the style + */ + public int getStyle() { + return style; + } + + /** + * @return the width + */ + public Length getWidth() { + return width; + } +} + * --- src/java/org/apache/fop/fo/flow/ChangeBarEnd.java (revision 0) +++ src/java/org/apache/fop/fo/flow/ChangeBarEnd.java (revision 0) @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.fo.flow; + + +import org.xml.sax.Attributes; +import org.xml.sax.Locator; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.fo.FONode; +import org.apache.fop.fo.PropertyList; + + +/** + * End of a change bar element. Notes the end of the affected objects of a change bar. + * */ +public class ChangeBarEnd extends ChangeBar { + + /** + * Create a change bar end object + * @param parent the parent FObj + */ + public ChangeBarEnd(FONode parent) { + super(parent); + } + + /** {@inheritDoc} */ + public String getLocalName() { + return "change-bar-end"; + } + + + /** + * {@inheritDoc} + * @return {@link org.apache.fop.fo.Constants#FO_CHANGE_BAR_END} + */ + public int getNameId() { + return FO_CHANGE_BAR_END; + } + + /** {@inheritDoc} */ + public void processNode(String elementName, Locator locator, + Attributes attlist, PropertyList pList) throws FOPException { + super.processNode(elementName, locator, attlist, pList); + + // check if we have an element on the stack at all + ChangeBar topElement = top(); + + if (null == topElement) { + getFOValidationEventProducer().changeBarNoBegin(this, getName(), locator); + } else { + if (!topElement.cbClass.equals(cbClass)) { + getFOValidationEventProducer().changeBarWrongStacking(this, + getName(), topElement.cbClass, cbClass, locator); + } + pop(); + } + + + } + +} --- src/java/org/apache/fop/fo/flow/ChangeBarBegin.java (revision 0) +++ src/java/org/apache/fop/fo/flow/ChangeBarBegin.java (revision 0) @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.fo.flow; + + +import org.xml.sax.Attributes; +import org.xml.sax.Locator; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.fo.FONode; +import org.apache.fop.fo.PropertyList; + + + +/** + * Change bar begin element. Notes the beginning of change bar of a certain class. + * + */ +public class ChangeBarBegin extends ChangeBar { + + + /** + * Create a new change bar begin object + * @param parent The parent FObj + */ + public ChangeBarBegin(FONode parent) { + super(parent); + } + + /** {@inheritDoc} */ + public String getLocalName() { + return "change-bar-begin"; + } + + + /** + * {@inheritDoc} + * @return {@link org.apache.fop.fo.Constants#FO_CHANGE_BAR_BEGIN} + */ + public int getNameId() { + return FO_CHANGE_BAR_BEGIN; + } + + /** {@inheritDoc} */ + public void processNode(String elementName, Locator locator, + Attributes attlist, PropertyList pList) throws FOPException { + super.processNode(elementName, locator, attlist, pList); + push(); + } +} --- src/java/org/apache/fop/fo/flow/Marker.java (revision 919765) +++ src/java/org/apache/fop/fo/flow/Marker.java (working copy) @@ -90,8 +90,15 @@ savePropertyListMaker = builderContext.getPropertyListMaker(); builderContext.setPropertyListMaker(new PropertyListMaker() { public PropertyList make(FObj fobj, PropertyList parentPropertyList) { - PropertyList pList = new MarkerPropertyList(fobj, parentPropertyList); - descendantPropertyLists.put(fobj, pList); + PropertyList pList; + + if (fobj.getLocalName().startsWith("change-bar-")) { + pList = savePropertyListMaker.make(fobj, parentPropertyList); + } + else { + pList = new MarkerPropertyList(fobj, parentPropertyList); + descendantPropertyLists.put(fobj, pList); + } return pList; } }); --- src/java/org/apache/fop/fo/FOElementMapping.java (revision 919765) +++ src/java/org/apache/fop/fo/FOElementMapping.java (working copy) @@ -136,6 +136,10 @@ foObjs.put("marker", new MarkerMaker()); foObjs.put("retrieve-marker", new RetrieveMarkerMaker()); foObjs.put("retrieve-table-marker", new RetrieveTableMarkerMaker()); + + // change bars + foObjs.put("change-bar-begin", new ChangeBarBeginMaker()); + foObjs.put("change-bar-end", new ChangeBarEndMaker()); } } @@ -520,4 +524,17 @@ return new org.apache.fop.fo.flow.RetrieveTableMarker(parent); } } + + static class ChangeBarBeginMaker extends ElementMapping.Maker { + public FONode make(FONode parent) { + return new org.apache.fop.fo.flow.ChangeBarBegin(parent); + } + } + + static class ChangeBarEndMaker extends ElementMapping.Maker { + public FONode make(FONode parent) { + return new org.apache.fop.fo.flow.ChangeBarEnd(parent); + } + } + } --- src/java/org/apache/fop/fo/FOValidationEventProducer.java (revision 919765) +++ src/java/org/apache/fop/fo/FOValidationEventProducer.java (working copy) @@ -357,6 +357,47 @@ QName offendingNode, Locator loc); /** + * A class for change bars is not unique. + * @param source the event source + * @param elementName the name of the context node + * @param name the class name + * @param loc the location of the error or null + * @event.severity FATAL + */ + void changeBarClassNotUnique(Object source, String elementName, String name, + Locator loc); + + /** + * Change bars were not stacked correctly + * @param source the event source + * @param elementName the name of the context node + * @param beginName the class name of the beginning change bar + * @param endName the class name of the ending change bar + * @param loc the location of the error or null + * @event.severity FATAL + */ + void changeBarWrongStacking(Object source, String elementName, String beginName, + String endName, Locator loc); + + /** + * Change bar ended without a start of bar occurred + * @param source the event source + * @param elementName the name of the context node + * @param loc the location of the error or null + * @event.severity FATAL + */ + void changeBarNoBegin(Object source, String elementName, + Locator loc); + /** + * Change bar not descendant of fo:flow or fo:static-content + * @param source the event source + * @param elementName the name of the context node + * @param loc the location of the error or null + * @event.severity FATAL + */ + void changeBarWrongAncestor(Object source, String elementName, Locator loc); + + /** * Alternate text is missing for a graphic element. * * @param source the event source --- src/java/org/apache/fop/fo/FOPropertyMapping.java (revision 919765) +++ src/java/org/apache/fop/fo/FOPropertyMapping.java (working copy) @@ -313,6 +313,7 @@ gp.createTableProperties(); gp.createWritingModeProperties(); gp.createMiscProperties(); + gp.createChangeBarProperties(); // Hardcode the subproperties. addSubpropMakerName("length", CP_LENGTH); @@ -2500,6 +2501,60 @@ addPropertyMaker("writing-mode", m); } + private void createChangeBarProperties() { + PropertyMaker m; + + // change-bar-class + m = new StringProperty.Maker(PR_CHANGE_BAR_CLASS); + m.setInherited(false); + addPropertyMaker("change-bar-class", m); + + // change-bar-color + m = new ColorProperty.Maker(PR_CHANGE_BAR_COLOR); + m.useGeneric(genericColor); + m.setInherited(true); + // TODO determine default color by current color profile + addPropertyMaker("change-bar-color", m); + + // change-bar-offset + m = new LengthProperty.Maker(PR_CHANGE_BAR_OFFSET); + m.setInherited(true); + m.setDefault("6pt"); + addPropertyMaker("change-bar-offset", m); + + // change-bar-placement + m = new EnumProperty.Maker(PR_CHANGE_BAR_PLACEMENT); + m.setInherited(true); + m.setDefault("start"); + m.addEnum("start", getEnumProperty(EN_START, "START")); + m.addEnum("end", getEnumProperty(EN_END, "END")); + m.addEnum("left", getEnumProperty(EN_LEFT, "LEFT")); + m.addEnum("right", getEnumProperty(EN_RIGHT, "RIGHT")); + m.addEnum("inside", getEnumProperty(EN_INSIDE, "INSIDE")); + m.addEnum("outside", getEnumProperty(EN_OUTSIDE, "OUTSIDE")); + m.addEnum("alternate", getEnumProperty(EN_ALTERNATE, "ALTERNATE")); + addPropertyMaker("change-bar-placement", m); + + // change-bar-style + m = new EnumProperty.Maker(PR_CHANGE_BAR_STYLE); + m.useGeneric(genericBorderStyle); + m.setInherited(true); + m.setDefault("solid"); + addPropertyMaker("change-bar-style", m); + + // change-bar-width + m = new LengthProperty.Maker(PR_CHANGE_BAR_WIDTH); + m.setInherited(true); + m.setDefault("6pt"); + addPropertyMaker("change-bar-width", m); + + // change-bar-offset + m = new LengthProperty.Maker(PR_CHANGE_BAR_OFFSET); + m.setInherited(true); + m.setDefault("6pt"); + addPropertyMaker("change-bar-offset", m); + } + private void createMiscProperties() { PropertyMaker m; --- src/java/org/apache/fop/fo/FOTreeBuilder.java (revision 919765) +++ src/java/org/apache/fop/fo/FOTreeBuilder.java (working copy) @@ -264,7 +264,9 @@ } else { // check that incoming node is valid for currentFObj if (currentFObj.getNamespaceURI().equals(FOElementMapping.URI) || currentFObj.getNamespaceURI().equals(ExtensionElementMapping.URI)) { - currentFObj.validateChildNode(locator, namespaceURI, localName); + if (!currentFObj.isChangeBarElement(namespaceURI, localName)) { + currentFObj.validateChildNode(locator, namespaceURI, localName); + } } } --- src/java/org/apache/fop/area/BodyRegion.java (revision 919765) +++ src/java/org/apache/fop/area/BodyRegion.java (working copy) @@ -36,6 +36,7 @@ private int columnGap; private int columnCount; + /** * Constructor which can read traits directly * from an fo:region-body formatting object. @@ -43,7 +44,8 @@ * @param parent the parent region viewport */ public BodyRegion(RegionBody rb, RegionViewport parent) { - this(rb.getNameId(), rb.getRegionName(), parent, rb.getColumnCount(), rb.getColumnGap()); + this(rb.getNameId(), rb.getRegionName(), parent, rb.getColumnCount(), rb.getColumnGap(), + rb.getWritingMode(), rb.getReferenceOrientation()); } /** @@ -54,10 +56,13 @@ * @param parent the parent region viewport * @param columnCount the number of columns * @param columnGap the gap between columns + * @param wrMode writing Mode + * @param refOrient reference orientation */ public BodyRegion(int regionClass, String regionName, RegionViewport parent, - int columnCount, int columnGap) { - super(regionClass, regionName, parent); + int columnCount, int columnGap, int wrMode, int refOrient) { + super(regionClass, regionName, parent, wrMode, refOrient); + this.columnCount = columnCount; this.columnGap = columnGap; mainReference = new MainReference(this); @@ -143,7 +148,7 @@ */ public Object clone() { BodyRegion br = new BodyRegion(getRegionClass(), getRegionName(), regionViewport, - getColumnCount(), getColumnGap()); + getColumnCount(), getColumnGap(), getWritingMode(), getReferenceOrientation()); br.setCTM(getCTM()); br.setIPD(getIPD()); br.beforeFloat = beforeFloat; --- src/java/org/apache/fop/area/MainReference.java (revision 919765) +++ src/java/org/apache/fop/area/MainReference.java (working copy) @@ -125,5 +125,9 @@ return parent.getColumnGap(); } + /** @return parent area of area */ + public BodyRegion getParent() { + return parent; + } } --- src/java/org/apache/fop/area/AreaTreeParser.java (revision 919765) +++ src/java/org/apache/fop/area/AreaTreeParser.java (working copy) @@ -571,9 +571,11 @@ String regionName = attributes.getValue("name"); int columnCount = XMLUtil.getAttributeAsInt(attributes, "columnCount", 1); int columnGap = XMLUtil.getAttributeAsInt(attributes, "columnGap", 0); + int wrMode = XMLUtil.getAttributeAsInt(attributes, "writingMode", Constants.EN_LR_TB); + int refOrient = XMLUtil.getAttributeAsInt(attributes, "referenceOrientation", 0); RegionViewport rv = getCurrentRegionViewport(); body = new BodyRegion(Constants.FO_REGION_BODY, - regionName, rv, columnCount, columnGap); + regionName, rv, columnCount, columnGap, wrMode, refOrient); transferForeignObjects(attributes, body); body.setCTM(getAttributeAsCTM(attributes, "ctm")); setAreaAttributes(attributes, body); @@ -1019,7 +1021,8 @@ String regionName = attributes.getValue("name"); RegionViewport rv = getCurrentRegionViewport(); RegionReference reg = new RegionReference(side, - regionName, rv); + regionName, rv, XMLUtil.getAttributeAsInt(attributes, "writingMode", Constants.EN_LR_TB), + XMLUtil.getAttributeAsInt(attributes, "referenceOrientation", 0)); transferForeignObjects(attributes, reg); reg.setCTM(getAttributeAsCTM(attributes, "ctm")); setAreaAttributes(attributes, reg); --- src/java/org/apache/fop/area/inline/TextArea.java (revision 919765) +++ src/java/org/apache/fop/area/inline/TextArea.java (working copy) @@ -67,6 +67,8 @@ */ public void addWord(String word, int offset, int[] letterAdjust) { WordArea wordArea = new WordArea(word, offset, letterAdjust); + wordArea.setChangeBars(getChangeBars()); + addChildArea(wordArea); wordArea.setParentArea(this); } @@ -80,6 +82,8 @@ */ public void addSpace(char space, int offset, boolean adjustable) { SpaceArea spaceArea = new SpaceArea(space, offset, adjustable); + spaceArea.setChangeBars(getChangeBars()); + addChildArea(spaceArea); spaceArea.setParentArea(this); } --- src/java/org/apache/fop/area/RegionReference.java (revision 919765) +++ src/java/org/apache/fop/area/RegionReference.java (working copy) @@ -22,6 +22,8 @@ import java.util.ArrayList; import java.util.List; +import org.apache.fop.datatypes.Numeric; +import org.apache.fop.fo.Constants; import org.apache.fop.fo.pagination.Region; /** @@ -36,8 +38,9 @@ private int regionClass; private String regionName; private CTM ctm; + private int writingMode; + private int referenceOrientation; - // the list of block areas from the static flow private ArrayList blocks = new ArrayList(); @@ -51,7 +54,8 @@ * @param parent the viewport for this region. */ public RegionReference(Region regionFO, RegionViewport parent) { - this(regionFO.getNameId(), regionFO.getRegionName(), parent); + this(regionFO.getNameId(), regionFO.getRegionName(), parent, + Constants.EN_LR_TB, 0); } /** @@ -60,10 +64,16 @@ * @param regionClass the region class (as returned by Region.getNameId()) * @param regionName the name of the region (as returned by Region.getRegionName()) * @param parent the viewport for this region. + * @param wrMode writing mode + * @param refOrient reference orientation */ - public RegionReference(int regionClass, String regionName, RegionViewport parent) { + public RegionReference(int regionClass, String regionName, RegionViewport parent, + int wrMode, int refOrient) { this.regionClass = regionClass; this.regionName = regionName; + this.writingMode = wrMode; + this.referenceOrientation = refOrient; + addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE); regionViewport = parent; } @@ -141,7 +151,8 @@ * @return a copy of this region reference area */ public Object clone() { - RegionReference rr = new RegionReference(regionClass, regionName, regionViewport); + RegionReference rr = new RegionReference(regionClass, regionName, + regionViewport, writingMode, referenceOrientation); rr.ctm = ctm; rr.setIPD(getIPD()); rr.blocks = (ArrayList)blocks.clone(); @@ -157,4 +168,16 @@ sb.append("}"); return sb.toString(); } + + + /** @return writing mode of region reference area */ + public int getWritingMode() { + return writingMode; + } + + /** @return reference orientation of region reference area */ + public int getReferenceOrientation() { + return referenceOrientation; + } + } --- src/java/org/apache/fop/area/Area.java (revision 919765) +++ src/java/org/apache/fop/area/Area.java (working copy) @@ -21,6 +21,7 @@ import java.io.Serializable; import java.util.Map; +import java.util.Vector; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -136,8 +137,28 @@ */ protected static Log log = LogFactory.getLog(Area.class); - /** + * The vector of change bars this area is affected by + */ + private Vector/**/ changeBars = null; + + /** + * Return the vector of change bars this area is affected by + * @return Vector of change bars or null + */ + public Vector/**/ getChangeBars() { + return changeBars; + } + + /** + * Set set of change bars affecting this area + * @param cbs The vector of change bars affecting the area + */ + public void setChangeBars(Vector/**/ cbs) { + changeBars = cbs; + } + + /** * Get the area class of this area. * * @return the area class