]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
FOP-1760: Add change bar generation
authorSimon Steiner <ssteiner@apache.org>
Fri, 13 Jul 2018 10:29:57 +0000 (10:29 +0000)
committerSimon Steiner <ssteiner@apache.org>
Fri, 13 Jul 2018 10:29:57 +0000 (10:29 +0000)
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1835810 13f79535-47bb-0310-9956-ffa450edef68

55 files changed:
fop-core/src/main/java/org/apache/fop/area/Area.java
fop-core/src/main/java/org/apache/fop/area/AreaTreeParser.java
fop-core/src/main/java/org/apache/fop/area/Span.java
fop-core/src/main/java/org/apache/fop/area/inline/InlineBlock.java [new file with mode: 0644]
fop-core/src/main/java/org/apache/fop/area/inline/TextArea.java
fop-core/src/main/java/org/apache/fop/fo/FOElementMapping.java
fop-core/src/main/java/org/apache/fop/fo/FONode.java
fop-core/src/main/java/org/apache/fop/fo/FOPropertyMapping.java
fop-core/src/main/java/org/apache/fop/fo/FOText.java
fop-core/src/main/java/org/apache/fop/fo/FOTreeBuilder.java
fop-core/src/main/java/org/apache/fop/fo/FOValidationEventProducer.java
fop-core/src/main/java/org/apache/fop/fo/FObj.java
fop-core/src/main/java/org/apache/fop/fo/flow/ChangeBar.java [new file with mode: 0644]
fop-core/src/main/java/org/apache/fop/fo/flow/ChangeBarBegin.java [new file with mode: 0644]
fop-core/src/main/java/org/apache/fop/fo/flow/ChangeBarEnd.java [new file with mode: 0644]
fop-core/src/main/java/org/apache/fop/fo/flow/table/TableRow.java
fop-core/src/main/java/org/apache/fop/fo/pagination/PageSequence.java
fop-core/src/main/java/org/apache/fop/fo/pagination/Root.java
fop-core/src/main/java/org/apache/fop/layoutmgr/AbstractBaseLayoutManager.java
fop-core/src/main/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
fop-core/src/main/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
fop-core/src/main/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java
fop-core/src/main/java/org/apache/fop/layoutmgr/ExternalDocumentLayoutManager.java
fop-core/src/main/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java
fop-core/src/main/java/org/apache/fop/layoutmgr/inline/AbstractPageNumberCitationLayoutManager.java
fop-core/src/main/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java
fop-core/src/main/java/org/apache/fop/layoutmgr/inline/ContentLayoutManager.java
fop-core/src/main/java/org/apache/fop/layoutmgr/inline/ExternalGraphicLayoutManager.java
fop-core/src/main/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java
fop-core/src/main/java/org/apache/fop/layoutmgr/inline/InlineStackingLayoutManager.java
fop-core/src/main/java/org/apache/fop/layoutmgr/inline/InstreamForeignObjectLM.java
fop-core/src/main/java/org/apache/fop/layoutmgr/inline/LeaderLayoutManager.java
fop-core/src/main/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
fop-core/src/main/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
fop-core/src/main/java/org/apache/fop/layoutmgr/inline/WrapperLayoutManager.java
fop-core/src/main/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java
fop-core/src/main/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java
fop-core/src/main/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java
fop-core/src/main/java/org/apache/fop/layoutmgr/table/RowPainter.java
fop-core/src/main/java/org/apache/fop/layoutmgr/table/TableAndCaptionLayoutManager.java
fop-core/src/main/java/org/apache/fop/layoutmgr/table/TableCaptionLayoutManager.java
fop-core/src/main/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java
fop-core/src/main/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java
fop-core/src/main/java/org/apache/fop/render/AbstractPathOrientedRenderer.java
fop-core/src/main/java/org/apache/fop/render/AbstractRenderer.java
fop-core/src/main/java/org/apache/fop/render/xml/XMLRenderer.java
fop/src/documentation/intermediate-format-ng/fop-intermediate-format-ng-datatypes.xsd
fop/test/layoutengine/standard-testcases/change-bar_block.xml [new file with mode: 0644]
fop/test/layoutengine/standard-testcases/change-bar_inline.xml [new file with mode: 0644]
fop/test/layoutengine/standard-testcases/change-bar_list.xml [new file with mode: 0644]
fop/test/layoutengine/standard-testcases/change-bar_overlapped.xml [new file with mode: 0644]
fop/test/layoutengine/standard-testcases/change-bar_placement-rtl.xml [new file with mode: 0644]
fop/test/layoutengine/standard-testcases/change-bar_placement.xml [new file with mode: 0644]
fop/test/layoutengine/standard-testcases/change-bar_style.xml [new file with mode: 0644]
fop/test/layoutengine/standard-testcases/change-bar_table.xml [new file with mode: 0644]

index 895367c19398c9201eb1278427956f8e1abddf04..87f645dd289a490e63e72ee7475fe691c98db9c2 100644 (file)
 package org.apache.fop.area;
 
 import java.io.Serializable;
+import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
+import org.apache.fop.fo.flow.ChangeBar;
 import org.apache.fop.traits.BorderProps;
 import org.apache.fop.traits.WritingModeTraitsGetter;
 
@@ -128,6 +130,29 @@ public class Area extends AreaTreeObject implements Serializable {
      */
     protected static final Log log = LogFactory.getLog(Area.class);
 
+    /**
+     * The active change bar list
+     */
+    private List<ChangeBar> changeBarList;
+
+    /**
+     * Returns the active change bar list.
+     *
+     * @return The active change bar list
+     */
+    public List<ChangeBar> getChangeBarList() {
+        return changeBarList;
+    }
+
+    /**
+     * Sets the active change bar list.
+     *
+     * @param changeBarList The active change bar list
+     */
+    public void setChangeBarList(List<ChangeBar> changeBarList) {
+        this.changeBarList = changeBarList;
+    }
+
     /**
      * Get the area class of this area.
      *
index 41563a85e5b41ce7450c5b3906d375b1f42c824e..587e8e4494d2aba45ddccfbc2cf0fc691ac1195e 100644 (file)
@@ -66,6 +66,7 @@ import org.apache.fop.area.inline.Container;
 import org.apache.fop.area.inline.ForeignObject;
 import org.apache.fop.area.inline.Image;
 import org.apache.fop.area.inline.InlineArea;
+import org.apache.fop.area.inline.InlineBlock;
 import org.apache.fop.area.inline.InlineBlockParent;
 import org.apache.fop.area.inline.InlineParent;
 import org.apache.fop.area.inline.InlineViewport;
@@ -80,6 +81,7 @@ import org.apache.fop.fo.extensions.ExtensionAttachment;
 import org.apache.fop.fonts.Font;
 import org.apache.fop.fonts.FontInfo;
 import org.apache.fop.traits.BorderProps;
+import org.apache.fop.traits.Direction;
 import org.apache.fop.traits.Visibility;
 import org.apache.fop.util.ColorUtil;
 import org.apache.fop.util.ContentHandlerFactory;
@@ -190,6 +192,7 @@ public class AreaTreeParser {
             makers.put("block", new BlockMaker());
             makers.put("lineArea", new LineAreaMaker());
             makers.put("inline", new InlineMaker());
+            makers.put("inlineblock", new InlineBlockMaker());
             makers.put("inlineparent", new InlineParentMaker());
             makers.put("inlineblockparent", new InlineBlockParentMaker());
             makers.put("text", new TextMaker());
@@ -594,6 +597,17 @@ public class AreaTreeParser {
                 BodyRegion body = getCurrentBodyRegion();
                 Span span = new Span(columnCount,
                         body.getColumnGap(), ipd);
+
+                String blockDirection = attributes.getValue("block-progression-direction");
+                if (blockDirection != null) {
+                    span.addTrait(Trait.BLOCK_PROGRESSION_DIRECTION, Direction.valueOf(blockDirection));
+                }
+
+                String inlineDirection = attributes.getValue("inline-progression-direction");
+                if (inlineDirection != null) {
+                    span.addTrait(Trait.INLINE_PROGRESSION_DIRECTION, Direction.valueOf(inlineDirection));
+                }
+
                 transferForeignObjects(attributes, span);
                 setAreaAttributes(attributes, span);
                 body.getMainReference().getSpans().add(span);
@@ -723,6 +737,34 @@ public class AreaTreeParser {
             }
         }
 
+        private class InlineBlockMaker extends AbstractMaker {
+
+            public void startElement(Attributes attributes) {
+
+                Block block = new Block();
+
+                if (attributes.getValue("left-offset") != null) {
+                    block.setXOffset(XMLUtil.getAttributeAsInt(attributes, "left-offset", 0));
+                }
+                if (attributes.getValue("top-offset") != null) {
+                    block.setYOffset(XMLUtil.getAttributeAsInt(attributes, "top-offset", 0));
+                }
+                transferForeignObjects(attributes, block);
+                setAreaAttributes(attributes, block);
+                setTraits(attributes, block, SUBSET_COMMON);
+                setTraits(attributes, block, SUBSET_BOX);
+                setTraits(attributes, block, SUBSET_COLOR);
+                Area parent = (Area)areaStack.peek();
+                InlineBlock inlineBlock = new InlineBlock(block);
+                parent.addChildArea(inlineBlock);
+                areaStack.push(inlineBlock);
+            }
+
+            public void endElement() {
+                assertObjectOfClass(areaStack.pop(), InlineBlock.class);
+            }
+        }
+
         private class InlineParentMaker extends AbstractMaker {
 
             public void startElement(Attributes attributes) {
index 41610f355af49124bca9fe06933db6952b3115e6..9fa22c6fdd4b81fa424b7f7784cc16ae2bd2a835 100644 (file)
@@ -81,6 +81,15 @@ public class Span extends Area {
         return colCount;
     }
 
+    /**
+     * Get the column gap for this span area.
+     *
+     * @return the column gap for this span area
+     */
+    public int getColumnGap() {
+        return colGap;
+    }
+
     /**
      * Get the width of a single column within this Span
      *
@@ -206,6 +215,8 @@ public class Span extends Area {
             }
             break;
         }
+        addTrait(Trait.INLINE_PROGRESSION_DIRECTION, wmtg.getInlineProgressionDirection());
+        addTrait(Trait.BLOCK_PROGRESSION_DIRECTION, wmtg.getBlockProgressionDirection());
     }
 
     /** {@inheritDoc} */
diff --git a/fop-core/src/main/java/org/apache/fop/area/inline/InlineBlock.java b/fop-core/src/main/java/org/apache/fop/area/inline/InlineBlock.java
new file mode 100644 (file)
index 0000000..9b5f967
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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.area.inline;
+
+import org.apache.fop.area.Block;
+
+/**
+ * This is the inline block area class.
+ * It wraps the child block when it has to be placed into inline parent.
+ */
+public class InlineBlock extends InlineParent {
+
+    private static final long serialVersionUID = -3725062353292109517L;
+    private final Block block;
+
+    public InlineBlock(Block block) {
+        this.block = block;
+    }
+
+    /**
+     * @return the wrapped block
+     */
+    public Block getBlock() {
+        return block;
+    }
+}
index 3081a38eb4bca66bc9c1d0470de58de37b7b69b4..a03e536cef0ef6e42e015321b3f69bf7839e37e3 100644 (file)
@@ -95,6 +95,7 @@ public class TextArea extends AbstractTextArea {
         WordArea wordArea = new WordArea(
             blockProgressionOffset, minWordLevel, word, letterAdjust, levels, gposAdjustments);
         wordArea.setIPD(ipd);
+        wordArea.setChangeBarList(getChangeBarList());
         addChildArea(wordArea);
         wordArea.setParentArea(this);
         updateLevel(minWordLevel);
@@ -113,6 +114,7 @@ public class TextArea extends AbstractTextArea {
         char space, int ipd, boolean adjustable, int blockProgressionOffset, int level) {
         SpaceArea spaceArea = new SpaceArea(blockProgressionOffset, level, space, adjustable);
         spaceArea.setIPD(ipd);
+        spaceArea.setChangeBarList(getChangeBarList());
         addChildArea(spaceArea);
         spaceArea.setParentArea(this);
         updateLevel(level);
index b087e1d9c12c8345877ada8b360cd3c600916d30..8bf92c2b30f543d775f0aad49ed6587e29c508d0 100644 (file)
@@ -141,6 +141,10 @@ public class FOElementMapping extends ElementMapping {
             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());
         }
     }
 
@@ -527,4 +531,16 @@ public class FOElementMapping extends ElementMapping {
             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);
+        }
+    }
 }
index b4e0ec0fee5ef2897d235b8ac6a4c80116efbf9a..f3c582dd56603a53445837949761d0c934bfe11d 100644 (file)
@@ -20,6 +20,7 @@
 package org.apache.fop.fo;
 
 // Java
+import java.util.List;
 import java.util.ListIterator;
 import java.util.Map;
 import java.util.Stack;
@@ -42,6 +43,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.extensions.svg.SVGElementMapping;
+import org.apache.fop.fo.flow.ChangeBar;
 import org.apache.fop.fo.pagination.Root;
 import org.apache.fop.util.CharUtilities;
 import org.apache.fop.util.ContentHandlerFactory;
@@ -63,6 +65,12 @@ public abstract class FONode implements Cloneable {
     /** pointer to the sibling nodes */
     protected FONode[] siblings;
 
+    /** The list of active change bars for the given node */
+    protected List<ChangeBar> nodeChangeBarList;
+
+    /** The list of active change bars for the start of the given node  */
+    protected List<ChangeBar> startOfNodeChangeBarList;
+
     /**
      * Marks the location of this object from the input FO
      *   <br>Call <code>locator.getSystemId()</code>,
@@ -173,6 +181,18 @@ public abstract class FONode implements Cloneable {
         return getBuilderContext().inMarker();
     }
 
+    /**
+     * Tests if the given element is a change bar element.
+     *
+     * @param namespaceURI The name space of the element
+     * @param localName The local name of the element
+     * @return A boolean value true if the given element is a change bar element
+     */
+    public boolean isChangeBarElement(String namespaceURI, String localName) {
+        return FO_URI.equals(namespaceURI)
+                && (localName.equals("change-bar-begin") || localName.equals("change-bar-end"));
+    }
+
     /**
      * Returns the user agent that is associated with the
      * tree's <code>FOEventHandler</code>.
@@ -1082,6 +1102,15 @@ public abstract class FONode implements Cloneable {
 
     }
 
+    /**
+     * Returns the list of active change bars.
+     *
+     * @return The list of active change bars
+     */
+    public List<ChangeBar> getChangeBarList() {
+        return nodeChangeBarList;
+    }
+
     /**
      * Sets the structure tree element.
      *
index da92cc834c5bdee8a721a0aeabe2b3162dffd836..0b8da47cc19823e8baec4adde02516a9dd1989b3 100644 (file)
@@ -322,6 +322,7 @@ public final class FOPropertyMapping implements Constants {
         gp.createTableProperties();
         gp.createWritingModeProperties();
         gp.createMiscProperties();
+        gp.createChangeBarProperties();
 
         // Hardcode the subproperties.
         addSubpropMakerName("length", CP_LENGTH);
@@ -2588,6 +2589,56 @@ public final class FOPropertyMapping implements Constants {
         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-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;
 
index 563d9699390b0ffab52b1b5e436d2a3c6ff98052..207c3184ce9f5e6b428a3902fd6cd312c6d64e54 100644 (file)
@@ -33,6 +33,7 @@ import org.apache.fop.apps.FOPException;
 import org.apache.fop.complexscripts.bidi.DelimitedTextRange;
 import org.apache.fop.datatypes.Length;
 import org.apache.fop.fo.flow.Block;
+import org.apache.fop.fo.pagination.PageSequence;
 import org.apache.fop.fo.properties.CommonFont;
 import org.apache.fop.fo.properties.CommonHyphenation;
 import org.apache.fop.fo.properties.CommonTextDecoration;
@@ -109,6 +110,11 @@ public class FOText extends FONode implements CharSequence, TextFragment {
      */
     public FOText(FONode parent) {
         super(parent);
+
+        PageSequence pageSequence = getRoot().getLastPageSequence();
+        if (pageSequence != null && pageSequence.hasChangeBars()) {
+            nodeChangeBarList = getRoot().getLastPageSequence().getClonedChangeBarList();
+        }
     }
 
     /** {@inheritDoc} */
index e3afbbb7585bbf6819e16b38d3521fe54105e439..249f0e0fe34ac782829bad69400fe1742ebed3b2 100644 (file)
@@ -273,7 +273,9 @@ public class FOTreeBuilder extends DefaultHandler {
                 if (currentFObj.getNamespaceURI().equals(FOElementMapping.URI)
                     || currentFObj.getNamespaceURI().equals(ExtensionElementMapping.URI)
                     || currentFObj.getNamespaceURI().equals(PDFElementMapping.NAMESPACE)) {
-                    currentFObj.validateChildNode(locator, namespaceURI, localName);
+                    if (!currentFObj.isChangeBarElement(namespaceURI, localName)) {
+                        currentFObj.validateChildNode(locator, namespaceURI, localName);
+                    }
                 }
             }
 
index a96cb3fe3b761268ee5fc9198874f04b94ed8ee4..452a9f563b830a07e08de493434445ec11d29732 100644 (file)
@@ -381,6 +381,47 @@ public interface FOValidationEventProducer extends EventProducer {
     void unknownFormattingObject(Object source, String elementName,
             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.
      *
index fc105e7e6a3ea340e66546f0bbed6fe9e5bd8ab5..f57e59bd11234298833d3c273d09f2f2dcbaf37d 100644 (file)
@@ -21,6 +21,7 @@ package org.apache.fop.fo;
 
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -34,7 +35,9 @@ import org.apache.xmlgraphics.util.QName;
 
 import org.apache.fop.apps.FOPException;
 import org.apache.fop.fo.extensions.ExtensionAttachment;
+import org.apache.fop.fo.flow.ChangeBar;
 import org.apache.fop.fo.flow.Marker;
+import org.apache.fop.fo.pagination.PageSequence;
 import org.apache.fop.fo.properties.Property;
 import org.apache.fop.fo.properties.PropertyMaker;
 
@@ -182,6 +185,39 @@ public abstract class FObj extends FONode implements Constants {
         if (id != null) {
             checkId(id);
         }
+
+        PageSequence pageSequence = getRoot().getLastPageSequence();
+        if (pageSequence != null && pageSequence.hasChangeBars()) {
+            startOfNodeChangeBarList = pageSequence.getClonedChangeBarList();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws FOPException FOP Exception
+     */
+    public void endOfNode() throws FOPException {
+
+        List<ChangeBar> endOfNodeChangeBarList = null;
+
+        PageSequence pageSequence = getRoot().getLastPageSequence();
+        if (pageSequence != null) {
+            endOfNodeChangeBarList = pageSequence.getClonedChangeBarList();
+        }
+
+        if (startOfNodeChangeBarList != null && endOfNodeChangeBarList != null) {
+
+            nodeChangeBarList = new LinkedList<ChangeBar>(endOfNodeChangeBarList);
+            nodeChangeBarList.retainAll(startOfNodeChangeBarList);
+
+            if (nodeChangeBarList.isEmpty()) {
+                nodeChangeBarList = null;
+            }
+
+            startOfNodeChangeBarList = null;
+        }
+
+        super.endOfNode();
     }
 
     /**
@@ -492,6 +528,8 @@ public abstract class FObj extends FONode implements Constants {
     protected boolean isInlineItem(String nsURI, String lName) {
         return (FO_URI.equals(nsURI)
                 && ("bidi-override".equals(lName)
+                        || "change-bar-begin".equals(lName)
+                        || "change-bar-end".equals(lName)
                         || "character".equals(lName)
                         || "external-graphic".equals(lName)
                         || "instream-foreign-object".equals(lName)
diff --git a/fop-core/src/main/java/org/apache/fop/fo/flow/ChangeBar.java b/fop-core/src/main/java/org/apache/fop/fo/flow/ChangeBar.java
new file mode 100644 (file)
index 0000000..5fa1234
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * 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.datatypes.Length;
+import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.FObj;
+import org.apache.fop.fo.PropertyList;
+import org.apache.fop.fo.StaticPropertyList;
+import org.apache.fop.fo.ValidationException;
+import org.apache.fop.fo.properties.SpaceProperty;
+
+/**
+ * Common change bar base class. Handles change bar properties and validates child nodes.
+ */
+public abstract class ChangeBar extends FObj {
+
+    /**
+     * Constructs a ChangeBar element with common parts for both begin and end change bars.
+     *
+     * @param parent The parent node
+     */
+    public ChangeBar(FONode parent) {
+        super(parent);
+    }
+
+    /**
+     * The change bar class (required).
+     */
+    protected String changeBarClass;
+
+    /**
+     * The change bar color.
+     */
+    protected Color color;
+
+    /**
+     * The change bar offset.
+     */
+    protected Length offset;
+
+    /**
+     * The change bar placement.
+     */
+    protected int placement = -1;
+
+    /**
+     * The change bar style.
+     */
+    protected int style = -1;
+
+    /**
+     * The change bar width.
+     */
+    protected Length width;
+
+    /**
+     * The actual line height.
+     */
+    protected SpaceProperty lineHeight;
+
+    /** {@inheritDoc} */
+    public void bind(PropertyList pList) throws FOPException {
+        super.bind(pList);
+
+        changeBarClass = 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();
+        lineHeight = pList.get(PR_LINE_HEIGHT).getSpace();
+    }
+
+    /** {@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 (inMarker()) {
+            PropertyList newPList = new StaticPropertyList(this, null);
+            newPList.addAttributesToList(attlist);
+            bind(newPList);
+        }
+
+        if (changeBarClass == null || changeBarClass.isEmpty()) {
+            missingPropertyError("change-bar-class");
+        }
+
+        if (findAncestor(FO_FLOW) == -1
+            && findAncestor(FO_STATIC_CONTENT) == -1) {
+            getFOValidationEventProducer().changeBarWrongAncestor(this, getName(), locator);
+          }
+    }
+
+    /**
+     * Adds the current change bar to the active change bar list.
+     */
+    protected void push() {
+        getRoot().getLastPageSequence().pushChangeBar(this);
+    }
+
+    /**
+     * Removes the starting counterpart of the current change bar from the active change bar list.
+     */
+    protected void pop() {
+        getRoot().getLastPageSequence().popChangeBar(this);
+    }
+
+    /**
+     * Returns the starting counterpart of the current (ending) change bar.
+     *
+     * @return The starting counterpart of the current (ending) change bar
+     */
+    protected ChangeBar getChangeBarBegin() {
+        return getRoot().getLastPageSequence().getChangeBarBegin(this);
+    }
+
+    /**
+     * Returns the change bar class.
+     *
+     * @return The change bar class
+     */
+    public String getChangeBarClass() {
+        return changeBarClass;
+    }
+
+    /**
+     * Returns the change bar color.
+     *
+     * @return The change bar color
+     */
+    public Color getColor() {
+        return color;
+    }
+
+    /**
+     * Returns the change bar offset.
+     *
+     * @return The change bar offset
+     */
+    public Length getOffset() {
+        return offset;
+    }
+
+    /**
+     * Returns the change bar placement.
+     *
+     * @return The change bar placement
+     */
+    public int getPlacement() {
+        return placement;
+    }
+
+    /**
+     * Returns the change bar style.
+     *
+     * @return The change bar style
+     */
+    public int getStyle() {
+        return style;
+    }
+
+    /**
+     * Returns the change bar width.
+     *
+     * @return The change bar width
+     */
+    public Length getWidth() {
+        return width;
+    }
+
+    /**
+     * Returns the line height.
+     *
+     * @return The line height
+     */
+    public SpaceProperty getLineHeight() {
+        return lineHeight;
+    }
+
+}
diff --git a/fop-core/src/main/java/org/apache/fop/fo/flow/ChangeBarBegin.java b/fop-core/src/main/java/org/apache/fop/fo/flow/ChangeBarBegin.java
new file mode 100644 (file)
index 0000000..961a0e3
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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;
+
+public class ChangeBarBegin extends ChangeBar {
+
+    /**
+     * Constructs a new ChangeBarBegin element.
+     *
+     * @param parent The parent node
+     */
+    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();
+    }
+}
diff --git a/fop-core/src/main/java/org/apache/fop/fo/flow/ChangeBarEnd.java b/fop-core/src/main/java/org/apache/fop/fo/flow/ChangeBarEnd.java
new file mode 100644 (file)
index 0000000..4feca13
--- /dev/null
@@ -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;
+
+public class ChangeBarEnd extends ChangeBar {
+
+    /**
+     * Constructs a new ChangeBarEnd element.
+     *
+     * @param parent The parent node
+     */
+    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 changeBarStart = getChangeBarBegin();
+
+        if (changeBarStart == null) {
+            getFOValidationEventProducer().changeBarNoBegin(this, getName(), locator);
+        } else {
+            pop();
+        }
+    }
+}
index 2beaf2f991fc5685b8467bcdf16757382f69311b..024b779052b3734f0444ec72b117bdcfe1653bae 100644 (file)
@@ -90,9 +90,11 @@ public class TableRow extends TableCellContainer implements BreakPropertySet {
     /** {@inheritDoc} */
     protected void addChildNode(FONode child) throws FOPException {
         if (!inMarker()) {
-            TableCell cell = (TableCell) child;
-            TablePart part = (TablePart) getParent();
-            addTableCellChild(cell, part.isFirst(this));
+            if (child instanceof TableCell) {
+               TableCell cell = (TableCell) child;
+               TablePart part = (TablePart) getParent();
+               addTableCellChild(cell, part.isFirst(this));
+            }
         }
         super.addChildNode(child);
     }
index a1a966e9098aa62621581783d964d55bb0f92c26..3f82e6822ee4a3ccd0678c2171a558330af5c5c6 100644 (file)
@@ -19,6 +19,8 @@
 
 package org.apache.fop.fo.pagination;
 
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Stack;
@@ -31,6 +33,7 @@ import org.apache.fop.datatypes.Numeric;
 import org.apache.fop.fo.FONode;
 import org.apache.fop.fo.PropertyList;
 import org.apache.fop.fo.ValidationException;
+import org.apache.fop.fo.flow.ChangeBar;
 import org.apache.fop.fo.properties.CommonHyphenation;
 import org.apache.fop.traits.Direction;
 import org.apache.fop.traits.WritingMode;
@@ -77,6 +80,11 @@ public class PageSequence extends AbstractPageSequence implements WritingModeTra
      */
     private Flow mainFlow;
 
+    /**
+     * Active change bars
+     */
+    private final List<ChangeBar> changeBarList = new LinkedList<ChangeBar>();
+
     /**
      * Create a PageSequence instance that is a child of the
      * given {@link FONode}.
@@ -118,6 +126,7 @@ public class PageSequence extends AbstractPageSequence implements WritingModeTra
                         masterReference, getLocator());
             }
         }
+        getRoot().addPageSequence(this);
         getFOEventHandler().startPageSequence(this);
     }
 
@@ -464,4 +473,73 @@ public class PageSequence extends AbstractPageSequence implements WritingModeTra
         return pageSequenceMaster.getLastSimplePageMaster(isOddPage, isFirstPage, isBlank, getMainFlow()
                 .getFlowName());
     }
+
+    /**
+     * Adds the specified change bar to the active change bar list.
+     *
+     * @param changeBarBegin The starting change bar element
+     */
+    public void pushChangeBar(ChangeBar changeBarBegin) {
+        changeBarList.add(changeBarBegin);
+    }
+
+    /**
+     * Removes the couple of the specified change bar from the active change bar list.
+     *
+     * @param changeBarEnd The ending change bar element
+     */
+    public void popChangeBar(ChangeBar changeBarEnd) {
+        ChangeBar changeBarBegin = getChangeBarBegin(changeBarEnd);
+        if (changeBarBegin != null) {
+            changeBarList.remove(changeBarBegin);
+        }
+    }
+
+    /**
+     * Returns the starting counterpart of the specified ending change bar.
+     *
+     * @param changeBarEnd The ending change bar element
+     * @return The starting counterpart of the specified ending change bar
+     */
+    public ChangeBar getChangeBarBegin(ChangeBar changeBarEnd) {
+        if (changeBarList.isEmpty()) {
+            return null;
+        } else {
+            String changeBarClass = changeBarEnd.getChangeBarClass();
+            for (int i = changeBarList.size() - 1; i >= 0; i--) {
+                ChangeBar changeBar = changeBarList.get(i);
+                if (changeBar.getChangeBarClass().equals(changeBarClass)) {
+                    return changeBar;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Tests if there are any active change bars.
+     *
+     * @return A boolean value true if there are any active change bars
+     */
+    public boolean hasChangeBars() {
+        return !changeBarList.isEmpty();
+    }
+
+    /**
+     * Returns the list of active change bars.
+     *
+     * @return The list of active change bars
+     */
+    public List<ChangeBar> getChangeBarList() {
+        return changeBarList;
+    }
+
+    /**
+     * Returns the copy of active change bars list.
+     *
+     * @return The list containing a copy of the active change bars
+     */
+    public List<ChangeBar> getClonedChangeBarList() {
+        return new LinkedList<ChangeBar>(changeBarList);
+    }
 }
index 51309a65d1dfcc3a5ab17c4b7a197ef72ac15c0d..3b895b3721bb5ac83c95033b703166f0523549dc 100644 (file)
@@ -281,6 +281,28 @@ public class Root extends FObj implements CommonAccessibilityHolder {
         }
     }
 
+    /**
+     * Adds the specified page sequence.
+     *
+     * @param pageSequence The page sequence to add
+     */
+    public void addPageSequence(PageSequence pageSequence) {
+        pageSequences.add(pageSequence);
+    }
+
+    /**
+     * Returns the last page sequence (current while parsing).
+     *
+     * @return The last page sequence or null
+     */
+    public PageSequence getLastPageSequence() {
+        if (getPageSequenceCount() > 0) {
+            return pageSequences.get(getPageSequenceCount() - 1);
+        } else {
+            return null;
+        }
+    }
+
     /**
      * Returns the associated LayoutMasterSet.
      * @return the LayoutMasterSet instance
index b687689bcbc3e8efc54dac12538846d9536ffa20..ca5d1c507dff37b654eb597e702d9b7e1329a408 100644 (file)
@@ -28,6 +28,7 @@ import org.apache.commons.logging.LogFactory;
 import org.apache.fop.datatypes.LengthBase;
 import org.apache.fop.datatypes.PercentBaseContext;
 import org.apache.fop.fo.FObj;
+import org.apache.fop.fo.flow.ChangeBar;
 
 /**
  * The base class for nearly all LayoutManagers.
@@ -257,6 +258,19 @@ public abstract class AbstractBaseLayoutManager
         return fobj;
     }
 
+    /**
+     * Returns the active change bar list.
+     *
+     * @return The active change bar list
+     */
+    public List<ChangeBar> getChangeBarList() {
+       if (fobj == null) {
+           return null;
+       } else {
+           return fobj.getChangeBarList();
+       }
+    }
+
     /** {@inheritDoc} */
     public void reset() {
         throw new UnsupportedOperationException("Not implemented");
index 9ce113d11a54450fb99213217d0dc8993cb1524f..f0fc77577084689f9d98d8481e7fef3d6f2fb370 100644 (file)
@@ -854,6 +854,7 @@ public class BlockContainerLayoutManager extends SpacedBorderedPaddedBlockLayout
             int level = getBlockContainerFO().getBidiLevel();
 
             viewportBlockArea = new BlockViewport(allowBPDUpdate);
+            viewportBlockArea.setChangeBarList(getChangeBarList());
             viewportBlockArea.addTrait(Trait.IS_VIEWPORT_AREA, Boolean.TRUE);
             if (level >= 0) {
                 viewportBlockArea.setBidiLevel(level);
@@ -892,6 +893,7 @@ public class BlockContainerLayoutManager extends SpacedBorderedPaddedBlockLayout
             }
 
             referenceArea = new Block();
+            referenceArea.setChangeBarList(getChangeBarList());
             referenceArea.addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE);
             if (level >= 0) {
                 referenceArea.setBidiLevel(level);
index 722a011ae958dfdeecf68cfdd8c16cb4c53fd176..ac0da5f6a019ca069d78deb12f9b0118e3bfc16b 100644 (file)
@@ -357,6 +357,7 @@ public class BlockLayoutManager extends SpacedBorderedPaddedBlockLayoutManager
     public Area getParentArea(Area childArea) {
         if (curBlockArea == null) {
             curBlockArea = new Block();
+            curBlockArea.setChangeBarList(getChangeBarList());
 
             curBlockArea.setIPD(super.getContentAreaIPD());
 
index b8714a57089b85a58d777a7655a9970c1000b106..6069dbcc3087504db8029c3e7c121bbcf9af3674 100644 (file)
@@ -124,6 +124,7 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
         int sp = TraitSetter.getEffectiveSpace(adjust, minoptmax);
         if (sp != 0) {
             Block spacer = new Block();
+            spacer.setChangeBarList(getChangeBarList());
             spacer.setBPD(sp);
             parentLayoutManager.addChildArea(spacer);
         }
index aae5a6b3078715863f1c514dd84ac1e3d0089491..06ad4eeba5ba6fd96e41511c24dec5239458a104 100644 (file)
@@ -178,6 +178,7 @@ public class ExternalDocumentLayoutManager extends AbstractPageSequenceLayoutMan
         Dimension imageSize = this.imageLayout.getViewportSize();
 
         Block blockArea = new Block();
+        blockArea.setChangeBarList(getChangeBarList());
         blockArea.setIPD(imageSize.width);
         LineArea lineArea = new LineArea();
 
index e95cd18ec22e5cdd079306da41ec84752bf8e049..3a706a3250cdbfdf656ac76d91c271561c6cadef 100644 (file)
@@ -39,6 +39,8 @@ import org.apache.fop.fo.flow.BasicLink;
 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.Float;
@@ -146,6 +148,8 @@ public class LayoutManagerMapping implements LayoutManagerMaker {
         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());
         registerMaker(MultiCase.class, new MultiCaseLayoutManagerMaker());
         registerMaker(MultiSwitch.class, new MultiSwitchLayoutManagerMaker());
         registerMaker(Float.class, new FloatLayoutManagerMaker());
index 2e1b7f2ae3d856fd0b303867ae5b99b87c01a2d8..c06ec522aecd6ef85875af547e6a95fb25667749 100644 (file)
@@ -133,6 +133,7 @@ public abstract class AbstractPageNumberCitationLayoutManager extends LeafNodeLa
             getPSLM().addUnresolvedArea(citation.getRefId(), unresolved);
             text = unresolved;
         }
+        text.setChangeBarList(getChangeBarList());
         setTraits(text);
         return text;
     }
index c959ee7be5fb3cb94a43fa7775e818795ba39fff..3f68df0e209695dd1ecb8dfb2b647fc5d237313e 100644 (file)
@@ -75,6 +75,7 @@ public class CharacterLayoutManager extends LeafNodeLayoutManager {
     private TextArea createCharacterArea() {
         Character fobj = (Character) this.fobj;
         TextArea text = new TextArea();
+        text.setChangeBarList(getChangeBarList());
         char ch = fobj.getCharacter();
         int ipd = font.getCharWidth(ch);
         int blockProgressionOffset = 0;
index af166498100e4390774a2128423fe21aaf78b90b..a5f128f85a144af9e1ac4daf4fb41230043e35f7 100644 (file)
@@ -84,6 +84,7 @@ public class ContentLayoutManager extends AbstractBaseLayoutManager
         // get breaks then add areas to title
         this.parentLM = pslm;
         holder = new LineArea();
+        holder.setChangeBarList(getChangeBarList());
 
         //        setUserAgent(foTitle.getUserAgent());
 
index 2719d5c961d47621d7ca8aafdf823b90a4b7ff3b..8a204607e6ddde988076b13e5822c36937427415 100644 (file)
@@ -42,7 +42,9 @@ public class ExternalGraphicLayoutManager extends AbstractGraphicsLayoutManager
 
     /** {@inheritDoc} */
     protected Area getChildArea() {
-        return new Image(((ExternalGraphic) fobj).getSrc());
+        Image im = new Image(((ExternalGraphic) fobj).getSrc());
+        im.setChangeBarList(getChangeBarList());
+        return im;
     }
 
 }
index df37b9902c48fc8276b3cd7c01a341158e78bd31..85f545e5e5cc55b7c9d63fabf7d60eb87b207206 100644 (file)
@@ -206,9 +206,11 @@ public class InlineLayoutManager extends InlineStackingLayoutManager {
         InlineArea area;
         if (isInline) {
             area = createInlineParent();
+            area.setChangeBarList(getChangeBarList());
             area.setBlockProgressionOffset(0);
         } else {
             area = new InlineBlockParent();
+            area.setChangeBarList(getChangeBarList());
         }
         if (fobj instanceof Inline || fobj instanceof BasicLink) {
             TraitSetter.setProducerID(area, fobj.getId());
index 5b9efa43ee65b8103efeb6550b987daeb6616889..7a8ac8627c8ad1a2758cc6ac9479b304f081ec5b 100644 (file)
@@ -181,6 +181,7 @@ public abstract class InlineStackingLayoutManager extends AbstractLayoutManager
             if (iAdjust != 0) {
                 //getLogger().debug("Add leading space: " + iAdjust);
                 Space ls = new Space();
+                ls.setChangeBarList(getChangeBarList());
                 ls.setIPD(iAdjust);
                 int level = parentArea.getBidiLevel();
                 if (level >= 0) {
index 4a54f582d3fb7135ba2cfa30cad42b4847817279..6936e3e9424479dae01997cdf63babb434b395f3 100644 (file)
@@ -46,7 +46,9 @@ public class InstreamForeignObjectLM extends AbstractGraphicsLayoutManager {
         org.w3c.dom.Document doc = child.getDOMDocument();
         String ns = child.getNamespaceURI();
 
-        return new ForeignObject(doc, ns);
+        ForeignObject obj = new ForeignObject(doc, ns);
+        obj.setChangeBarList(getChangeBarList());
+        return obj;
     }
 
 }
index 5f65a596963558d6f01d9c48b6f38cf63535e62d..a6d695b063779cbb8471c072ff7b9dd54a49a46c 100644 (file)
@@ -217,6 +217,10 @@ public class LeaderLayoutManager extends LeafNodeLayoutManager {
                 leaderArea.setBidiLevel(fobj.getBidiLevelRecursive());
             }
         }
+
+        assert leaderArea != null;
+        leaderArea.setChangeBarList(getChangeBarList());
+
         TraitSetter.setProducerID(leaderArea, fobj.getId());
         return leaderArea;
      }
index 8ee5d1e702250a0c6376aaee469a5636b0cea22f..c15c1d0beb991c200c29be35ead589b058c7a1ff 100644 (file)
@@ -1504,6 +1504,8 @@ public class LineLayoutManager extends InlineStackingLayoutManager
         LineArea lineArea = new LineArea(
                 (lbp.getLeafPos() < seq.size() - 1 ? textAlignment : textAlignmentLast),
                 lbp.difference, lbp.availableStretch, lbp.availableShrink);
+        lineArea.setChangeBarList(getChangeBarList());
+
         if (lbp.startIndent != 0) {
             lineArea.addTrait(Trait.START_INDENT, lbp.startIndent);
         }
@@ -1619,6 +1621,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
         }
 
         LineArea lineArea = new LineArea();
+        lineArea.setChangeBarList(getChangeBarList());
         setCurrentArea(lineArea);
         LayoutContext lc = LayoutContext.newInstance();
         lc.setAlignmentContext(alignmentContext);
index 27bd544dddd1f6024f7d74ee59eb5b176627111d..3134ebb1796b72b4ff474a7df6040fec44f85d43 100644 (file)
@@ -32,6 +32,7 @@ import org.apache.fop.area.Trait;
 import org.apache.fop.area.inline.TextArea;
 import org.apache.fop.fo.Constants;
 import org.apache.fop.fo.FOText;
+import org.apache.fop.fo.flow.ChangeBar;
 import org.apache.fop.fonts.Font;
 import org.apache.fop.fonts.FontSelector;
 import org.apache.fop.fonts.GlyphMapping;
@@ -312,6 +313,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
 
         TextArea textArea = new TextAreaBuilder(realWidth, totalAdjust, context, firstMappingIndex,
                 lastMappingIndex, context.isLastArea(), mapping.font).build();
+        textArea.setChangeBarList(getChangeBarList());
 
         // wordSpaceDim is computed in relation to wordSpaceIPD.opt
         // but the renderer needs to know the adjustment in relation
@@ -411,6 +413,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                 textArea = new TextArea(width.getStretch(), width.getShrink(),
                         adjust);
             }
+            textArea.setChangeBarList(getChangeBarList());
         }
 
         private void setInlineProgressionDimension() {
@@ -1457,6 +1460,15 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
 
     }
 
+    @Override
+    public List<ChangeBar> getChangeBarList() {
+        if (foText == null) {
+            return null;
+        } else {
+            return foText.getChangeBarList();
+        }
+    }
+
     /** {@inheritDoc} */
     public String toString() {
         return super.toString() + "{"
index 9b37e24056b3092c254e9749cabd10b8f44648a1..ff2c59f4a9bd59d32933f512d5078b1c1c73f94c 100644 (file)
@@ -68,10 +68,12 @@ public class WrapperLayoutManager extends LeafNodeLayoutManager {
             if (parentLayoutManager instanceof BlockStackingLayoutManager
                     && !(parentLayoutManager instanceof BlockLayoutManager)) {
                 Block helperBlock = new Block();
+                helperBlock.setChangeBarList(getChangeBarList());
                 TraitSetter.setProducerID(helperBlock, fobj.getId());
                 parentLayoutManager.addChildArea(helperBlock);
             } else {
                 InlineArea area = getEffectiveArea(context);
+                area.setChangeBarList(getChangeBarList());
                 parentLayoutManager.addChildArea(area);
             }
         }
index d39b634774c9218f2c44a09f544a88a5d79dd9e3..b73abeb0da15f3617be48d87d320b09824c4d185 100644 (file)
@@ -216,6 +216,7 @@ public class ListBlockLayoutManager extends SpacedBorderedPaddedBlockLayoutManag
     public Area getParentArea(Area childArea) {
         if (curBlockArea == null) {
             curBlockArea = new Block();
+            curBlockArea.setChangeBarList(getChangeBarList());
 
             // Set up dimensions
             // Must get dimensions from parent area
index 214ba626921847d1815fd4e685a7c4cd07d37fdd..0cc877e372d18d3c03c16f665e27d35f42698245 100644 (file)
@@ -176,6 +176,7 @@ public class ListItemContentLayoutManager extends BlockStackingLayoutManager imp
     public Area getParentArea(Area childArea) {
         if (curBlockArea == null) {
             curBlockArea = new Block();
+            curBlockArea.setChangeBarList(getChangeBarList());
             curBlockArea.setPositioning(Block.ABSOLUTE);
             // set position
             curBlockArea.setXOffset(xOffset);
index 9d9769a7c5571f74d6f25765b9dd2732d08f64cc..764575ac8c001c2fef461b469454e375251b050a 100644 (file)
@@ -739,6 +739,7 @@ public class ListItemLayoutManager extends SpacedBorderedPaddedBlockLayoutManage
     public Area getParentArea(Area childArea) {
         if (curBlockArea == null) {
             curBlockArea = new Block();
+            curBlockArea.setChangeBarList(getChangeBarList());
 
             // Set up dimensions
             /*Area parentArea =*/ parentLayoutManager.getParentArea(curBlockArea);
index cbc19c1ecff927430c52cf5de7b871f5e507598c..06dda5efeac335d426325309976fdfbc3458650d 100644 (file)
@@ -468,6 +468,7 @@ class RowPainter {
 
         //generate the block area
         Block block = new Block();
+        block.setChangeBarList(tclm.getTableLM().getFObj().getChangeBarList());
         block.setPositioning(Block.ABSOLUTE);
         block.addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE);
         block.setIPD(ipd);
index aaa896ce3faa35fe65e877ef02dd63923f7ef2eb..d95e508c5052731b6d51fe84193f2e357de75d74 100644 (file)
@@ -179,6 +179,8 @@ public class TableAndCaptionLayoutManager extends BlockStackingLayoutManager {
     public Area getParentArea(Area childArea) {
         if (curBlockArea == null) {
             curBlockArea = new Block();
+            curBlockArea.setChangeBarList(getChangeBarList());
+
             // Set up dimensions
             // Must get dimensions from parent area
             Area parentArea = parentLayoutManager.getParentArea(curBlockArea);
index 8823c0fae924faa89034a2cf6ed12b83236b7be3..ee4cba2e44818e690a0875a174b621c92a6cfc42 100644 (file)
@@ -175,6 +175,8 @@ public class TableCaptionLayoutManager extends BlockStackingLayoutManager {
     public Area getParentArea(Area childArea) {
         if (curBlockArea == null) {
             curBlockArea = new Block();
+            curBlockArea.setChangeBarList(getChangeBarList());
+
             // Set up dimensions
             // Must get dimensions from parent area
             Area parentArea = parentLayoutManager.getParentArea(curBlockArea);
index cfa064db6a9946cd8f24200a0d84d7306fe5fe5d..a56b00ce7afdaeddf0ad3ffd8174842b5915614c 100644 (file)
@@ -529,11 +529,13 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager {
         if (usedBPD < cellBPD) {
             if (getTableCell().getDisplayAlign() == EN_CENTER) {
                 Block space = new Block();
+                space.setChangeBarList(getChangeBarList());
                 space.setBPD((cellBPD - usedBPD) / 2);
                 space.setBidiLevel(getTableCell().getBidiLevelRecursive());
                 curBlockArea.addBlock(space);
             } else if (getTableCell().getDisplayAlign() == EN_AFTER) {
                 Block space = new Block();
+                space.setChangeBarList(getChangeBarList());
                 space.setBPD(cellBPD - usedBPD);
                 space.setBidiLevel(getTableCell().getBidiLevelRecursive());
                 curBlockArea.addBlock(space);
@@ -620,6 +622,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager {
                            boolean outer, int level) {
         if (blocks[i][j] == null) {
             blocks[i][j] = new Block();
+            blocks[i][j].setChangeBarList(getChangeBarList());
             blocks[i][j].addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE);
             blocks[i][j].setPositioning(Block.ABSOLUTE);
             blocks[i][j].setBidiLevel(level);
@@ -651,6 +654,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager {
         int paddingEnd = padding.getPaddingEnd(false, this);
 
         Block block = new Block();
+        block.setChangeBarList(getChangeBarList());
         TraitSetter.setProducerID(block, getTable().getId());
         block.setPositioning(Block.ABSOLUTE);
         block.setIPD(cellIPD + paddingStart + paddingEnd);
@@ -677,6 +681,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager {
     public Area getParentArea(Area childArea) {
         if (curBlockArea == null) {
             curBlockArea = new Block();
+            curBlockArea.setChangeBarList(getChangeBarList());
             curBlockArea.addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE);
             TraitSetter.setProducerID(curBlockArea, getTableCell().getId());
             curBlockArea.setPositioning(Block.ABSOLUTE);
index 4940c66b2838f3856eda5cf22c8010933c62ec25..333419649a5b998a775765355bee945b48c0326f 100644 (file)
@@ -438,6 +438,8 @@ public class TableLayoutManager extends SpacedBorderedPaddedBlockLayoutManager
     public Area getParentArea(Area childArea) {
         if (curBlockArea == null) {
             curBlockArea = new Block();
+            curBlockArea.setChangeBarList(getChangeBarList());
+
             // Set up dimensions
             // Must get dimensions from parent area
             /*Area parentArea =*/ parentLayoutManager.getParentArea(curBlockArea);
index 552d9f92fc4acf14525a52d53d6bc1ee3e4cc533..a078509e70b27eb1c356a9b408104b8fd35f622b 100644 (file)
@@ -736,6 +736,7 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer {
         // save position and offset
         int saveIP = currentIPPosition;
         int saveBP = currentBPPosition;
+        int saveBO = getBeginOffset();
 
         //Establish a new coordinate system
         AffineTransform at = new AffineTransform();
@@ -743,6 +744,8 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer {
         at.translate(block.getXOffset(), block.getYOffset());
         at.translate(0, block.getSpaceBefore());
 
+        setBeginOffset(saveBO - block.getXOffset());
+
         if (!at.isIdentity()) {
             establishTransformationMatrix(at);
         }
@@ -760,6 +763,8 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer {
             restoreGraphicsState();
         }
 
+        setBeginOffset(saveBO);
+
         // stacked and relative blocks effect stacking
         currentIPPosition = saveIP;
         currentBPPosition = saveBP;
index d57d3ce06fc7aa8bba6c5a02650d7c22ef6eb31d..e8ab76d536b7276e35ffb48bf3443c1390b91673 100644 (file)
@@ -41,6 +41,7 @@ import org.apache.fop.apps.FOUserAgent;
 import org.apache.fop.area.Area;
 import org.apache.fop.area.BeforeFloat;
 import org.apache.fop.area.Block;
+import org.apache.fop.area.BlockParent;
 import org.apache.fop.area.BlockViewport;
 import org.apache.fop.area.BodyRegion;
 import org.apache.fop.area.CTM;
@@ -61,6 +62,7 @@ import org.apache.fop.area.inline.FilledArea;
 import org.apache.fop.area.inline.ForeignObject;
 import org.apache.fop.area.inline.Image;
 import org.apache.fop.area.inline.InlineArea;
+import org.apache.fop.area.inline.InlineBlock;
 import org.apache.fop.area.inline.InlineBlockParent;
 import org.apache.fop.area.inline.InlineParent;
 import org.apache.fop.area.inline.InlineViewport;
@@ -70,7 +72,11 @@ import org.apache.fop.area.inline.SpaceArea;
 import org.apache.fop.area.inline.TextArea;
 import org.apache.fop.area.inline.WordArea;
 import org.apache.fop.fo.Constants;
+import org.apache.fop.fo.flow.ChangeBar;
+import org.apache.fop.fo.properties.Property;
 import org.apache.fop.fonts.FontInfo;
+import org.apache.fop.traits.BorderProps;
+import org.apache.fop.traits.Direction;
 import org.apache.fop.traits.Visibility;
 
 /**
@@ -111,7 +117,74 @@ public abstract class AbstractRenderer
      */
     protected int containingIPPosition;
 
-    /** the currently active PageViewport */
+    /**
+     * The "start edge" IP Position of the current column (for change bars)
+     */
+    protected int columnStartIPPosition;
+
+    /**
+     * The "end edge" IP Position of the current column (for change bars)
+     */
+    protected int columnEndIPPosition;
+
+    /**
+     * The "left" position of the current column (for change bars)
+     */
+    protected int columnLeftIPPosition;
+
+    /**
+     * The "right" position of the current column (for change bars)
+     */
+    protected int columnRightIPPosition;
+
+    /**
+     * The number of columns in the span (for change bars)
+     */
+    protected int columnCount;
+
+    /**
+     * The index number of the current column (for change bars)
+     */
+    protected int columnIndex;
+
+    /**
+     * The column width (for change bars)
+     */
+    protected int columnWidth;
+
+    /**
+     * The size of column gap (for change bars)
+     */
+    protected int columnGap;
+
+    /**
+     * The block progression direction (for change bars)
+     */
+    protected Direction blockProgressionDirection;
+
+    /**
+     * The inline progression direction (for change bars)
+     */
+    protected Direction inlineProgressionDirection;
+
+    /**
+     * Is binding on start edge of column?
+     */
+    protected boolean bindingOnStartEdge;
+
+    /**
+     * Is binding on end edge of column?
+     */
+    protected boolean bindingOnEndEdge;
+
+    /**
+     * The IP begin offset of coordinate 0
+     */
+    private int beginOffset;
+
+    /**
+     * the currently active PageViewport
+     */
     protected PageViewport currentPageViewport;
 
     /* warned XML handlers */
@@ -407,36 +480,95 @@ public abstract class AbstractRenderer
      * that are positioned into columns.
      * </p>
      *
-     * @param m The main reference area
+     * @param mainReference The main reference area
      */
-    protected void renderMainReference(MainReference mr) {
+    protected void renderMainReference(MainReference mainReference) {
         Span span = null;
-        List spans = mr.getSpans();
+        List spans = mainReference.getSpans();
         int saveBPPos = currentBPPosition;
-        int saveSpanBPPos = saveBPPos;
         int saveIPPos = currentIPPosition;
+        int saveSpanBPPos = saveBPPos;
+
         for (Object span1 : spans) {
             span = (Span) span1;
+
+            columnCount = span.getColumnCount();
+            columnGap = span.getColumnGap();
+            columnWidth = span.getColumnWidth();
+
+            blockProgressionDirection = (Direction) span.getTrait(Trait.BLOCK_PROGRESSION_DIRECTION);
+            inlineProgressionDirection = (Direction) span.getTrait(Trait.INLINE_PROGRESSION_DIRECTION);
+
             int level = span.getBidiLevel();
             if (level < 0) {
                 level = 0;
             }
             if ((level & 1) == 1) {
                 currentIPPosition += span.getIPD();
-                currentIPPosition += mr.getColumnGap();
+                currentIPPosition += columnGap;
             }
-            for (int c = 0; c < span.getColumnCount(); c++) {
-                NormalFlow flow = span.getNormalFlow(c);
+
+            for (columnIndex = 0; columnIndex < columnCount; columnIndex++) {
+
+                NormalFlow flow = span.getNormalFlow(columnIndex);
+
+                boolean isLeftToRight = (inlineProgressionDirection == null)
+                        || (inlineProgressionDirection.getEnumValue() == Constants.EN_LR);
+
                 if (flow != null) {
+
+                    // if direction is right to left, then end is left edge,
+                    // else end is right edge (for top-bottom/bottom-top block
+                    // progression directions)
+
+                    // binding edge is on left edge for odd pages and
+                    // on right edge for even pages
+
+                    int pageIndex = currentPageViewport.getPageIndex();
+
+                    bindingOnStartEdge = false;
+                    bindingOnEndEdge = false;
+
+                    if (isLeftToRight) {
+
+                        columnStartIPPosition = 0;
+                        columnEndIPPosition = columnWidth;
+                        columnLeftIPPosition = 0;
+                        columnRightIPPosition = columnWidth;
+
+                        if (blockProgressionDirection == null || blockProgressionDirection.isVertical()) {
+                            if (pageIndex % 2 == 0) {
+                                bindingOnStartEdge = true;
+                            } else {
+                                bindingOnEndEdge = true;
+                            }
+                        }
+
+                    } else {
+
+                        columnStartIPPosition = columnWidth;
+                        columnEndIPPosition = 0;
+                        columnLeftIPPosition = 0;
+                        columnRightIPPosition = columnWidth;
+
+                        if (blockProgressionDirection == null || blockProgressionDirection.isVertical()) {
+                            if (pageIndex % 2 == 0) {
+                                bindingOnEndEdge = true;
+                            } else {
+                                bindingOnStartEdge = true;
+                            }
+                        }
+                    }
+
                     currentBPPosition = saveSpanBPPos;
                     if ((level & 1) == 1) {
                         currentIPPosition -= flow.getIPD();
-                        currentIPPosition -= mr.getColumnGap();
+                        currentIPPosition -= columnGap;
                     }
                     renderFlow(flow);
                     if ((level & 1) == 0) {
                         currentIPPosition += flow.getIPD();
-                        currentIPPosition += mr.getColumnGap();
+                        currentIPPosition += columnGap;
                     }
                 }
             }
@@ -504,7 +636,6 @@ public abstract class AbstractRenderer
             endVParea();
 
             // clip if necessary
-
             currentIPPosition = saveIP;
             currentBPPosition = saveBP;
         } else {
@@ -584,6 +715,18 @@ public abstract class AbstractRenderer
      */
     protected void renderBlock(Block block) {
         assert block != null;
+        List<ChangeBar> changeBarList = block.getChangeBarList();
+
+        if (changeBarList != null && !changeBarList.isEmpty()) {
+            int saveIP = currentIPPosition;
+            int saveBP = currentBPPosition;
+
+            drawChangeBars(block, changeBarList);
+
+            currentIPPosition = saveIP;
+            currentBPPosition = saveBP;
+        }
+
         List children = block.getChildAreas();
         boolean inNewLayer = false;
         if (maybeStartLayer(block)) {
@@ -627,8 +770,18 @@ public abstract class AbstractRenderer
         maybeEndLayer(block, inNewLayer);
     }
 
+    /**
+     * Renders an inline block area.
+     *
+     * @param inlineBlock The inline block area
+     */
+    protected void renderInlineBlock(InlineBlock inlineBlock) {
+        renderBlock(inlineBlock.getBlock());
+    }
+
     /**
      * Establish new optional content group layer.
+     *
      * @param layer name of layer
      */
     protected abstract void startLayer(String layer);
@@ -699,6 +852,11 @@ public abstract class AbstractRenderer
      * @param inlineArea inline area text to render
      */
     protected void renderInlineArea(InlineArea inlineArea) {
+        List<ChangeBar> changeBarList = inlineArea.getChangeBarList();
+
+        if (changeBarList != null && !changeBarList.isEmpty()) {
+            drawChangeBars(inlineArea, changeBarList);
+        }
         if (inlineArea instanceof TextArea) {
             renderText((TextArea) inlineArea);
         //} else if (inlineArea instanceof Character) {
@@ -707,6 +865,8 @@ public abstract class AbstractRenderer
             renderWord((WordArea) inlineArea);
         } else if (inlineArea instanceof SpaceArea) {
             renderSpace((SpaceArea) inlineArea);
+        } else if (inlineArea instanceof InlineBlock) {
+            renderInlineBlock((InlineBlock) inlineArea);
         } else if (inlineArea instanceof InlineParent) {
             renderInlineParent((InlineParent) inlineArea);
         } else if (inlineArea instanceof InlineBlockParent) {
@@ -757,6 +917,16 @@ public abstract class AbstractRenderer
         List children = text.getChildAreas();
         int saveIP = currentIPPosition;
         int saveBP = currentBPPosition;
+
+        List<ChangeBar> changeBarList = text.getChangeBarList();
+
+        if (changeBarList != null && !changeBarList.isEmpty()) {
+            drawChangeBars(text, changeBarList);
+
+            currentIPPosition = saveIP;
+            currentBPPosition = saveBP;
+        }
+
         for (Object aChildren : children) {
             InlineArea inline = (InlineArea) aChildren;
             renderInlineArea(inline);
@@ -877,6 +1047,11 @@ public abstract class AbstractRenderer
      * (todo) Make renderImage() protected
      */
     public void renderImage(Image image, Rectangle2D pos) {
+        List<ChangeBar> changeBarList = image.getChangeBarList();
+
+        if (changeBarList != null && !changeBarList.isEmpty()) {
+            drawChangeBars(image, changeBarList);
+        }
         // Default: do nothing.
         // Some renderers (ex. Text) don't support images.
     }
@@ -903,6 +1078,12 @@ public abstract class AbstractRenderer
      * (todo) Make renderForeignObject() protected
      */
     protected void renderForeignObject(ForeignObject fo, Rectangle2D pos) {
+        List<ChangeBar> changeBarList = fo.getChangeBarList();
+
+        if (changeBarList != null && !changeBarList.isEmpty()) {
+            drawChangeBars(fo, changeBarList);
+        }
+
         // Default: do nothing.
         // Some renderers (ex. Text) don't support foreign objects.
     }
@@ -975,4 +1156,191 @@ public abstract class AbstractRenderer
         matrix[5] = Math.round(matrix[5] * 1000);
         return new AffineTransform(matrix);
     }
+
+    /**
+     * Draws all change bars associated with an area.
+     *
+     * @param area The area to draw change bars for
+     * @param changeBarList The list of change bars affecting the area
+     */
+    protected void drawChangeBars(Area area, List<ChangeBar> changeBarList) {
+
+        if (area.getTraitAsBoolean(Trait.IS_REFERENCE_AREA)) {
+            return;
+        }
+
+        Block changeBarArea;
+
+        int saveIP = currentIPPosition;
+        int saveBP = currentBPPosition;
+
+        int currentColumnStartIP = columnStartIPPosition;
+        int currentColumnEndIP = columnEndIPPosition;
+        int currentColumnLeftIP = columnLeftIPPosition;
+        int currentColumnRightIP = columnRightIPPosition;
+
+        for (ChangeBar changeBar : changeBarList) {
+
+            boolean isLeftToRight = (inlineProgressionDirection == null)
+                    || (inlineProgressionDirection.getEnumValue() == Constants.EN_LR);
+
+            changeBarArea = new Block();
+
+            // currentIPPosition is reset to zero so from now on all multicolumn
+            // dimensions has to be calculated relatively to the given column
+            currentIPPosition = 0;
+            currentBPPosition = saveBP;
+
+            int changeBarWidth = changeBar.getWidth().getValue();
+            int changeBarOffset = changeBar.getOffset().getValue();
+
+            if (isLeftToRight) {
+                currentColumnStartIP = columnStartIPPosition - changeBarWidth;
+                currentColumnLeftIP = columnLeftIPPosition - changeBarWidth;
+            } else {
+                currentColumnEndIP = columnEndIPPosition - changeBarWidth;
+                currentColumnLeftIP = columnLeftIPPosition - changeBarWidth;
+            }
+
+            // xOffset by default is negative width for change bars placed on the
+            // start edge (overriden if placement is at the end edge)
+            int xOffset = currentColumnStartIP;
+
+            // 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 xScale = -1;
+
+            // determines currentIPPosition based on placement
+            switch (changeBar.getPlacement()) {
+                case EN_START:
+                    xOffset = currentColumnStartIP;
+                    xScale = -1;
+                    break;
+                case EN_END:
+                    xOffset = currentColumnEndIP;
+                    xScale = 1;
+                    break;
+                case EN_LEFT:
+                    xOffset = currentColumnLeftIP;
+                    xScale = (isLeftToRight) ? -1 : 1;
+                    break;
+                case EN_RIGHT:
+                    xOffset = currentColumnRightIP;
+                    xScale = (isLeftToRight) ? 1 : -1;
+                    break;
+                case EN_INSIDE:
+                    if (bindingOnStartEdge) {
+                        xOffset = currentColumnStartIP;
+                        xScale = -1;
+                    } else if (bindingOnEndEdge) {
+                        xOffset = currentColumnEndIP;
+                        xScale = 1;
+                    } else {
+                        xOffset = currentColumnStartIP;
+                        xScale = -1;
+                    }
+                    break;
+                case EN_OUTSIDE:
+                    if (bindingOnStartEdge) {
+                        xOffset = columnEndIPPosition;
+                        xScale = 1;
+                    } else if (bindingOnEndEdge) {
+                        xOffset = columnStartIPPosition;
+                        xScale = -1;
+                    } else {
+                        xOffset = columnStartIPPosition;
+                        xScale = -1;
+                    }
+                    break;
+                case EN_ALTERNATE:
+                    if (columnCount == 2) {
+                        if (columnIndex == 0) {
+                            xOffset = columnStartIPPosition;
+                            xScale = -1;
+                        } else {
+                            xOffset = columnEndIPPosition;
+                            xScale = 1;
+                        }
+                    } else {
+                        if (bindingOnStartEdge) {
+                            xOffset = columnEndIPPosition;
+                            xScale = 1;
+                        } else if (bindingOnEndEdge) {
+                            xOffset = columnStartIPPosition;
+                            xScale = -1;
+                        } else {
+                            xOffset = columnStartIPPosition;
+                            xScale = -1;
+                        }
+                    }
+                    break;
+                default:
+                    break;
+            }
+
+            if (isLeftToRight) {
+                xOffset += xScale * changeBarOffset;
+            } else {
+                xOffset -= xScale * changeBarOffset;
+            }
+
+            xOffset += getBeginOffset();
+
+            // Change bar area has 0 ipd, class xsl-absolute, no margin or padding
+            changeBarArea.setAreaClass(Area.CLASS_ABSOLUTE);
+            changeBarArea.setIPD(0);
+
+            BorderProps props = BorderProps.makeRectangular(
+                    changeBar.getStyle(), changeBarWidth, changeBar.getColor(),
+                    BorderProps.Mode.SEPARATE);
+
+            changeBarArea.addTrait(Trait.BORDER_START, props);
+            changeBarArea.addTrait(Trait.BORDER_END, props);
+
+            changeBarArea.setXOffset(xOffset);
+
+            int areaHeight = area.getAllocBPD();
+
+            if (area instanceof BlockParent) {
+                changeBarArea.setBPD(areaHeight);
+                changeBarArea.setYOffset(((BlockParent) area).getYOffset());
+                renderBlock(changeBarArea);
+
+            } else {
+                if (areaHeight > 0) {
+                    Property p = changeBar.getLineHeight().getOptimum(DummyPercentBaseContext.getInstance());
+                    int lineHeight = p.getLength().getValue();
+                    changeBarArea.setBPD(lineHeight);
+                    changeBarArea.setYOffset(areaHeight - lineHeight);
+                }
+                renderInlineBlock(new InlineBlock(changeBarArea));
+            }
+
+            // restore position on page
+            currentIPPosition = saveIP;
+            currentBPPosition = saveBP;
+        }
+    }
+
+    /**
+     * Returns 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;
+    }
+
+    /**
+     * Sets 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;
+    }
 }
index f8765f2809ba4c567f0664c30469f8dc5e596c2e..ecad6b500cab57f8b2944047744b67d75eb6ba83 100644 (file)
@@ -72,6 +72,7 @@ import org.apache.fop.area.inline.Container;
 import org.apache.fop.area.inline.ForeignObject;
 import org.apache.fop.area.inline.Image;
 import org.apache.fop.area.inline.InlineArea;
+import org.apache.fop.area.inline.InlineBlock;
 import org.apache.fop.area.inline.InlineBlockParent;
 import org.apache.fop.area.inline.InlineParent;
 import org.apache.fop.area.inline.InlineViewport;
@@ -692,6 +693,26 @@ public class XMLRenderer extends AbstractXMLRenderer {
         endElement("block");
     }
 
+    /** {@inheritDoc} */
+    @Override
+    protected void renderInlineBlock(InlineBlock inlineBlock) {
+        Block block = inlineBlock.getBlock();
+        atts.clear();
+        addAreaAttributes(block);
+        addTraitAttributes(block);
+        if (block.getXOffset() != 0) {
+            addAttribute("left-offset", block.getXOffset());
+        }
+        if (block.getYOffset() != 0) {
+            addAttribute("top-offset", block.getYOffset());
+        }
+        startElement("inlineblock", atts);
+        if (block.getChildAreas() != null) {
+           renderBlocks(null, block.getChildAreas());
+        }
+        endElement("inlineblock");
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -943,6 +964,4 @@ public class XMLRenderer extends AbstractXMLRenderer {
             addAttribute("reversed", "true");
         }
     }
-
-
 }
index e25556f9b527c193c43a5eb47cb05b6fcb70799e..e4865f2d2ece29923600cda72d7964ebdc62f6af 100644 (file)
@@ -67,6 +67,8 @@
   </xs:simpleType>
   <xs:simpleType name="borderStyle">
     <xs:restriction base="xs:string">
+      <xs:enumeration value="none"/>
+      <xs:enumeration value="hidden"/>
       <xs:enumeration value="solid"/>
       <xs:enumeration value="dotted"/>
       <xs:enumeration value="dashed"/>
@@ -79,6 +81,8 @@
   </xs:simpleType>
   <xs:simpleType name="ruleStyle">
     <xs:restriction base="xs:string">
+      <xs:enumeration value="none"/>
+      <xs:enumeration value="hidden"/>
       <xs:enumeration value="solid"/>
       <xs:enumeration value="dotted"/>
       <xs:enumeration value="dashed"/>
@@ -92,7 +96,7 @@
       <!-- TODO refine me: \w+ will not be good enough for CMYK color, for example
       <xs:pattern value="\((solid|dotted|dashed|double|groove|ridge|inset|outset),\w+,\d+(,collapse-(inner|outer))?"/>
       -->
-      <xs:pattern value="\((solid|dotted|dashed|double|groove|ridge|inset|outset),.+\)"/>
+      <xs:pattern value="\((none|hidden|solid|dotted|dashed|double|groove|ridge|inset|outset),.+\)"/>
     </xs:restriction>
   </xs:simpleType>
   <xs:simpleType name="lengthListType">
diff --git a/fop/test/layoutengine/standard-testcases/change-bar_block.xml b/fop/test/layoutengine/standard-testcases/change-bar_block.xml
new file mode 100644 (file)
index 0000000..9277343
--- /dev/null
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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$ -->
+<testcase>
+   <info>
+      <p>This test checks fo:change-bar-* on block elements.</p>
+   </info>
+   <fo>
+      <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+         <fo:layout-master-set>
+            <fo:simple-page-master page-height="145mm" page-width="210mm" margin="10mm"
+               master-name="master">
+               <fo:region-body column-count="2" column-gap="10mm"/>
+            </fo:simple-page-master>
+         </fo:layout-master-set>
+         <fo:page-sequence master-reference="master">
+            <fo:flow flow-name="xsl-region-body">
+               
+               <fo:block change-bar-style="solid" change-bar-color="red" change-bar-offset="3mm"
+                  change-bar-width="0.3mm">
+                  
+                  <fo:change-bar-begin change-bar-class="global"/>
+                  <fo:block id="red-01" color="red">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</fo:block>
+                  <fo:change-bar-begin change-bar-class="local-blue" change-bar-color="blue"
+                     change-bar-offset="2mm"/>
+                  <fo:block id="blue-01" color="blue">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="local-blue"/>
+                  <fo:change-bar-begin change-bar-class="local-green" change-bar-color="green"
+                     change-bar-offset="2mm"/>
+                  <fo:block id="green-01" color="green">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="local-green"/>
+                  <fo:block id="red-02" color="red">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="global"/>
+                  
+               </fo:block>
+            </fo:flow>
+         </fo:page-sequence>
+      </fo:root>
+   </fo>
+   <checks>
+      <eval expected="(solid,#ff0000,850)" xpath="//block[@prod-id='red-01']/block[1]/@border-start"/>
+      <eval expected="-9353" xpath="//block[@prod-id='red-01']/block[1]/@left-offset"/>
+      <eval expected="(solid,#ff0000,850)" xpath="//block[@prod-id='blue-01']/block[1]/@border-start"/>
+      <eval expected="-9353" xpath="//block[@prod-id='blue-01']/block[1]/@left-offset"/>
+      <eval expected="(solid,#0000ff,850)" xpath="//block[@prod-id='blue-01']/block[2]/@border-start"/>
+      <eval expected="-6519" xpath="//block[@prod-id='blue-01']/block[2]/@left-offset"/>
+      <eval expected="(solid,#ff0000,850)" xpath="//block[@prod-id='green-01']/block[1]/@border-start"/>
+      <eval expected="-9353" xpath="//block[@prod-id='green-01']/block[1]/@left-offset"/>
+      <eval expected="(solid,#008000,850)" xpath="//block[@prod-id='green-01']/block[2]/@border-start"/>
+      <eval expected="-6519" xpath="//block[@prod-id='green-01']/block[2]/@left-offset"/>
+      <eval expected="(solid,#ff0000,850)" xpath="//block[@prod-id='red-02']/block[1]/@border-start"/>
+      <eval expected="-9353" xpath="//block[@prod-id='red-02']/block[1]/@left-offset"/>
+   </checks>
+</testcase>
diff --git a/fop/test/layoutengine/standard-testcases/change-bar_inline.xml b/fop/test/layoutengine/standard-testcases/change-bar_inline.xml
new file mode 100644 (file)
index 0000000..d90500d
--- /dev/null
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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$ -->
+<testcase>
+   <info>
+      <p>This test checks fo:change-bar-* on inline elements.</p>
+   </info>
+   <fo>
+      <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+         <fo:layout-master-set>
+            <fo:simple-page-master page-height="145mm" page-width="210mm" margin="10mm"
+               master-name="master">
+               <fo:region-body column-count="2" column-gap="10mm"/>
+            </fo:simple-page-master>
+         </fo:layout-master-set>
+         <fo:page-sequence master-reference="master">
+            <fo:flow flow-name="xsl-region-body">
+
+               <fo:block change-bar-style="solid" change-bar-color="red" change-bar-offset="2mm"
+                  change-bar-width="0.3mm">
+
+                  <fo:block>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+                        <fo:change-bar-begin change-bar-class="red-01"/><fo:inline id="red-01"
+                        color="red">tempor incididunt</fo:inline><fo:change-bar-end
+                        change-bar-class="red-01"/> ut labore et dolore magna aliqua.</fo:block>
+
+                  <fo:block>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+                        <fo:change-bar-begin change-bar-class="red-02"/><fo:inline id="red-02"
+                        color="red">tempor incididunt</fo:inline><fo:change-bar-end
+                        change-bar-class="red-02"/> ut labore et <fo:change-bar-begin
+                        change-bar-color="blue" change-bar-offset="3mm" change-bar-class="blue-02"
+                        /><fo:inline id="blue-02" color="blue">dolore
+                        magna</fo:inline><fo:change-bar-end change-bar-class="blue-02"/>
+                     aliqua.</fo:block>
+
+                  <fo:block>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+                        <fo:change-bar-begin change-bar-class="red-03"/><fo:inline id="red-03-a"
+                        color="red">tempor incididunt ut </fo:inline><fo:change-bar-begin
+                        change-bar-color="blue" change-bar-offset="3mm" change-bar-class="blue-03"
+                        /><fo:inline id="blue-03" color="blue">labore</fo:inline><fo:change-bar-end
+                        change-bar-class="blue-03"/><fo:inline id="red-03-b" color="red"> et dolore
+                        magna</fo:inline><fo:change-bar-end change-bar-class="red-03"/>
+                     aliqua.</fo:block>
+
+               </fo:block>
+            </fo:flow>
+         </fo:page-sequence>
+      </fo:root>
+   </fo>
+   <checks>
+      <eval expected="(solid,#ff0000,850)" xpath="//inlineparent[@prod-id='red-01']/inlineblock[1]/@border-start"/>
+      <eval expected="-6519" xpath="//inlineparent[@prod-id='red-01']/inlineblock[1]/@left-offset"/>
+      <eval expected="(solid,#ff0000,850)" xpath="//inlineparent[@prod-id='red-02']/inlineblock[1]/@border-start"/>
+      <eval expected="-6519" xpath="//inlineparent[@prod-id='red-02']/inlineblock[1]/@left-offset"/>
+      <eval expected="(solid,#0000ff,850)" xpath="//inlineparent[@prod-id='blue-02']/inlineblock[1]/@border-start"/>
+      <eval expected="-9353" xpath="//inlineparent[@prod-id='blue-02']/inlineblock[1]/@left-offset"/>
+      <eval expected="(solid,#ff0000,850)" xpath="//inlineparent[@prod-id='red-03-a']/inlineblock[1]/@border-start"/>
+      <eval expected="-6519" xpath="//inlineparent[@prod-id='red-03-a']/inlineblock[1]/@left-offset"/>
+      <eval expected="(solid,#ff0000,850)" xpath="//inlineparent[@prod-id='blue-03']/inlineblock[1]/@border-start"/>
+      <eval expected="-6519" xpath="//inlineparent[@prod-id='blue-03']/inlineblock[1]/@left-offset"/>
+      <eval expected="(solid,#0000ff,850)" xpath="//inlineparent[@prod-id='blue-03']/inlineblock[2]/@border-start"/>
+      <eval expected="-9353" xpath="//inlineparent[@prod-id='blue-03']/inlineblock[2]/@left-offset"/>
+      <eval expected="(solid,#ff0000,850)" xpath="//inlineparent[@prod-id='red-03-b']/inlineblock[1]/@border-start"/>
+      <eval expected="-6519" xpath="//inlineparent[@prod-id='red-03-b']/inlineblock[1]/@left-offset"/>
+   </checks>
+</testcase>
diff --git a/fop/test/layoutengine/standard-testcases/change-bar_list.xml b/fop/test/layoutengine/standard-testcases/change-bar_list.xml
new file mode 100644 (file)
index 0000000..f1219fc
--- /dev/null
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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$ -->
+<testcase>
+   <info>
+      <p>This test checks fo:change-bar-* on list elements.</p>
+   </info>
+   <fo>
+      <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+         <fo:layout-master-set>
+            <fo:simple-page-master page-height="145mm" page-width="210mm" margin="10mm"
+               master-name="master">
+               <fo:region-body column-count="2" column-gap="10mm"/>
+            </fo:simple-page-master>
+         </fo:layout-master-set>
+         <fo:page-sequence master-reference="master">
+            <fo:flow flow-name="xsl-region-body">
+
+               <fo:block change-bar-style="solid" change-bar-color="red" change-bar-width="0.3mm"
+                  change-bar-offset="3mm">
+                  <fo:change-bar-begin change-bar-class="list-block"/>
+                  <fo:list-block id="list-block">
+                     <fo:change-bar-begin change-bar-class="list-item-first" change-bar-offset="2mm"
+                        change-bar-color="green"/>
+                     <fo:list-item id="list-item-first">
+                        <fo:list-item-label id="list-item-first-label" end-indent="label-end()">
+                           <fo:block>1</fo:block>
+                        </fo:list-item-label>
+                        <fo:list-item-body id="list-item-first-body" start-indent="body-start()">
+                           <fo:block>First</fo:block>
+                        </fo:list-item-body>
+                     </fo:list-item>
+                     <fo:change-bar-end change-bar-class="list-item-first"/>
+                     <fo:list-item id="list-item-second">
+                        <fo:change-bar-begin change-bar-class="list-item-second-label"
+                           change-bar-offset="2mm" change-bar-color="blue"/>
+                        <fo:list-item-label id="list-item-second-label" end-indent="label-end()">
+                           <fo:block>2</fo:block>
+                        </fo:list-item-label>
+                        <fo:change-bar-end change-bar-class="list-item-second-label"/>
+                        <fo:change-bar-begin change-bar-class="list-item-second-body" change-bar-offset="1mm"
+                           change-bar-color="magenta"/>
+                        <fo:list-item-body id="list-item-second-body" start-indent="body-start()">
+                           <fo:block>Second</fo:block>
+                        </fo:list-item-body>
+                        <fo:change-bar-end change-bar-class="list-item-second-body"/>
+                     </fo:list-item>
+                  </fo:list-block>
+                  <fo:change-bar-end change-bar-class="list-block"/>
+               </fo:block>
+            </fo:flow>
+         </fo:page-sequence>
+      </fo:root>
+   </fo>
+   <checks>
+      <!-- the first -->
+      <eval expected="(solid,#ff0000,850)" xpath="//block[@prod-id='list-item-first-label']/block[1]/block[1]/@border-start"/>
+      <eval expected="-9353" xpath="//block[@prod-id='list-item-first-label']/block[1]/block[1]/@left-offset"/>
+      <eval expected="(solid,#008000,850)" xpath="//block[@prod-id='list-item-first-label']/block[1]/block[2]/@border-start"/>
+      <eval expected="-6519" xpath="//block[@prod-id='list-item-first-label']/block[1]/block[2]/@left-offset"/>
+      <eval expected="(solid,#ff0000,850)" xpath="//block[@prod-id='list-item-first-body']/block[1]/block[1]/@border-start"/>
+      <eval expected="-9353" xpath="//block[@prod-id='list-item-first-body']/block[1]/block[1]/@left-offset"/>
+      <eval expected="(solid,#008000,850)" xpath="//block[@prod-id='list-item-first-body']/block[1]/block[2]/@border-start"/>
+      <eval expected="-6519" xpath="//block[@prod-id='list-item-first-body']/block[1]/block[2]/@left-offset"/>
+      <!-- the second -->
+      <eval expected="(solid,#ff0000,850)" xpath="//block[@prod-id='list-item-second-label']/block[1]/block[1]/@border-start"/>
+      <eval expected="-9353" xpath="//block[@prod-id='list-item-second-label']/block[1]/block[1]/@left-offset"/>
+      <eval expected="(solid,#0000ff,850)" xpath="//block[@prod-id='list-item-second-label']/block[1]/block[2]/@border-start"/>
+      <eval expected="-6519" xpath="//block[@prod-id='list-item-second-label']/block[1]/block[2]/@left-offset"/>
+      <eval expected="(solid,#ff0000,850)" xpath="//block[@prod-id='list-item-second-body']/block[1]/block[1]/@border-start"/>
+      <eval expected="-9353" xpath="//block[@prod-id='list-item-second-body']/block[1]/block[1]/@left-offset"/>
+      <eval expected="(solid,#ff00ff,850)" xpath="//block[@prod-id='list-item-second-body']/block[1]/block[2]/@border-start"/>
+      <eval expected="-3684" xpath="//block[@prod-id='list-item-second-body']/block[1]/block[2]/@left-offset"/>
+   </checks>
+</testcase>
diff --git a/fop/test/layoutengine/standard-testcases/change-bar_overlapped.xml b/fop/test/layoutengine/standard-testcases/change-bar_overlapped.xml
new file mode 100644 (file)
index 0000000..2406707
--- /dev/null
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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$ -->
+<testcase>
+   <info>
+      <p>This test checks fo:change-bar-* on list elements.</p>
+   </info>
+   <fo>
+      <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+         <fo:layout-master-set>
+            <fo:simple-page-master page-height="145mm" page-width="210mm" margin="10mm"
+               master-name="master">
+               <fo:region-body column-count="2" column-gap="10mm"/>
+            </fo:simple-page-master>
+         </fo:layout-master-set>
+         <fo:page-sequence master-reference="master">
+            <fo:flow flow-name="xsl-region-body">
+               
+               <fo:block change-bar-style="solid" change-bar-color="red" change-bar-offset="2mm"
+                  change-bar-width="0.3mm">
+                  
+                  <fo:block>
+                     <fo:change-bar-begin change-bar-class="first-half"/><fo:inline color="red"
+                        id="first-half">January February March April May </fo:inline><fo:change-bar-begin
+                           change-bar-class="summer" change-bar-color="green" change-bar-offset="1mm"
+                        /><fo:inline color="brown" id="june-inline">June</fo:inline><fo:change-bar-end
+                           change-bar-class="first-half"/><fo:inline color="green" id="summer"> July
+                              August</fo:inline><fo:change-bar-end change-bar-class="summer"/> September October
+                     November December</fo:block>
+                  
+                  <fo:change-bar-begin change-bar-class="first-half"/>
+                  <fo:block id="january">January</fo:block>
+                  <fo:block id="february">February</fo:block>
+                  <fo:block id="march">March</fo:block>
+                  <fo:wrapper color="red">
+                     <fo:block id="april">April</fo:block>
+                     <fo:block id="may">May</fo:block>
+                  </fo:wrapper>
+                  <fo:change-bar-begin change-bar-class="summer" change-bar-color="green"
+                     change-bar-offset="1mm"/>
+                  <fo:wrapper color="brown">
+                     <fo:block id="june-block">June</fo:block>
+                  </fo:wrapper>
+                  <fo:change-bar-end change-bar-class="first-half"/>
+                  <fo:wrapper color="red">
+                     <fo:block id="july">July</fo:block>
+                     <fo:block id="august">August</fo:block>
+                  </fo:wrapper>
+                  <fo:change-bar-end change-bar-class="summer"/>
+                  <fo:block id="september">September</fo:block>
+                  <fo:block id="october">October</fo:block>
+                  <fo:block id="november">November</fo:block>
+                  <fo:block id="december">December</fo:block>
+                  
+               </fo:block>
+            </fo:flow>
+         </fo:page-sequence>
+      </fo:root>
+   </fo>
+   <checks>
+      <!-- inline -->
+      <eval expected="(solid,#ff0000,850)" xpath="//inlineparent[@prod-id='first-half']/inlineblock[1]/@border-start"/>
+      <eval expected="-6519" xpath="//inlineparent[@prod-id='first-half']/inlineblock[1]/@left-offset"/>
+      <eval expected="(solid,#ff0000,850)" xpath="//inlineparent[@prod-id='june-inline']/inlineblock[1]/@border-start"/>
+      <eval expected="-6519" xpath="//inlineparent[@prod-id='june-inline']/inlineblock[1]/@left-offset"/>
+      <eval expected="(solid,#008000,850)" xpath="//inlineparent[@prod-id='june-inline']/inlineblock[2]/@border-start"/>
+      <eval expected="-3684" xpath="//inlineparent[@prod-id='june-inline']/inlineblock[2]/@left-offset"/>
+      <eval expected="(solid,#008000,850)" xpath="//lineArea[2]/inlineparent[@prod-id='summer']/inlineblock[1]/@border-start"/>
+      <eval expected="-3684" xpath="//lineArea[2]/inlineparent[@prod-id='summer']/inlineblock[1]/@left-offset"/>
+      <!-- block -->
+      <eval expected="(solid,#ff0000,850)" xpath="//block[@prod-id='may']/block[1]/@border-start"/>
+      <eval expected="-6519" xpath="//block[@prod-id='may']/block[1]/@left-offset"/>
+      <eval expected="(solid,#ff0000,850)" xpath="//block[@prod-id='june-block']/block[1]/@border-start"/>
+      <eval expected="-6519" xpath="//block[@prod-id='june-block']/block[1]/@left-offset"/>
+      <eval expected="(solid,#008000,850)" xpath="//block[@prod-id='june-block']/block[2]/@border-start"/>
+      <eval expected="-3684" xpath="//block[@prod-id='june-block']/block[2]/@left-offset"/>
+      <eval expected="(solid,#008000,850)" xpath="//block[@prod-id='july']/block[1]/@border-start"/>
+      <eval expected="-3684" xpath="//block[@prod-id='july']/block[1]/@left-offset"/>
+   </checks>
+</testcase>
diff --git a/fop/test/layoutengine/standard-testcases/change-bar_placement-rtl.xml b/fop/test/layoutengine/standard-testcases/change-bar_placement-rtl.xml
new file mode 100644 (file)
index 0000000..f9b5b19
--- /dev/null
@@ -0,0 +1,226 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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$ -->
+<testcase>
+   <info>
+      <p>This test checks fo:change-bar-start placement.</p>
+   </info>
+   <fo>
+      <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+         <fo:layout-master-set>
+            <fo:simple-page-master page-height="145mm" page-width="210mm" margin="10mm"
+               master-name="master">
+               <fo:region-body column-count="2" column-gap="10mm"/>
+            </fo:simple-page-master>
+         </fo:layout-master-set>
+         <fo:page-sequence master-reference="master" writing-mode="rl-tb">
+            <fo:flow flow-name="xsl-region-body">
+
+               <fo:block change-bar-style="solid" change-bar-color="red" change-bar-offset="2mm"
+                  change-bar-width="0.3mm">
+
+                  <fo:change-bar-begin change-bar-class="left" change-bar-placement="left"/>
+                  <fo:block id="page1-col1-left">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="left"/>
+
+                  <fo:change-bar-begin change-bar-class="right" change-bar-placement="right"/>
+                  <fo:block id="page1-col1-right">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="right"/>
+
+                  <fo:change-bar-begin change-bar-class="start" change-bar-placement="start"/>
+                  <fo:block id="page1-col1-start">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="start"/>
+
+                  <fo:change-bar-begin change-bar-class="end" change-bar-placement="end"/>
+                  <fo:block id="page1-col1-end">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="end"/>
+
+                  <fo:change-bar-begin change-bar-class="inside" change-bar-placement="inside"/>
+                  <fo:block id="page1-col1-inside">Lorem ipsum dolor sit amet, consectetur
+                     adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="inside"/>
+
+                  <fo:change-bar-begin change-bar-class="outside" change-bar-placement="outside"/>
+                  <fo:block id="page1-col1-outside">Lorem ipsum dolor sit amet, consectetur
+                     adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="outside"/>
+
+                  <fo:change-bar-begin change-bar-class="left" change-bar-placement="left"/>
+                  <fo:block id="page1-col2-left">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="left"/>
+
+                  <fo:change-bar-begin change-bar-class="right" change-bar-placement="right"/>
+                  <fo:block id="page1-col2-right">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="right"/>
+
+                  <fo:change-bar-begin change-bar-class="start" change-bar-placement="start"/>
+                  <fo:block id="page1-col2-start">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="start"/>
+
+                  <fo:change-bar-begin change-bar-class="end" change-bar-placement="end"/>
+                  <fo:block id="page1-col2-end">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="end"/>
+
+                  <fo:change-bar-begin change-bar-class="inside" change-bar-placement="inside"/>
+                  <fo:block id="page1-col2-inside">Lorem ipsum dolor sit amet, consectetur
+                     adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="inside"/>
+
+                  <fo:change-bar-begin change-bar-class="outside" change-bar-placement="outside"/>
+                  <fo:block id="page1-col2-outside">Lorem ipsum dolor sit amet, consectetur
+                     adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="outside"/>
+
+                  <fo:change-bar-begin change-bar-class="left" change-bar-placement="left"/>
+                  <fo:block id="page2-col1-left">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="left"/>
+
+                  <fo:change-bar-begin change-bar-class="right" change-bar-placement="right"/>
+                  <fo:block id="page2-col1-right">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="right"/>
+
+                  <fo:change-bar-begin change-bar-class="start" change-bar-placement="start"/>
+                  <fo:block id="page2-col1-start">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="start"/>
+
+                  <fo:change-bar-begin change-bar-class="end" change-bar-placement="end"/>
+                  <fo:block id="page2-col1-end">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="end"/>
+
+                  <fo:change-bar-begin change-bar-class="inside" change-bar-placement="inside"/>
+                  <fo:block id="page2-col1-inside">Lorem ipsum dolor sit amet, consectetur
+                     adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="inside"/>
+
+                  <fo:change-bar-begin change-bar-class="outside" change-bar-placement="outside"/>
+                  <fo:block id="page2-col1-outside">Lorem ipsum dolor sit amet, consectetur
+                     adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="outside"/>
+
+                  <fo:change-bar-begin change-bar-class="left" change-bar-placement="left"/>
+                  <fo:block id="page2-col2-left">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="left"/>
+
+                  <fo:change-bar-begin change-bar-class="right" change-bar-placement="right"/>
+                  <fo:block id="page2-col2-right">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="right"/>
+
+                  <fo:change-bar-begin change-bar-class="start" change-bar-placement="start"/>
+                  <fo:block id="page2-col2-start">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="start"/>
+
+                  <fo:change-bar-begin change-bar-class="end" change-bar-placement="end"/>
+                  <fo:block id="page2-col2-end">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="end"/>
+
+                  <fo:change-bar-begin change-bar-class="inside" change-bar-placement="inside"/>
+                  <fo:block id="page2-col2-inside">Lorem ipsum dolor sit amet, consectetur
+                     adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="inside"/>
+
+                  <fo:change-bar-begin change-bar-class="outside" change-bar-placement="outside"/>
+                  <fo:block id="page2-col2-outside">Lorem ipsum dolor sit amet, consectetur
+                     adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="outside"/>
+
+                  <fo:change-bar-begin change-bar-class="alternate" change-bar-placement="alternate"/>
+                  <fo:block id="page3-col1-alternate">Lorem ipsum dolor sit amet, consectetur
+                     adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:block id="page3-col2-alternate" break-before="column">Lorem ipsum dolor sit
+                     amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore
+                     et dolore magna aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="alternate"/>
+               </fo:block>
+            </fo:flow>
+         </fo:page-sequence>
+      </fo:root>
+   </fo>
+   <checks>
+      <eval expected="-6519" xpath="//block[@prod-id='page1-col1-left']/block[1]/@left-offset"/>
+      <eval expected="5669" xpath="//block[@prod-id='page1-col1-right']/block[1]/@left-offset"/>
+      <eval expected="-6519" xpath="//block[@prod-id='page1-col1-start']/block[1]/@left-offset"/>
+      <eval expected="5669" xpath="//block[@prod-id='page1-col1-end']/block[1]/@left-offset"/>
+      <eval expected="-6519" xpath="//block[@prod-id='page1-col1-inside']/block[1]/@left-offset"/>
+      <eval expected="-5669" xpath="//block[@prod-id='page1-col1-outside']/block[1]/@left-offset"/>
+
+      <eval expected="-6519" xpath="//block[@prod-id='page1-col2-left']/block[1]/@left-offset"/>
+      <eval expected="5669" xpath="//block[@prod-id='page1-col2-right']/block[1]/@left-offset"/>
+      <eval expected="-6519" xpath="//block[@prod-id='page1-col2-start']/block[1]/@left-offset"/>
+      <eval expected="5669" xpath="//block[@prod-id='page1-col2-end']/block[1]/@left-offset"/>
+      <eval expected="-6519" xpath="//block[@prod-id='page1-col2-inside']/block[1]/@left-offset"/>
+      <eval expected="-5669" xpath="//block[@prod-id='page1-col2-outside']/block[1]/@left-offset"/>
+
+      <eval expected="-6519" xpath="//block[@prod-id='page2-col1-left']/block[1]/@left-offset"/>
+      <eval expected="5669" xpath="//block[@prod-id='page2-col1-right']/block[1]/@left-offset"/>
+      <eval expected="-6519" xpath="//block[@prod-id='page2-col1-start']/block[1]/@left-offset"/>
+      <eval expected="5669" xpath="//block[@prod-id='page2-col1-end']/block[1]/@left-offset"/>
+      <eval expected="-6519" xpath="//block[@prod-id='page2-col1-inside']/block[1]/@left-offset"/>
+      <eval expected="-5669" xpath="//block[@prod-id='page2-col1-outside']/block[1]/@left-offset"/>
+
+      <eval expected="-6519" xpath="//block[@prod-id='page2-col2-left']/block[1]/@left-offset"/>
+      <eval expected="5669" xpath="//block[@prod-id='page2-col2-right']/block[1]/@left-offset"/>
+      <eval expected="-6519" xpath="//block[@prod-id='page2-col2-start']/block[1]/@left-offset"/>
+      <eval expected="5669" xpath="//block[@prod-id='page2-col2-end']/block[1]/@left-offset"/>
+      <eval expected="-6519" xpath="//block[@prod-id='page2-col2-inside']/block[1]/@left-offset"/>
+      <eval expected="-5669" xpath="//block[@prod-id='page2-col2-outside']/block[1]/@left-offset"/>
+
+      <eval expected="-5669" xpath="//block[@prod-id='page3-col1-alternate']/block[1]/@left-offset"/>
+      <eval expected="-5669" xpath="//block[@prod-id='page3-col2-alternate']/block[1]/@left-offset"/>
+   </checks>
+</testcase>
diff --git a/fop/test/layoutengine/standard-testcases/change-bar_placement.xml b/fop/test/layoutengine/standard-testcases/change-bar_placement.xml
new file mode 100644 (file)
index 0000000..82d4bd9
--- /dev/null
@@ -0,0 +1,226 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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$ -->
+<testcase>
+   <info>
+      <p>This test checks fo:change-bar-start placement.</p>
+   </info>
+   <fo>
+      <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+         <fo:layout-master-set>
+            <fo:simple-page-master page-height="145mm" page-width="210mm" margin="10mm"
+               master-name="master">
+               <fo:region-body column-count="2" column-gap="10mm"/>
+            </fo:simple-page-master>
+         </fo:layout-master-set>
+         <fo:page-sequence master-reference="master">
+            <fo:flow flow-name="xsl-region-body">
+
+               <fo:block change-bar-style="solid" change-bar-color="red" change-bar-offset="2mm"
+                  change-bar-width="0.3mm">
+
+                  <fo:change-bar-begin change-bar-class="left" change-bar-placement="left"/>
+                  <fo:block id="page1-col1-left">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="left"/>
+
+                  <fo:change-bar-begin change-bar-class="right" change-bar-placement="right"/>
+                  <fo:block id="page1-col1-right">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="right"/>
+
+                  <fo:change-bar-begin change-bar-class="start" change-bar-placement="start"/>
+                  <fo:block id="page1-col1-start">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="start"/>
+
+                  <fo:change-bar-begin change-bar-class="end" change-bar-placement="end"/>
+                  <fo:block id="page1-col1-end">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="end"/>
+
+                  <fo:change-bar-begin change-bar-class="inside" change-bar-placement="inside"/>
+                  <fo:block id="page1-col1-inside">Lorem ipsum dolor sit amet, consectetur
+                     adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="inside"/>
+
+                  <fo:change-bar-begin change-bar-class="outside" change-bar-placement="outside"/>
+                  <fo:block id="page1-col1-outside">Lorem ipsum dolor sit amet, consectetur
+                     adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="outside"/>
+
+                  <fo:change-bar-begin change-bar-class="left" change-bar-placement="left"/>
+                  <fo:block id="page1-col2-left">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="left"/>
+
+                  <fo:change-bar-begin change-bar-class="right" change-bar-placement="right"/>
+                  <fo:block id="page1-col2-right">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="right"/>
+
+                  <fo:change-bar-begin change-bar-class="start" change-bar-placement="start"/>
+                  <fo:block id="page1-col2-start">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="start"/>
+
+                  <fo:change-bar-begin change-bar-class="end" change-bar-placement="end"/>
+                  <fo:block id="page1-col2-end">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="end"/>
+
+                  <fo:change-bar-begin change-bar-class="inside" change-bar-placement="inside"/>
+                  <fo:block id="page1-col2-inside">Lorem ipsum dolor sit amet, consectetur
+                     adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="inside"/>
+
+                  <fo:change-bar-begin change-bar-class="outside" change-bar-placement="outside"/>
+                  <fo:block id="page1-col2-outside">Lorem ipsum dolor sit amet, consectetur
+                     adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="outside"/>
+
+                  <fo:change-bar-begin change-bar-class="left" change-bar-placement="left"/>
+                  <fo:block id="page2-col1-left">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="left"/>
+
+                  <fo:change-bar-begin change-bar-class="right" change-bar-placement="right"/>
+                  <fo:block id="page2-col1-right">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="right"/>
+
+                  <fo:change-bar-begin change-bar-class="start" change-bar-placement="start"/>
+                  <fo:block id="page2-col1-start">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="start"/>
+
+                  <fo:change-bar-begin change-bar-class="end" change-bar-placement="end"/>
+                  <fo:block id="page2-col1-end">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="end"/>
+
+                  <fo:change-bar-begin change-bar-class="inside" change-bar-placement="inside"/>
+                  <fo:block id="page2-col1-inside">Lorem ipsum dolor sit amet, consectetur
+                     adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="inside"/>
+
+                  <fo:change-bar-begin change-bar-class="outside" change-bar-placement="outside"/>
+                  <fo:block id="page2-col1-outside">Lorem ipsum dolor sit amet, consectetur
+                     adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="outside"/>
+
+                  <fo:change-bar-begin change-bar-class="left" change-bar-placement="left"/>
+                  <fo:block id="page2-col2-left">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="left"/>
+
+                  <fo:change-bar-begin change-bar-class="right" change-bar-placement="right"/>
+                  <fo:block id="page2-col2-right">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="right"/>
+
+                  <fo:change-bar-begin change-bar-class="start" change-bar-placement="start"/>
+                  <fo:block id="page2-col2-start">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="start"/>
+
+                  <fo:change-bar-begin change-bar-class="end" change-bar-placement="end"/>
+                  <fo:block id="page2-col2-end">Lorem ipsum dolor sit amet, consectetur adipiscing
+                     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="end"/>
+
+                  <fo:change-bar-begin change-bar-class="inside" change-bar-placement="inside"/>
+                  <fo:block id="page2-col2-inside">Lorem ipsum dolor sit amet, consectetur
+                     adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="inside"/>
+
+                  <fo:change-bar-begin change-bar-class="outside" change-bar-placement="outside"/>
+                  <fo:block id="page2-col2-outside">Lorem ipsum dolor sit amet, consectetur
+                     adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="outside"/>
+
+                  <fo:change-bar-begin change-bar-class="alternate" change-bar-placement="alternate"/>
+                  <fo:block id="page3-col1-alternate">Lorem ipsum dolor sit amet, consectetur
+                     adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+                     aliqua.</fo:block>
+                  <fo:block id="page3-col2-alternate" break-before="column">Lorem ipsum dolor sit
+                     amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore
+                     et dolore magna aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="alternate"/>
+               </fo:block>
+            </fo:flow>
+         </fo:page-sequence>
+      </fo:root>
+   </fo>
+   <checks>
+      <eval expected="-6519" xpath="//block[@prod-id='page1-col1-left']/block[1]/@left-offset"/>
+      <eval expected="5669" xpath="//block[@prod-id='page1-col1-right']/block[1]/@left-offset"/>
+      <eval expected="-6519" xpath="//block[@prod-id='page1-col1-start']/block[1]/@left-offset"/>
+      <eval expected="5669" xpath="//block[@prod-id='page1-col1-end']/block[1]/@left-offset"/>
+      <eval expected="-6519" xpath="//block[@prod-id='page1-col1-inside']/block[1]/@left-offset"/>
+      <eval expected="-5669" xpath="//block[@prod-id='page1-col1-outside']/block[1]/@left-offset"/>
+
+      <eval expected="-6519" xpath="//block[@prod-id='page1-col2-left']/block[1]/@left-offset"/>
+      <eval expected="5669" xpath="//block[@prod-id='page1-col2-right']/block[1]/@left-offset"/>
+      <eval expected="-6519" xpath="//block[@prod-id='page1-col2-start']/block[1]/@left-offset"/>
+      <eval expected="5669" xpath="//block[@prod-id='page1-col2-end']/block[1]/@left-offset"/>
+      <eval expected="-6519" xpath="//block[@prod-id='page1-col2-inside']/block[1]/@left-offset"/>
+      <eval expected="-5669" xpath="//block[@prod-id='page1-col2-outside']/block[1]/@left-offset"/>
+
+      <eval expected="-6519" xpath="//block[@prod-id='page2-col1-left']/block[1]/@left-offset"/>
+      <eval expected="5669" xpath="//block[@prod-id='page2-col1-right']/block[1]/@left-offset"/>
+      <eval expected="-6519" xpath="//block[@prod-id='page2-col1-start']/block[1]/@left-offset"/>
+      <eval expected="5669" xpath="//block[@prod-id='page2-col1-end']/block[1]/@left-offset"/>
+      <eval expected="-6519" xpath="//block[@prod-id='page2-col1-inside']/block[1]/@left-offset"/>
+      <eval expected="-5669" xpath="//block[@prod-id='page2-col1-outside']/block[1]/@left-offset"/>
+
+      <eval expected="-6519" xpath="//block[@prod-id='page2-col2-left']/block[1]/@left-offset"/>
+      <eval expected="5669" xpath="//block[@prod-id='page2-col2-right']/block[1]/@left-offset"/>
+      <eval expected="-6519" xpath="//block[@prod-id='page2-col2-start']/block[1]/@left-offset"/>
+      <eval expected="5669" xpath="//block[@prod-id='page2-col2-end']/block[1]/@left-offset"/>
+      <eval expected="-6519" xpath="//block[@prod-id='page2-col2-inside']/block[1]/@left-offset"/>
+      <eval expected="-5669" xpath="//block[@prod-id='page2-col2-outside']/block[1]/@left-offset"/>
+
+      <eval expected="-5669" xpath="//block[@prod-id='page3-col1-alternate']/block[1]/@left-offset"/>
+      <eval expected="-5669" xpath="//block[@prod-id='page3-col2-alternate']/block[1]/@left-offset"/>
+   </checks>
+</testcase>
diff --git a/fop/test/layoutengine/standard-testcases/change-bar_style.xml b/fop/test/layoutengine/standard-testcases/change-bar_style.xml
new file mode 100644 (file)
index 0000000..65203cf
--- /dev/null
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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$ -->
+<testcase>
+   <info>
+      <p>This test checks fo:change-bar-start style.</p>
+   </info>
+   <fo>
+      <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+         <fo:layout-master-set>
+            <fo:simple-page-master page-height="145mm" page-width="210mm" margin="10mm"
+               master-name="master">
+               <fo:region-body column-count="2" column-gap="10mm"/>
+            </fo:simple-page-master>
+         </fo:layout-master-set>
+         <fo:page-sequence master-reference="master">
+            <fo:flow flow-name="xsl-region-body">
+
+               <fo:block change-bar-color="red" change-bar-offset="2mm" change-bar-width="1mm">
+
+                  <fo:change-bar-begin change-bar-class="none" change-bar-style="none"/>
+                  <fo:block id="none">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
+                     do eiusmod tempor incididunt ut labore et dolore magna aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="none"/>
+
+                  <fo:change-bar-begin change-bar-class="hidden" change-bar-style="hidden"/>
+                  <fo:block id="hidden">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
+                     do eiusmod tempor incididunt ut labore et dolore magna aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="hidden"/>
+
+                  <fo:change-bar-begin change-bar-class="dotted" change-bar-style="dotted"/>
+                  <fo:block id="dotted">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
+                     do eiusmod tempor incididunt ut labore et dolore magna aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="dotted"/>
+
+                  <fo:change-bar-begin change-bar-class="dashed" change-bar-style="dashed"/>
+                  <fo:block id="dashed">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
+                     do eiusmod tempor incididunt ut labore et dolore magna aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="dashed"/>
+
+                  <fo:change-bar-begin change-bar-class="solid" change-bar-style="solid"/>
+                  <fo:block id="solid">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
+                     do eiusmod tempor incididunt ut labore et dolore magna aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="solid"/>
+
+                  <fo:change-bar-begin change-bar-class="double" change-bar-style="double"/>
+                  <fo:block id="double">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
+                     do eiusmod tempor incididunt ut labore et dolore magna aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="double"/>
+
+                  <fo:change-bar-begin change-bar-class="groove" change-bar-style="groove"/>
+                  <fo:block id="groove">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
+                     do eiusmod tempor incididunt ut labore et dolore magna aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="groove"/>
+
+                  <fo:change-bar-begin change-bar-class="ridge" change-bar-style="ridge"/>
+                  <fo:block id="ridge">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
+                     do eiusmod tempor incididunt ut labore et dolore magna aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="ridge"/>
+
+                  <fo:change-bar-begin change-bar-class="inset" change-bar-style="inset"/>
+                  <fo:block id="inset">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
+                     do eiusmod tempor incididunt ut labore et dolore magna aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="inset"/>
+
+                  <fo:change-bar-begin change-bar-class="outset" change-bar-style="outset"/>
+                  <fo:block id="outset">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
+                     do eiusmod tempor incididunt ut labore et dolore magna aliqua.</fo:block>
+                  <fo:change-bar-end change-bar-class="outset"/>
+               </fo:block>
+            </fo:flow>
+         </fo:page-sequence>
+      </fo:root>
+   </fo>
+   <checks>
+      <eval expected="(none,#ff0000,2834)" xpath="//block[@prod-id='none']/block[1]/@border-start"/>
+      <eval expected="(hidden,#ff0000,2834)" xpath="//block[@prod-id='hidden']/block[1]/@border-start"/>
+      <eval expected="(dotted,#ff0000,2834)" xpath="//block[@prod-id='dotted']/block[1]/@border-start"/>
+      <eval expected="(dashed,#ff0000,2834)" xpath="//block[@prod-id='dashed']/block[1]/@border-start"/>
+      <eval expected="(solid,#ff0000,2834)" xpath="//block[@prod-id='solid']/block[1]/@border-start"/>
+      <eval expected="(double,#ff0000,2834)" xpath="//block[@prod-id='double']/block[1]/@border-start"/>
+      <eval expected="(groove,#ff0000,2834)" xpath="//block[@prod-id='groove']/block[1]/@border-start"/>
+      <eval expected="(ridge,#ff0000,2834)" xpath="//block[@prod-id='ridge']/block[1]/@border-start"/>
+      <eval expected="(inset,#ff0000,2834)" xpath="//block[@prod-id='inset']/block[1]/@border-start"/>
+      <eval expected="(outset,#ff0000,2834)" xpath="//block[@prod-id='outset']/block[1]/@border-start"/>
+   </checks>
+</testcase>
diff --git a/fop/test/layoutengine/standard-testcases/change-bar_table.xml b/fop/test/layoutengine/standard-testcases/change-bar_table.xml
new file mode 100644 (file)
index 0000000..39bd4b8
--- /dev/null
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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$ -->
+<testcase>
+   <info>
+      <p>This test checks fo:change-bar-* on table elements.</p>
+   </info>
+   <fo>
+      <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+         <fo:layout-master-set>
+            <fo:simple-page-master page-height="145mm" page-width="210mm" margin="10mm"
+               master-name="master">
+               <fo:region-body column-count="2" column-gap="10mm"/>
+            </fo:simple-page-master>
+         </fo:layout-master-set>
+         <fo:page-sequence master-reference="master">
+            <fo:flow flow-name="xsl-region-body">
+
+               <fo:table change-bar-style="solid" change-bar-color="red" change-bar-offset="2mm"
+                  change-bar-width="0.3mm">
+                  <fo:table-header>
+                     <fo:change-bar-begin change-bar-class="headerRow" change-bar-offset="0.1mm"
+                        change-bar-color="green"/>
+                     <fo:table-row>
+                        <fo:table-cell id="header-row1-col1">
+                           <fo:block>header-row1-col1</fo:block>
+                        </fo:table-cell>
+                        <fo:table-cell id="header-row1-col2">
+                           <fo:block>header-row1-col2</fo:block>
+                        </fo:table-cell>
+                     </fo:table-row>
+                     <fo:change-bar-end change-bar-class="headerRow"/>
+                     <fo:table-row>
+                        <fo:change-bar-begin change-bar-class="headerCell" change-bar-color="blue"/>
+                        <fo:table-cell id="header-row2-col1">
+                           <fo:block>header-row2-col1</fo:block>
+                        </fo:table-cell>
+                        <fo:change-bar-end change-bar-class="headerCell"/>
+                        <fo:table-cell id="header-row2-col2">
+                           <fo:change-bar-begin change-bar-class="headerCellBlock"
+                              change-bar-offset="1mm"/>
+                           <fo:block>header-row2-col2</fo:block>
+                           <fo:change-bar-end change-bar-class="headerCellBlock"/>
+                        </fo:table-cell>
+                     </fo:table-row>
+                  </fo:table-header>
+                  <fo:change-bar-begin change-bar-class="footer"/>
+                  <fo:table-footer>
+                     <fo:table-row>
+                        <fo:change-bar-begin change-bar-class="footerRow" change-bar-offset="3mm"
+                           change-bar-color="green"/>
+                        <fo:table-cell id="footer-row1-col1">
+                           <fo:block>footer-row1-col1</fo:block>
+                        </fo:table-cell>
+                        <fo:change-bar-end change-bar-class="footerRow"/>
+                        <fo:table-cell id="footer-row1-col2">
+                           <fo:block>footer-row1-col2</fo:block>
+                        </fo:table-cell>
+                     </fo:table-row>
+                     <fo:table-row>
+                        <fo:table-cell id="footer-row2-col1">
+                           <fo:block>footer-row2-col1</fo:block>
+                        </fo:table-cell>
+                        <fo:table-cell id="footer-row2-col2">
+                           <fo:block>footer-row2-col2</fo:block>
+                        </fo:table-cell>
+                     </fo:table-row>
+                  </fo:table-footer>
+                  <fo:change-bar-end change-bar-class="footer"/>
+                  <fo:table-body>
+                     <fo:change-bar-begin change-bar-class="bodyRow"/>
+                     <fo:table-row>
+                        <fo:table-cell id="body-row1-col1">
+                           <fo:block>body-row1-col1</fo:block>
+                        </fo:table-cell>
+                        <fo:table-cell id="body-row1-col2">
+                           <fo:block>body-row1-col2</fo:block>
+                        </fo:table-cell>
+                     </fo:table-row>
+                     <fo:change-bar-end change-bar-class="bodyRow"/>
+                     <fo:table-row>
+                        <fo:change-bar-begin change-bar-class="bodyCell" change-bar-offset="0.1mm"
+                           change-bar-color="blue"/>
+                        <fo:table-cell id="body-row2-col1">
+                           <fo:block>body-row2-col1</fo:block>
+                        </fo:table-cell>
+                        <fo:change-bar-end change-bar-class="bodyCell"/>
+                        <fo:table-cell id="body-row2-col2">
+                           <fo:change-bar-begin change-bar-class="bodyCellBlock"
+                              change-bar-offset="1mm"/>
+                           <fo:block>body-row2-col2</fo:block>
+                           <fo:change-bar-end change-bar-class="bodyCellBlock"/>
+                        </fo:table-cell>
+                     </fo:table-row>
+                  </fo:table-body>
+               </fo:table>
+            </fo:flow>
+         </fo:page-sequence>
+      </fo:root>
+   </fo>
+   <checks>
+      <!-- header -->
+      <eval expected="(solid,#008000,850)" xpath="//block[@prod-id='header-row1-col1']/block[1]/block[1]/@border-start"/>
+      <eval expected="-1133" xpath="//block[@prod-id='header-row1-col1']/block[1]/block[1]/@left-offset"/>
+      <eval expected="(solid,#008000,850)" xpath="//block[@prod-id='header-row1-col2']/block[1]/block[1]/@border-start"/>
+      <eval expected="-1133" xpath="//block[@prod-id='header-row1-col2']/block[1]/block[1]/@left-offset"/>      
+      <eval expected="(solid,#0000ff,850)" xpath="//block[@prod-id='header-row2-col1']/block[1]/block[1]/@border-start"/>
+      <eval expected="-6519" xpath="//block[@prod-id='header-row2-col1']/block[1]/block[1]/@left-offset"/>
+      <eval expected="(solid,#ff0000,850)" xpath="//block[@prod-id='header-row2-col2']/block[1]/block[1]/@border-start"/>
+      <eval expected="-3684" xpath="//block[@prod-id='header-row2-col2']/block[1]/block[1]/@left-offset"/>
+      <!-- body -->
+      <eval expected="(solid,#ff0000,850)" xpath="//block[@prod-id='body-row1-col1']/block[1]/block[1]/@border-start"/>
+      <eval expected="-6519" xpath="//block[@prod-id='body-row1-col1']/block[1]/block[1]/@left-offset"/>
+      <eval expected="(solid,#ff0000,850)" xpath="//block[@prod-id='body-row1-col2']/block[1]/block[1]/@border-start"/>
+      <eval expected="-6519" xpath="//block[@prod-id='body-row1-col2']/block[1]/block[1]/@left-offset"/>
+      <eval expected="(solid,#0000ff,850)" xpath="//block[@prod-id='body-row2-col1']/block[1]/block[1]/@border-start"/>
+      <eval expected="-1133" xpath="//block[@prod-id='body-row2-col1']/block[1]/block[1]/@left-offset"/>
+      <eval expected="(solid,#ff0000,850)" xpath="//block[@prod-id='body-row2-col2']/block[1]/block[1]/@border-start"/>
+      <eval expected="-3684" xpath="//block[@prod-id='body-row2-col2']/block[1]/block[1]/@left-offset"/>
+      <!-- footer -->
+      <eval expected="(solid,#ff0000,850)" xpath="//block[@prod-id='footer-row1-col1']/block[1]/block[1]/@border-start"/>
+      <eval expected="-6519" xpath="//block[@prod-id='footer-row1-col1']/block[1]/block[1]/@left-offset"/>
+      <eval expected="(solid,#008000,850)" xpath="//block[@prod-id='footer-row1-col1']/block[1]/block[2]/@border-start"/>
+      <eval expected="-9353" xpath="//block[@prod-id='footer-row1-col1']/block[1]/block[2]/@left-offset"/>
+      <eval expected="(solid,#ff0000,850)" xpath="//block[@prod-id='footer-row1-col2']/block[1]/block[1]/@border-start"/>
+      <eval expected="-6519" xpath="//block[@prod-id='footer-row1-col2']/block[1]/block[1]/@left-offset"/>
+      <eval expected="(solid,#ff0000,850)" xpath="//block[@prod-id='footer-row2-col1']/block[1]/block[1]/@border-start"/>
+      <eval expected="-6519" xpath="//block[@prod-id='footer-row2-col1']/block[1]/block[1]/@left-offset"/>
+      <eval expected="(solid,#ff0000,850)" xpath="//block[@prod-id='footer-row2-col2']/block[1]/block[1]/@border-start"/>
+      <eval expected="-6519" xpath="//block[@prod-id='footer-row2-col2']/block[1]/block[1]/@left-offset"/>
+   </checks>
+</testcase>