--- src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java (revision 1102396) +++ src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java (working copy) @@ -617,13 +617,16 @@ // save position and offset int saveIP = currentIPPosition; int saveBP = currentBPPosition; - + int saveBO = getBeginOffset(); + //Establish a new coordinate system AffineTransform at = new AffineTransform(); at.translate(currentIPPosition, currentBPPosition); at.translate(block.getXOffset(), block.getYOffset()); at.translate(0, block.getSpaceBefore()); + setBeginOffset(saveBO - block.getXOffset()); + if (!at.isIdentity()) { establishTransformationMatrix(at); } @@ -641,6 +644,8 @@ restoreGraphicsState(); } + setBeginOffset(saveBO); + // stacked and relative blocks effect stacking currentIPPosition = saveIP; currentBPPosition = saveBP; --- src/java/org/apache/fop/render/AbstractRenderer.java (revision 1102396) +++ 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.InlineViewport; import org.apache.fop.area.inline.WordArea; 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,51 @@ */ 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 IP begin offset of coordinate 0 + */ + private int beginOffset = 0; + /** the currently active PageViewport */ protected PageViewport currentPageViewport; @@ -405,10 +453,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(); @@ -557,6 +655,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) { @@ -618,6 +729,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) { @@ -673,6 +791,19 @@ * @param text the text to render */ protected void renderText(TextArea text) { + Vector changeBars = text.getChangeBars(); + + if (null != changeBars && !changeBars.isEmpty()) { + // this block has change bars attached to it + int saveIP = currentIPPosition; + int saveBP = currentBPPosition; + + drawChangeBars(text, changeBars); + + currentIPPosition = saveIP; + currentBPPosition = saveBP; + } + int saveIP = currentIPPosition; int saveBP = currentBPPosition; Iterator iter = text.getChildAreas().iterator(); @@ -760,6 +891,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. } @@ -786,6 +923,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. } @@ -858,4 +1002,141 @@ 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: + break; + } + + xOffset += getBeginOffset(); + + // 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; + + } + } + + /** + * return the begin offset of the inline begin (changes by reference area transforms) + * @return the offset from current coordinate system 0 that the IP begin is at + */ + protected int getBeginOffset() { + return beginOffset; + } + + /** + * Set the begin offset for inline progression begin (changes by reference area tranforms) + * @param offset the new offset from IPP 0 that true IP start is at + */ + protected void setBeginOffset(int offset) { + beginOffset = offset; + } + } --- src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java (revision 1102396) +++ 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; @@ -140,6 +142,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/inline/ContentLayoutManager.java (revision 1102396) +++ src/java/org/apache/fop/layoutmgr/inline/ContentLayoutManager.java (working copy) @@ -86,6 +86,7 @@ // get breaks then add areas to title this.parentLM = pslm; holder = new LineArea(); + holder.setChangeBars(getChangeBars()); // setUserAgent(foTitle.getUserAgent()); --- src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java (revision 1102396) +++ src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java (working copy) @@ -205,9 +205,11 @@ InlineArea area; if (isInline) { area = createInlineParent(); + area.setChangeBars(getChangeBars()); area.setOffset(0); } else { area = new InlineBlockParent(); + area.setChangeBars(getChangeBars()); } if (fobj instanceof Inline) { TraitSetter.setProducerID(area, getInlineFO().getId()); --- src/java/org/apache/fop/layoutmgr/inline/ExternalGraphicLayoutManager.java (revision 1102396) +++ 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/PageNumberCitationLayoutManager.java (revision 1102396) +++ src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLayoutManager.java (working copy) @@ -69,6 +69,8 @@ int width = getStringWidth(str); text.setIPD(width); } + + text.setChangeBars(getChangeBars()); updateTextAreaTraits(text); return text; --- src/java/org/apache/fop/layoutmgr/inline/WrapperLayoutManager.java (revision 1102396) +++ src/java/org/apache/fop/layoutmgr/inline/WrapperLayoutManager.java (working copy) @@ -68,10 +68,12 @@ 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); } } --- src/java/org/apache/fop/layoutmgr/inline/InstreamForeignObjectLM.java (revision 1102396) +++ 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/TextLayoutManager.java (revision 1102396) +++ src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java (working copy) @@ -23,6 +23,7 @@ import java.util.LinkedList; import java.util.List; import java.util.ListIterator; +import java.util.Vector; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -363,7 +364,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; @@ -455,6 +457,8 @@ textArea = new TextArea(width.getStretch(), width.getShrink(), adjust); } + + textArea.setChangeBars(getChangeBars()); } private void setInlineProgressionDimension() { @@ -1341,4 +1345,13 @@ } + @Override + public Vector/**/ getChangeBars() { + if (null == foText) { + return null; + } + else { + return foText.getChangeBars(); + } + } } --- src/java/org/apache/fop/layoutmgr/inline/PageNumberLayoutManager.java (revision 1102396) +++ 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 1102396) +++ src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java (working copy) @@ -1426,6 +1426,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, lbp.startIndent); } @@ -1534,6 +1536,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 1102396) +++ src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java (working copy) @@ -76,6 +76,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 1102396) +++ 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; } --- src/java/org/apache/fop/layoutmgr/inline/InlineStackingLayoutManager.java (revision 1102396) +++ src/java/org/apache/fop/layoutmgr/inline/InlineStackingLayoutManager.java (working copy) @@ -179,6 +179,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 1102396) +++ src/java/org/apache/fop/layoutmgr/inline/AbstractPageNumberCitationLayoutManager.java (working copy) @@ -110,6 +110,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); @@ -117,6 +119,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/PageNumberCitationLastLayoutManager.java (revision 1102396) +++ 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/BlockContainerLayoutManager.java (revision 1102396) +++ src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java (working copy) @@ -836,6 +836,8 @@ boolean allowBPDUpdate = autoHeight && !switchedProgressionDirection; viewportBlockArea = new BlockViewport(allowBPDUpdate); + viewportBlockArea.setChangeBars(getChangeBars()); + viewportBlockArea.addTrait(Trait.IS_VIEWPORT_AREA, Boolean.TRUE); viewportBlockArea.setIPD(getContentAreaIPD()); @@ -871,6 +873,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/ExternalDocumentLayoutManager.java (revision 1102396) +++ src/java/org/apache/fop/layoutmgr/ExternalDocumentLayoutManager.java (working copy) @@ -177,6 +177,8 @@ Dimension imageSize = this.imageLayout.getViewportSize(); Block blockArea = new Block(); + blockArea.setChangeBars(getChangeBars()); + blockArea.setIPD(imageSize.width); LineArea lineArea = new LineArea(); @@ -245,7 +247,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 1102396) +++ src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java (working copy) @@ -357,6 +357,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/list/ListBlockLayoutManager.java (revision 1102396) +++ src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java (working copy) @@ -218,6 +218,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 1102396) +++ src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java (working copy) @@ -586,6 +586,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 1102396) +++ src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java (working copy) @@ -173,6 +173,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/table/TableLayoutManager.java (revision 1102396) +++ src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java (working copy) @@ -420,6 +420,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/TableCellLayoutManager.java (revision 1102396) +++ src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java (working copy) @@ -398,10 +398,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); } @@ -456,6 +460,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); } @@ -486,6 +492,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); @@ -511,6 +519,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/TableAndCaptionLayoutManager.java (revision 1102396) +++ 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 1102396) +++ 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 1102396) +++ 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/BlockStackingLayoutManager.java (revision 1102396) +++ src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java (working copy) @@ -124,6 +124,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/AbstractBaseLayoutManager.java (revision 1102396) +++ 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,21 @@ 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 1102396) +++ src/java/org/apache/fop/apps/FOUserAgent.java (working copy) @@ -24,6 +24,8 @@ import java.net.MalformedURLException; import java.util.Date; import java.util.Map; +import java.util.TreeMap; +import java.util.Vector; import javax.xml.transform.Source; import javax.xml.transform.TransformerException; @@ -47,6 +49,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; @@ -83,7 +86,14 @@ private FopFactory factory; + /** + * The change bars encountered + */ + private static Vector stackedChangeBars = new Vector(); + + + /** * The base URL for all URL resolutions, especially for * external-graphics. */ @@ -693,5 +703,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 top-most changebar from stack of nested change bars + * + * @return change bar that is the top most changebar 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/fo/FOText.java (revision 1102396) +++ 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 1102396) +++ 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,12 @@ /** pointer to the sibling nodes */ protected FONode[] siblings; + /** change bars affecting this */ + protected Vector affectedByChangeBars = null; + + /** change bars at start of element */ + protected Vector affectedByChangeBarsStart = null; + /** * Marks the location of this object from the input FO *
Call locator.getSystemId(), @@ -170,6 +177,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. * @@ -912,4 +931,14 @@ } + /** + * Return the change bars that affect this element + * + * @return vector of change bars elements affecting this element + */ + public Vector/**/getChangeBars() { + return affectedByChangeBars; + } + + } --- src/java/org/apache/fop/fo/FObj.java (revision 1102396) +++ 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. @@ -153,9 +155,50 @@ if (id != null) { checkId(id); } + // check if we are under the influence of change bars + if (null != getUserAgent().topChangeBar()) { + // OK, so copy over the stack of change bars + affectedByChangeBarsStart = getUserAgent().copyChangeBars(); + } } /** + * {@inheritDoc} + * @throws FOPException FOP Exception + */ + protected void endOfNode() throws FOPException { + // now take all change bars that are active now and were active at the start + // of node and put them into the affectedByChangeBars + Vector nowChangeBars = getUserAgent().copyChangeBars(); + + + if (null != affectedByChangeBarsStart && null != nowChangeBars) { + // to save memory, we first try to match all elements to the start + if (affectedByChangeBarsStart.containsAll(nowChangeBars) + && nowChangeBars.containsAll(affectedByChangeBarsStart)) { + affectedByChangeBars = affectedByChangeBarsStart; + } + else { + affectedByChangeBars = new Vector(); + + for (int idx = 0; idx < nowChangeBars.size(); idx++) { + if (affectedByChangeBarsStart.contains(nowChangeBars.get(idx))) { + affectedByChangeBars.add(nowChangeBars.get(idx)); + } + } + + if (0 == affectedByChangeBars.size()) { + affectedByChangeBars = null; + } + } + + affectedByChangeBarsStart = null; + } + + 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 --- 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,196 @@ +/* + * 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 java.util.Collections; +import java.util.Map; +import java.util.Vector; +import java.util.TreeMap; + +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.FOTreeBuilderContext; +import org.apache.fop.fo.FObj; +import org.apache.fop.fo.FObjMixed; +import org.apache.fop.fo.PropertyList; +import org.apache.fop.fo.PropertyListMaker; +import org.apache.fop.fo.ValidationException; +import org.apache.fop.fo.properties.Property; +import org.apache.fop.fo.properties.PropertyCache; +import org.apache.fop.datatypes.Length; + +/** Common change bar base class. Handles properties and local child validation */ +public abstract class ChangeBar extends FObj { + + + /** + * Construct a ChangeBar element, common parts for start and end + * + * @param parent the parent element, containing the change bars start/end + */ + 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); + + cbClass = pList.get(PR_CHANGE_BAR_CLASS).getString(); + color = pList.get(PR_CHANGE_BAR_COLOR).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. + * @return the class of the change bar as a string + */ + 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(); + + } + + /** + * Return top-most change bar from the stack of nested change bars. + * + * @return the topmost changebar or null + */ + 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,87 @@ +/* + * 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.util.Collections; +import java.util.Map; + +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.FOTreeBuilderContext; +import org.apache.fop.fo.FObj; +import org.apache.fop.fo.FObjMixed; +import org.apache.fop.fo.PropertyList; +import org.apache.fop.fo.PropertyListMaker; +import org.apache.fop.fo.ValidationException; +import org.apache.fop.fo.properties.Property; +import org.apache.fop.fo.properties.PropertyCache; + +/** + * End of a change bar element. Notes the end of the affected objects of a change bar. + * */ +public class ChangeBarEnd extends ChangeBar { + + /** + * Construct a new ChangeBarEnd element + * @param parent the parent of the element + */ + 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,77 @@ +/* + * 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.util.Collections; +import java.util.Map; + +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.FOTreeBuilderContext; +import org.apache.fop.fo.FObj; +import org.apache.fop.fo.FObjMixed; +import org.apache.fop.fo.PropertyList; +import org.apache.fop.fo.PropertyListMaker; +import org.apache.fop.fo.ValidationException; +import org.apache.fop.fo.properties.Property; +import org.apache.fop.fo.properties.PropertyCache; + +/** + * Change bar begin element. Notes the beginning of change bar of a certain class. + * + */ +public class ChangeBarBegin extends ChangeBar { + + + /** + * Construct a new ChangeBarEnd element + * + * @param parent the parent element of the new change bar end element + */ + 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/FOElementMapping.java (revision 1102396) +++ 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/FOPropertyMapping.java (revision 1102396) +++ src/java/org/apache/fop/fo/FOPropertyMapping.java (working copy) @@ -318,6 +318,7 @@ gp.createTableProperties(); gp.createWritingModeProperties(); gp.createMiscProperties(); + gp.createChangeBarProperties(); // Hardcode the subproperties. addSubpropMakerName("length", CP_LENGTH); @@ -2518,6 +2519,62 @@ addPropertyMaker("writing-mode", m); } + private void createChangeBarProperties() { + PropertyMaker m; + + // change-bar-class + m = new StringProperty.Maker(PR_CHANGE_BAR_CLASS); + m.setInherited(false); + m.setDefault(""); + addPropertyMaker("change-bar-class", m); + + // change-bar-color + m = new ColorProperty.Maker(PR_CHANGE_BAR_COLOR); + + m.setInherited(true); + // TODO: fall back to "color" property + m.setDefault("black"); + 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/FOValidationEventProducer.java (revision 1102396) +++ 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/FOTreeBuilder.java (revision 1102396) +++ 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 1102396) +++ src/java/org/apache/fop/area/BodyRegion.java (working copy) @@ -46,7 +46,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()); } /** @@ -57,10 +58,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); @@ -146,7 +150,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 1102396) +++ src/java/org/apache/fop/area/MainReference.java (working copy) @@ -124,5 +124,9 @@ return parent.getColumnGap(); } + /** @return the parent region of this area */ + public BodyRegion getParent() { + return parent; + } } --- src/java/org/apache/fop/area/AreaTreeParser.java (revision 1102396) +++ src/java/org/apache/fop/area/AreaTreeParser.java (working copy) @@ -95,6 +95,7 @@ import static org.apache.fop.fo.Constants.FO_REGION_BODY; import static org.apache.fop.fo.Constants.FO_REGION_END; import static org.apache.fop.fo.Constants.FO_REGION_START; +import static org.apache.fop.fo.Constants.EN_LR_TB; /** * This is a parser for the area tree XML (intermediate format) which is used to reread an area @@ -582,8 +583,12 @@ 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", + EN_LR_TB); + int refOrient = XMLUtil.getAttributeAsInt(attributes, "referenceOrientation", 0); RegionViewport rv = getCurrentRegionViewport(); - body = new BodyRegion(FO_REGION_BODY, regionName, rv, columnCount, columnGap); + body = new BodyRegion(FO_REGION_BODY, + regionName, rv, columnCount, columnGap, wrMode, refOrient); transferForeignObjects(attributes, body); body.setCTM(getAttributeAsCTM(attributes, "ctm")); setAreaAttributes(attributes, body); @@ -1027,8 +1032,20 @@ private void pushNewRegionReference(Attributes attributes, int side) { String regionName = attributes.getValue("name"); RegionViewport rv = getCurrentRegionViewport(); + String wrMode = attributes.getValue("writingMode"); + String refOrient = attributes.getValue("referenceOrientation"); + + if (null == wrMode || wrMode.isEmpty()) { + wrMode = "0"; + } + + if (null == refOrient || refOrient.isEmpty()) { + refOrient = "0"; + } + RegionReference reg = new RegionReference(side, - regionName, rv); + regionName, rv, Integer.parseInt(wrMode), + Integer.parseInt(refOrient)); transferForeignObjects(attributes, reg); reg.setCTM(getAttributeAsCTM(attributes, "ctm")); setAreaAttributes(attributes, reg); --- src/java/org/apache/fop/area/inline/TextArea.java (revision 1102396) +++ src/java/org/apache/fop/area/inline/TextArea.java (working copy) @@ -69,6 +69,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); } @@ -82,6 +84,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 1102396) +++ src/java/org/apache/fop/area/RegionReference.java (working copy) @@ -23,6 +23,7 @@ import java.util.List; import org.apache.fop.fo.pagination.Region; +import org.apache.fop.fo.Constants; /** * This is a region reference area for a page regions. @@ -36,6 +37,8 @@ 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(); @@ -50,7 +53,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); } /** @@ -59,10 +63,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(); @@ -158,4 +169,16 @@ sb.append("}"); return sb.toString(); } + + + /** @return the writing mode of this region */ + public int getWritingMode() { + return writingMode; + } + + /** @return the reference orientation of this region */ + public int getReferenceOrientation() { + return referenceOrientation; + } + } --- src/java/org/apache/fop/area/Area.java (revision 1102396) +++ 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; @@ -141,6 +142,28 @@ /** + * The vector of change bars this arrea 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 the vector 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