]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Merged trunk@1354651
authorPeter Hancock <phancock@apache.org>
Fri, 29 Jun 2012 11:22:42 +0000 (11:22 +0000)
committerPeter Hancock <phancock@apache.org>
Fri, 29 Jun 2012 11:22:42 +0000 (11:22 +0000)
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_RoundedCorners@1355321 13f79535-47bb-0310-9956-ffa450edef68

29 files changed:
1  2 
src/documentation/intermediate-format-ng/fop-intermediate-format-ng-content.xsd
src/java/org/apache/fop/afp/AFPResourceManager.java
src/java/org/apache/fop/area/Trait.java
src/java/org/apache/fop/fo/Constants.java
src/java/org/apache/fop/fo/FOPropertyMapping.java
src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java
src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java
src/java/org/apache/fop/layoutmgr/TraitSetter.java
src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java
src/java/org/apache/fop/render/afp/AFPDocumentHandler.java
src/java/org/apache/fop/render/afp/AFPImageHandler.java
src/java/org/apache/fop/render/afp/AFPImageHandlerGraphics2D.java
src/java/org/apache/fop/render/afp/AFPImageHandlerRawJPEG.java
src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java
src/java/org/apache/fop/render/afp/AFPPainter.java
src/java/org/apache/fop/render/afp/AbstractAFPImageHandlerRawStream.java
src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java
src/java/org/apache/fop/render/intermediate/BorderPainter.java
src/java/org/apache/fop/render/intermediate/IFPainter.java
src/java/org/apache/fop/render/intermediate/IFParser.java
src/java/org/apache/fop/render/intermediate/IFRenderer.java
src/java/org/apache/fop/render/intermediate/IFSerializer.java
src/java/org/apache/fop/render/java2d/Java2DPainter.java
src/java/org/apache/fop/render/pcl/PCLPainter.java
src/java/org/apache/fop/render/pdf/PDFPainter.java
src/java/org/apache/fop/render/ps/PSBorderPainter.java
src/java/org/apache/fop/render/ps/PSPainter.java
src/java/org/apache/fop/traits/BorderProps.java
src/sandbox/org/apache/fop/render/svg/SVGPainter.java

index 85748ac333a3b26d8c567b51c391c678bf1976b0,eae7a88af4f929c07ee385a43b83f4b03f104011..5e58c820837212f45eca66cb0a5468f674761152
    <xs:attributeGroup name="rectAtts">
      <xs:attributeGroup ref="mf:posAtts"/>
      <xs:attributeGroup ref="mf:sizeAtts"/>
-     <xs:attribute name="start" type="mf:borderDef"/>
-     <xs:attribute name="end" type="mf:borderDef"/>
-     <xs:attribute name="before" type="mf:borderDef"/>
-     <xs:attribute name="after" type="mf:borderDef"/>
 +  </xs:attributeGroup>
 +   <xs:attributeGroup name="borderAtts">
++    <xs:attribute name="left" type="mf:borderDef"/>
++    <xs:attribute name="right" type="mf:borderDef"/>
++    <xs:attribute name="top" type="mf:borderDef"/>
++    <xs:attribute name="bottom" type="mf:borderDef"/>
    </xs:attributeGroup>
    <xs:attributeGroup name="fillAtts">
      <xs:attribute name="fill" type="xs:string" default="none"/>
index de55430849d46570057f3c4513b89a643b154f7d,89341588c60712125a8d157e332405604964f12e..9544f76c75bc2b73eb8a43db0ca8065880c5a2e9
@@@ -61,9 -65,13 +65,9 @@@ public class AFPResourceManager 
      /** Maintain a reference count of instream objects for referencing purposes */
      private int instreamObjectCount = 0;
  
 -    /** a mapping of resourceInfo --> include name */
 -    private final Map<AFPResourceInfo, String> includeNameMap
 -        = new java.util.HashMap<AFPResourceInfo, String>();
 -
 -    /** a mapping of resourceInfo --> page segment name */
 -    private Map<AFPResourceInfo, String> pageSegmentMap
 -        = new java.util.HashMap<AFPResourceInfo, String>();
 +    /** Mapping of resourceInfo to AbstractCachedObject */
-     private final Map/*<AFPResourceInfo, AbstractCachedObject>*/ includeObjectCache
-     = new java.util.HashMap()/*<AFPResourceInfo,String>*/;
++    private final Map<AFPResourceInfo, AbstractCachedObject> includeObjectCache
++            = new java.util.HashMap<AFPResourceInfo, AbstractCachedObject>();
  
      private AFPResourceLevelDefaults resourceLevelDefaults = new AFPResourceLevelDefaults();
  
          streamer.setDefaultResourceGroupFilePath(filePath);
      }
  
 -
 -        String objectName = includeNameMap.get(resourceInfo);
 -        if (objectName != null) {
 -            // an existing data resource so reference it by adding an include to the current page
 -            includeObject(dataObjectInfo, objectName);
 -            return true;
 -        }
 -
 -        objectName = pageSegmentMap.get(resourceInfo);
 -        if (objectName != null) {
 -            // an existing data resource so reference it by adding an include to the current page
 -            includePageSegment(dataObjectInfo, objectName);
 -            return true;
 -        }
 -        return false;
+     /**
+      * Tries to create an include of a data object that has been previously added to the
+      * AFP data stream. If no such object was available, the method returns false which serves
+      * as a signal that the object has to be created.
+      * @param dataObjectInfo the data object info
+      * @return true if the inclusion succeeded, false if the object was not available
+      * @throws IOException thrown if an I/O exception of some sort has occurred.
+      */
+     public boolean tryIncludeObject(AFPDataObjectInfo dataObjectInfo) throws IOException {
+         AFPResourceInfo resourceInfo = dataObjectInfo.getResourceInfo();
+         updateResourceInfoUri(resourceInfo);
++        return includeCachedObject(resourceInfo, dataObjectInfo.getObjectAreaInfo());
+     }
      /**
       * Creates a new data object in the AFP datastream
       *
  
              // add data object into its resource group destination
              resourceGroup.addObject(namedObj);
--
 -            // create the include object
 -            String objectName = namedObj.getName();
 -            if (usePageSegment) {
 -                includePageSegment(dataObjectInfo, objectName);
 -                pageSegmentMap.put(resourceInfo, objectName);
 -            } else {
 -                includeObject(dataObjectInfo, objectName);
 -                // record mapping of resource info to data object resource name
 -                includeNameMap.put(resourceInfo, objectName);
 -            }
 +            includeObject(namedObj, dataObjectInfo);
          } else {
              // not to be included so inline data object directly into the current page
              dataStream.getCurrentPage().addObject(namedObj);
          resourceInfo.setName(resourceName);
          resourceInfo.setUri(uri.toASCIIString());
  
 -        String objectName = includeNameMap.get(resourceInfo);
 -        if (objectName == null) {
 +        AbstractCachedObject cachedObject = (AbstractCachedObject)
 +                includeObjectCache.get(resourceInfo);
-         if (cachedObject == null ) {
++        if (cachedObject == null) {
              if (log.isDebugEnabled()) {
                  log.debug("Adding included resource: " + resourceName);
              }
          }
      }
  
 -        String resource = includeNameMap.get(resourceInfo);
 -        if (resource == null) {
+     /**
+      * Creates an included resource extracting the named resource from an external source.
+      * @param resourceName the name of the resource
+      * @param uri the URI for the resource
+      * @param accessor resource accessor to access the resource with
+      * @throws IOException if an I/O error occurs while loading the resource
+      */
+     public void createIncludedResourceFromExternal(final String resourceName,
+             final URI uri, final ResourceAccessor accessor) throws IOException {
+         AFPResourceLevel resourceLevel = new AFPResourceLevel(AFPResourceLevel.PRINT_FILE);
+         AFPResourceInfo resourceInfo = new AFPResourceInfo();
+         resourceInfo.setLevel(resourceLevel);
+         resourceInfo.setName(resourceName);
+         resourceInfo.setUri(uri.toASCIIString());
 -
 -            includeNameMap.put(resourceInfo, resourceName);
 -
++        AbstractCachedObject cachedObject = (AbstractCachedObject)
++                includeObjectCache.get(resourceInfo);
++        
++        if (cachedObject == null) {
+             ResourceGroup resourceGroup = streamer.getResourceGroup(resourceLevel);
+             //resourceObject delegates write commands to copyNamedResource()
+             //The included resource may already be wrapped in a resource object
+             AbstractNamedAFPObject resourceObject = new AbstractNamedAFPObject(null) {
+                 @Override
+                 protected void writeContent(OutputStream os) throws IOException {
+                     InputStream inputStream = null;
+                     try {
+                         inputStream = accessor.createInputStream(uri);
+                         BufferedInputStream bin = new BufferedInputStream(inputStream);
+                         AFPResourceUtil.copyNamedResource(resourceName, bin, os);
+                     } finally {
+                         IOUtils.closeQuietly(inputStream);
+                     }
+                 }
+                 //bypass super.writeStart
+                 @Override
+                 protected void writeStart(OutputStream os) throws IOException { }
+                 //bypass super.writeEnd
+                 @Override
+                 protected void writeEnd(OutputStream os) throws IOException { }
+             };
+             resourceGroup.addObject(resourceObject);
++            cachedObject = new CachedObject(resourceName, null);
++            includeObjectCache.put(resourceInfo, cachedObject);
+         }
+     }
      /**
       * Sets resource level defaults. The existing defaults over merged with the ones passed in
       * as parameter.
index 9e9d576c320221c57815867e7368a62bdde61080,65320fd4851be1c0a38b3ecb6870751c173ad686..cd0d4becfe1b5097f52a20f83d13fd4fb1aeff76
@@@ -49,161 -54,123 +54,124 @@@ public final class Trait implements Ser
       * Internal link trait.
       * Contains the PageViewport key and the PROD_ID of the target area
       */
-     public static final Integer INTERNAL_LINK = new Integer(1);
+     public static final Integer INTERNAL_LINK = 1;
  
-     /**
-      * External link. A URL link to an external resource.
-      */
-     public static final Integer EXTERNAL_LINK = new Integer(2);
+     /** * External link. A URL link to an external resource. */
+     public static final Integer EXTERNAL_LINK = 2;
  
-     /**
-      * The font triplet for the current font.
-      */
-     public static final Integer FONT = new Integer(3);
+     /** The font triplet for the current font. */
+     public static final Integer FONT = 3;
  
-     /**
-      * Font size for the current font.
-      */
-     public static final Integer FONT_SIZE = new Integer(4);
+     /** Font size for the current font. */
+     public static final Integer FONT_SIZE = 4;
  
-     /**
-      * The current color.
-      */
-     public static final Integer COLOR = new Integer(7);
+     /** The current color. */
+     public static final Integer COLOR = 7;
  
-     /**
-      * The ID of the FO that produced an area.
-      */
-     public static final Integer PROD_ID = new Integer(8);
+     /** The ID of the FO that produced an area. */
+     public static final Integer PROD_ID = 8;
  
-     /**
-      * Background trait for an area.
-      */
-     public static final Integer BACKGROUND = new Integer(9);
+     /** Background trait for an area. */
+     public static final Integer BACKGROUND = 9;
  
-     /**
-      * Underline trait used when rendering inline parent.
-      */
-     public static final Integer UNDERLINE = new Integer(10);
+     /** Underline trait used when rendering inline parent. */
+     public static final Integer UNDERLINE = 10;
  
-     /**
-      * Overline trait used when rendering inline parent.
-      */
-     public static final Integer OVERLINE = new Integer(11);
+     /** Overline trait used when rendering inline parent. */
+     public static final Integer OVERLINE = 11;
  
-     /**
-      * Linethrough trait used when rendering inline parent.
-      */
-     public static final Integer LINETHROUGH = new Integer(12);
+     /** Linethrough trait used when rendering inline parent. */
+     public static final Integer LINETHROUGH = 12;
  
-     /**
-      * Shadow offset.
-      */
+     /** Shadow offset. */
      //public static final Integer OFFSET = new Integer(13);
  
-     /**
-      * The shadow for text.
-      */
+     /** The shadow for text. */
      //public static final Integer SHADOW = new Integer(14);
  
-     /**
-      * The border start.
-      */
-     public static final Integer BORDER_START = new Integer(15);
+     /** The border start. */
+     public static final Integer BORDER_START = 15;
  
-     /**
-      * The border end.
-      */
-     public static final Integer BORDER_END = new Integer(16);
+     /** The border end. */
+     public static final Integer BORDER_END = 16;
  
-     /**
-      * The border before.
-      */
-     public static final Integer BORDER_BEFORE = new Integer(17);
+     /** The border before. */
+     public static final Integer BORDER_BEFORE = 17;
  
-     /**
-      * The border after.
-      */
-     public static final Integer BORDER_AFTER = new Integer(18);
+     /** The border after. */
+     public static final Integer BORDER_AFTER = 18;
  
-     /**
-      * The padding start.
-      */
-     public static final Integer PADDING_START = new Integer(19);
+     /** The padding start. */
+     public static final Integer PADDING_START = 19;
  
-     /**
-      * The padding end.
-      */
-     public static final Integer PADDING_END = new Integer(20);
+     /** The padding end. */
+     public static final Integer PADDING_END = 20;
  
-     /**
-      * The padding before.
-      */
-     public static final Integer PADDING_BEFORE = new Integer(21);
+     /** The padding before. */
+     public static final Integer PADDING_BEFORE = 21;
  
-     /**
-      * The padding after.
-      */
-     public static final Integer PADDING_AFTER = new Integer(22);
+     /** The padding after. */
+     public static final Integer PADDING_AFTER = 22;
  
-     /**
-      * The space start.
-      */
-     public static final Integer SPACE_START = new Integer(23);
+     /** The space start. */
+     public static final Integer SPACE_START = 23;
  
-     /**
-      * The space end.
-      */
-     public static final Integer SPACE_END  = new Integer(24);
+     /** The space end. */
+     public static final Integer SPACE_END  = 24;
  
-     /**
-      * break before
-      */
+     /** break before */
      //public static final Integer BREAK_BEFORE = new Integer(25);
  
-     /**
-      * break after
-      */
+     /** break after */
      //public static final Integer BREAK_AFTER = new Integer(26);
  
-     /**
-      * The start-indent trait.
-      */
-     public static final Integer START_INDENT = new Integer(27);
+     /** The start-indent trait. */
+     public static final Integer START_INDENT = 27;
  
-     /**
-      * The end-indent trait.
-      */
-     public static final Integer END_INDENT  = new Integer(28);
+     /** The end-indent trait. */
+     public static final Integer END_INDENT  = 28;
  
      /** The space-before trait. */
-     public static final Integer SPACE_BEFORE  = new Integer(29);
+     public static final Integer SPACE_BEFORE  = 29;
  
      /** The space-after trait. */
-     public static final Integer SPACE_AFTER  = new Integer(30);
+     public static final Integer SPACE_AFTER  = 30;
  
      /** The is-reference-area trait. */
-     public static final Integer IS_REFERENCE_AREA = new Integer(31);
+     public static final Integer IS_REFERENCE_AREA = 31;
  
      /** The is-viewport-area trait. */
-     public static final Integer IS_VIEWPORT_AREA = new Integer(32);
+     public static final Integer IS_VIEWPORT_AREA = 32;
  
      /** Blinking trait used when rendering inline parent. */
-     public static final Integer BLINK = new Integer(33);
+     public static final Integer BLINK = 33;
  
      /** Trait for color of underline decorations when rendering inline parent. */
-     public static final Integer UNDERLINE_COLOR = new Integer(34);
+     public static final Integer UNDERLINE_COLOR = 34;
      /** Trait for color of overline decorations when rendering inline parent. */
-     public static final Integer OVERLINE_COLOR = new Integer(35);
+     public static final Integer OVERLINE_COLOR = 35;
      /** Trait for color of linethrough decorations when rendering inline parent. */
-     public static final Integer LINETHROUGH_COLOR = new Integer(36);
+     public static final Integer LINETHROUGH_COLOR = 36;
+     /** For navigation in the document structure. */
+     public static final Integer STRUCTURE_TREE_ELEMENT = 37;
  
-     /** The ptr trait. Used for accessibility   */
-     public static final Integer PTR = new Integer(37);
+     /** writing mode trait */
+     public static final Integer WRITING_MODE = 38;
+     /** inline progression direction trait */
+     public static final Integer INLINE_PROGRESSION_DIRECTION = 39;
+     /** block progression direction trait */
+     public static final Integer BLOCK_PROGRESSION_DIRECTION = 40;
+     /** column progression direction trait */
+     public static final Integer COLUMN_PROGRESSION_DIRECTION = 41;
+     /** shift direction trait */
+     public static final Integer SHIFT_DIRECTION = 42;
  
 +
      /** Maximum value used by trait keys */
-     public static final int MAX_TRAIT_KEY = 38;
+     public static final int MAX_TRAIT_KEY = 42;
  
      private static final TraitInfo[] TRAIT_INFO = new TraitInfo[MAX_TRAIT_KEY + 1];
  
index d9b0f252721fd005da7d216054b6aba3ee20a2ad,2d10dcdd9fb0154cd17cba7affee7a2db1d9d1bc..324a470f5fe6f6821a11bcb47486ef57a1f73a3d
@@@ -777,32 -775,18 +775,41 @@@ public interface Constants 
       * Property constant - FOP proprietary: alternative text for e-g and i-f-o.
       * Used for accessibility.
       */
-     int PR_X_ALT_TEXT = 275;
+     int PR_X_ALT_TEXT = 274;
+     /** Property constant - FOP proprietary prototype (in XSL-FO 2.0 Requirements) */
+     int PR_X_XML_BASE = 275;
++
 +
 +    /** Property constant FOP proprietary*/
 +    int PR_X_BORDER_BEFORE_RADIUS_START = 276;
 +
 +    /** Property constant FOP proprietary*/
 +    int PR_X_BORDER_BEFORE_RADIUS_END = 277;
 +
 +    /** Property constant FOP proprietary*/
 +    int PR_X_BORDER_AFTER_RADIUS_START = 278;
 +    /** Property constant FOP proprietary*/
 +    int PR_X_BORDER_AFTER_RADIUS_END = 279;
 +
 +    /** Property constant FOP proprietary*/
 +    int PR_X_BORDER_START_RADIUS_START = 280;
 +    /** Property constant FOP proprietary*/
 +    int PR_X_BORDER_START_RADIUS_END = 281;
 +    /** Property constant FOP proprietary*/
 +    int PR_X_BORDER_END_RADIUS_START = 282;
 +    /** Property constant FOP proprietary*/
 +    int PR_X_BORDER_END_RADIUS_END = 283;
 +    /** Property constant FOP proprietary*/
 +    int PR_X_BORDER_RADIUS = 284;
+     /**
+      * Property constant - FOP proprietary extension (see NumberConverter) used
+      * to perform additional control over number conversion when generating page
+      * numbers.
+      */
 -    int PR_X_NUMBER_CONVERSION_FEATURES = 276;
 -
++    int PR_X_NUMBER_CONVERSION_FEATURES = 285;
++    
      /** Number of property constants defined */
-     int PROPERTY_COUNT = 284;
 -    int PROPERTY_COUNT = 276;
++    int PROPERTY_COUNT = 285;
  
      // compound property constants
  
index 3b4b818b5c78c111dbd3686027b02913760e58dd,0e7f3d9789302dd276150ce727bfdaa0219aae72..050da71bbe259fd4f8ed64fde36b53a7a6679adb
@@@ -178,21 -170,7 +180,21 @@@ public class CommonBorderPaddingBackgro
              }
          }
  
-         /** {@inheritDoc} */
 +        /**
 +         * @return the border-*-start-radius
 +         */
 +        public CondLengthProperty getRadiusStart() {
 +            return this.radiusStart;
 +        }
 +
 +        /**
 +         * @return the border-*-end-radius
 +         */
 +        public CondLengthProperty getRadiusEnd() {
 +            return this.radiusEnd;
 +        }
 +
+         @Override
          public String toString() {
              StringBuffer sb = new StringBuffer("BorderInfo");
              sb.append(" {");
              if (this == obj) {
                  return true;
              }
 -            if (!(obj instanceof BorderInfo)) {
 -                return false;
 +            if (obj instanceof BorderInfo) {
 +                BorderInfo bi = (BorderInfo)obj;
 +                return (this.mColor == bi.mColor
 +                        && this.mStyle == bi.mStyle
 +                        && this.mWidth == bi.mWidth
 +                        && this.radiusStart == bi.radiusStart
 +                        && this.radiusEnd == bi.radiusEnd);
              }
-             return false;
+             BorderInfo other = (BorderInfo) obj;
+             return CompareUtil.equal(mColor, other.mColor)
+                     && mStyle == other.mStyle
+                     && CompareUtil.equal(mWidth, other.mWidth);
          }
  
-         /** {@inheritDoc} */
+         @Override
          public int hashCode() {
              if (this.hash == -1) {
                  int hash = 17;
       * @return a CommonBorderPaddingBackground instance (cached if possible)
       * @throws PropertyException in case of an error
       */
--    public static CommonBorderPaddingBackground getInstance(PropertyList pList)
-     throws PropertyException {
-         CommonBorderPaddingBackground newInstance
-         = new CommonBorderPaddingBackground(pList);
 -        throws PropertyException {
++    public static CommonBorderPaddingBackground getInstance(PropertyList pList) throws PropertyException {
+         CommonBorderPaddingBackground newInstance = new CommonBorderPaddingBackground(pList);
          CommonBorderPaddingBackground cachedInstance = null;
          /* if padding-* and background-position-* resolve to absolute lengths
           * the whole instance can be cached */
       */
      public int getBPPaddingAndBorder(boolean discard, PercentBaseContext context) {
          return getPaddingBefore(discard, context) + getPaddingAfter(discard, context)
 -               + getBorderBeforeWidth(discard) + getBorderAfterWidth(discard);
 +        + getBorderBeforeWidth(discard) + getBorderAfterWidth(discard);
      }
  
-     /** {@inheritDoc} */
+     @Override
      public String toString() {
          return "CommonBordersAndPadding (Before, After, Start, End):\n"
 -            + "Borders: (" + getBorderBeforeWidth(false) + ", " + getBorderAfterWidth(false) + ", "
 -            + getBorderStartWidth(false) + ", " + getBorderEndWidth(false) + ")\n"
 -            + "Border Colors: (" + getBorderColor(BEFORE) + ", " + getBorderColor(AFTER) + ", "
 -            + getBorderColor(START) + ", " + getBorderColor(END) + ")\n"
 -            + "Padding: (" + getPaddingBefore(false, null) + ", " + getPaddingAfter(false, null)
 -            + ", " + getPaddingStart(false, null) + ", " + getPaddingEnd(false, null) + ")\n";
 +        + "Borders: (" + getBorderBeforeWidth(false) + ", " + getBorderAfterWidth(false) + ", "
 +        + getBorderStartWidth(false) + ", " + getBorderEndWidth(false) + ")\n"
 +        + "Border Colors: (" + getBorderColor(BEFORE) + ", " + getBorderColor(AFTER) + ", "
 +        + getBorderColor(START) + ", " + getBorderColor(END) + ")\n"
 +        + "Padding: (" + getPaddingBefore(false, null) + ", " + getPaddingAfter(false, null)
 +        + ", " + getPaddingStart(false, null) + ", " + getPaddingEnd(false, null) + ")\n";
      }
  
      /**
          if (this == obj) {
              return true;
          }
 -        if (!(obj instanceof CommonBorderPaddingBackground)) {
 +        if (obj instanceof CommonBorderPaddingBackground) {
 +            CommonBorderPaddingBackground cbpb = (CommonBorderPaddingBackground)obj;
 +            return (this.backgroundAttachment == cbpb.backgroundAttachment
 +                    && this.backgroundColor == cbpb.backgroundColor
 +                    && this.backgroundImage.equals(cbpb.backgroundImage)
 +                    && this.backgroundPositionHorizontal == cbpb.backgroundPositionHorizontal
 +                    && this.backgroundPositionVertical == cbpb.backgroundPositionVertical
 +                    && this.backgroundRepeat == cbpb.backgroundRepeat
-                     && this.borderInfo[BEFORE] == cbpb.borderInfo[BEFORE]
-                     && this.borderInfo[AFTER] == cbpb.borderInfo[AFTER]
-                     && this.borderInfo[START] == cbpb.borderInfo[START]
-                     && this.borderInfo[END] == cbpb.borderInfo[END]
-                     && this.padding[BEFORE] == cbpb.padding[BEFORE]
-                     && this.padding[AFTER] == cbpb.padding[AFTER]
-                     && this.padding[START] == cbpb.padding[START]
-                     && this.padding[END] == cbpb.padding[END]
-                     );
++                    && Arrays.equals(borderInfo, cbpb.borderInfo)
++                    && Arrays.equals(padding, cbpb.padding));
++        } else {
+             return false;
          }
--
-         return false;
 -        CommonBorderPaddingBackground other = (CommonBorderPaddingBackground) obj;
 -        return backgroundAttachment == other.backgroundAttachment
 -                && CompareUtil.equal(backgroundColor, other.backgroundColor)
 -                && CompareUtil.equal(backgroundImage, other.backgroundImage)
 -                && CompareUtil.equal(backgroundPositionHorizontal, backgroundPositionHorizontal)
 -                && CompareUtil.equal(backgroundPositionVertical, other.backgroundPositionVertical)
 -                && backgroundRepeat == other.backgroundRepeat
 -                && Arrays.equals(borderInfo, other.borderInfo)
 -                && Arrays.equals(padding, other.padding);
      }
  
-     /** {@inheritDoc} */
+     @Override
      public int hashCode() {
          if (this.hash == -1) {
-             int hash = 17;
+             int hash = getHashCode(backgroundColor,
+                     backgroundImage,
+                     backgroundPositionHorizontal,
+                     backgroundPositionVertical,
+                     borderInfo[BEFORE],
+                     borderInfo[AFTER],
+                     borderInfo[START],
+                     borderInfo[END],
+                     padding[BEFORE],
+                     padding[AFTER],
+                     padding[START],
+                     padding[END]);
              hash = 37 * hash + backgroundAttachment;
-             hash = 37 * hash + (backgroundColor == null ? 0 : backgroundColor.hashCode());
-             hash = 37 * hash + (backgroundImage == null ? 0 : backgroundImage.hashCode());
-             hash = 37 * hash
-                 + (backgroundPositionHorizontal == null
-                    ? 0 : backgroundPositionHorizontal.hashCode());
-             hash = 37 * hash
-                 + (backgroundPositionVertical == null
-                    ? 0 : backgroundPositionVertical.hashCode());
              hash = 37 * hash + backgroundRepeat;
-             hash = 37 * hash + (borderInfo[BEFORE] == null ? 0 : borderInfo[BEFORE].hashCode());
-             hash = 37 * hash + (borderInfo[AFTER] == null ? 0 : borderInfo[AFTER].hashCode());
-             hash = 37 * hash + (borderInfo[START] == null ? 0 : borderInfo[START].hashCode());
-             hash = 37 * hash + (borderInfo[END] == null ? 0 : borderInfo[END].hashCode());
-             hash = 37 * hash + (padding[BEFORE] == null ? 0 : padding[BEFORE].hashCode());
-             hash = 37 * hash + (padding[AFTER] == null ? 0 : padding[AFTER].hashCode());
-             hash = 37 * hash + (padding[START] == null ? 0 : padding[START].hashCode());
-             hash = 37 * hash + (padding[END] == null ? 0 : padding[END].hashCode());
              this.hash = hash;
          }
          return this.hash;
      }
+     private int getHashCode(Object... objects) {
+         int hash = 17;
+         for (Object o : objects) {
+             hash = 37 * hash + (o == null ? 0 : o.hashCode());
+         }
+         return hash;
+     }
  }
index a3d44f0a50e9910f6a9786e367fb4850673347ad,0ae4994787af882defae022cb9a43ac4a5f01838..3648f70913f4d4dfded2112922968811a19b596a
@@@ -57,33 -58,33 +58,33 @@@ public final class TraitSetter 
       * @param context   Property evaluation context
       */
      public static void setBorderPaddingTraits(Area area,
-             CommonBorderPaddingBackground bpProps, boolean bNotFirst, boolean bNotLast,
+             CommonBorderPaddingBackground bpProps, boolean isNotFirst, boolean isNotLast,
              PercentBaseContext context) {
-         int iBP;
-         iBP = bpProps.getPadding(CommonBorderPaddingBackground.START, bNotFirst, context);
-         if (iBP > 0) {
-             area.addTrait(Trait.PADDING_START, new Integer(iBP));
+         int padding;
+         padding = bpProps.getPadding(CommonBorderPaddingBackground.START, isNotFirst, context);
+         if (padding > 0) {
+             area.addTrait(Trait.PADDING_START, padding);
          }
-         iBP = bpProps.getPadding(CommonBorderPaddingBackground.END, bNotLast, context);
-         if (iBP > 0) {
-             area.addTrait(Trait.PADDING_END, new Integer(iBP));
+         padding = bpProps.getPadding(CommonBorderPaddingBackground.END, isNotLast, context);
+         if (padding > 0) {
+             area.addTrait(Trait.PADDING_END, padding);
          }
-         iBP = bpProps.getPadding(CommonBorderPaddingBackground.BEFORE, false, context);
-         if (iBP > 0) {
-             area.addTrait(Trait.PADDING_BEFORE, new Integer(iBP));
+         padding = bpProps.getPadding(CommonBorderPaddingBackground.BEFORE, false, context);
+         if (padding > 0) {
+             area.addTrait(Trait.PADDING_BEFORE, padding);
          }
-         iBP = bpProps.getPadding(CommonBorderPaddingBackground.AFTER, false, context);
-         if (iBP > 0) {
-             area.addTrait(Trait.PADDING_AFTER, new Integer(iBP));
+         padding = bpProps.getPadding(CommonBorderPaddingBackground.AFTER, false, context);
+         if (padding > 0) {
+             area.addTrait(Trait.PADDING_AFTER, padding);
          }
  
-         addBorderTrait(area, bpProps, bNotFirst,
+         addBorderTrait(area, bpProps, isNotFirst,
                  CommonBorderPaddingBackground.START,
 -                BorderProps.SEPARATE, Trait.BORDER_START);
 +                BorderProps.SEPARATE, Trait.BORDER_START, context);
  
-         addBorderTrait(area, bpProps, bNotLast,
+         addBorderTrait(area, bpProps, isNotLast,
                  CommonBorderPaddingBackground.END,
 -                BorderProps.SEPARATE, Trait.BORDER_END);
 +                BorderProps.SEPARATE, Trait.BORDER_END, context);
  
          addBorderTrait(area, bpProps, false,
                  CommonBorderPaddingBackground.BEFORE,
  
          addBorderTrait(area, bpProps, false,
                  CommonBorderPaddingBackground.AFTER,
 -                BorderProps.SEPARATE, Trait.BORDER_AFTER);
 +                BorderProps.SEPARATE, Trait.BORDER_AFTER, context);
      }
  
-     /**
+     /*
       * Sets border traits on an area.
       *
       * @param area    area to set the traits on
       */
      private static void addBorderTrait(Area area,
                                         CommonBorderPaddingBackground bpProps,
 -                                       boolean discard, int side, int mode,
 -                                       Integer trait) {
 -        int borderWidth = bpProps.getBorderWidth(side, discard);
 -        if (borderWidth > 0) {
 -            area.addTrait(trait,
 -                    new BorderProps(bpProps.getBorderStyle(side),
 -                            borderWidth, bpProps.getBorderColor(side),
 -                            mode));
 +                                       boolean bDiscard, int iSide, int mode,
-                                        Object oTrait, PercentBaseContext context) {
++                                       Integer oTrait, PercentBaseContext context) {
 +        int iBP = bpProps.getBorderWidth(iSide, bDiscard);
 +        int radiusStart = bpProps.getBorderRadiusStart(iSide, bDiscard, context);
 +        int radiusEnd = bpProps.getBorderRadiusEnd(iSide, bDiscard, context);
 +        if (iBP > 0 || radiusStart > 0 || radiusEnd > 0) {
 +            BorderProps bps =  new BorderProps(bpProps.getBorderStyle(iSide),
 +                    iBP, bpProps.getBorderColor(iSide),
 +                    mode);
 +            bps.setRadiusStart(radiusStart);
 +            bps.setRadiusEnd(radiusEnd);
 +            area.addTrait(oTrait, bps);
          }
      }
  
       * @param context Property evaluation context
       * @deprecated Call the other addBorders() method and addPadding separately.
       */
-     public static void addBorders(Area area, CommonBorderPaddingBackground bordProps,
+     public static void addBorders(Area area, CommonBorderPaddingBackground borderProps,
                                    PercentBaseContext context) {
-         BorderProps bps = getBorderProps(bordProps, CommonBorderPaddingBackground.BEFORE, context);
 -        BorderProps bps = getBorderProps(borderProps, CommonBorderPaddingBackground.BEFORE);
++        BorderProps bps = getBorderProps(borderProps, CommonBorderPaddingBackground.BEFORE, context);
          if (bps != null) {
              area.addTrait(Trait.BORDER_BEFORE, bps);
          }
-         bps = getBorderProps(bordProps, CommonBorderPaddingBackground.AFTER, context);
 -        bps = getBorderProps(borderProps, CommonBorderPaddingBackground.AFTER);
++        bps = getBorderProps(borderProps, CommonBorderPaddingBackground.AFTER, context);
          if (bps != null) {
              area.addTrait(Trait.BORDER_AFTER, bps);
          }
-         bps = getBorderProps(bordProps, CommonBorderPaddingBackground.START, context);
 -        bps = getBorderProps(borderProps, CommonBorderPaddingBackground.START);
++        bps = getBorderProps(borderProps, CommonBorderPaddingBackground.START, context);
          if (bps != null) {
              area.addTrait(Trait.BORDER_START, bps);
          }
-         bps = getBorderProps(bordProps, CommonBorderPaddingBackground.END, context);
 -        bps = getBorderProps(borderProps, CommonBorderPaddingBackground.END);
++        bps = getBorderProps(borderProps, CommonBorderPaddingBackground.END, context);
          if (bps != null) {
              area.addTrait(Trait.BORDER_END, bps);
          }
                  boolean discardBefore, boolean discardAfter,
                  boolean discardStart, boolean discardEnd,
                  PercentBaseContext context) {
-         BorderProps bps = getBorderProps(bordProps, CommonBorderPaddingBackground.BEFORE, context);
 -        BorderProps bps = getBorderProps(borderProps, CommonBorderPaddingBackground.BEFORE);
++        BorderProps bps = getBorderProps(borderProps, CommonBorderPaddingBackground.BEFORE, context);
          if (bps != null && !discardBefore) {
              area.addTrait(Trait.BORDER_BEFORE, bps);
          }
-         bps = getBorderProps(bordProps, CommonBorderPaddingBackground.AFTER, context);
 -        bps = getBorderProps(borderProps, CommonBorderPaddingBackground.AFTER);
++        bps = getBorderProps(borderProps, CommonBorderPaddingBackground.AFTER, context);
          if (bps != null && !discardAfter) {
              area.addTrait(Trait.BORDER_AFTER, bps);
          }
-         bps = getBorderProps(bordProps, CommonBorderPaddingBackground.START, context);
 -        bps = getBorderProps(borderProps, CommonBorderPaddingBackground.START);
++        bps = getBorderProps(borderProps, CommonBorderPaddingBackground.START, context);
          if (bps != null && !discardStart) {
              area.addTrait(Trait.BORDER_START, bps);
          }
-         bps = getBorderProps(bordProps, CommonBorderPaddingBackground.END, context);
 -        bps = getBorderProps(borderProps, CommonBorderPaddingBackground.END);
++        bps = getBorderProps(borderProps, CommonBorderPaddingBackground.END, context);
          if (bps != null && !discardEnd) {
              area.addTrait(Trait.BORDER_END, bps);
          }
index aa4b6325a72bb8d9a9822dcf193be4003bdd28f9,cb66f2abbc59338ce3e35c0b358c50c566764a45..042efccc52ea30d14accb90549d83d2fefa62187
@@@ -32,8 -32,9 +32,8 @@@ import org.apache.batik.parser.AWTTrans
  
  import org.apache.xmlgraphics.image.loader.ImageSize;
  import org.apache.xmlgraphics.util.QName;
--import org.apache.xmlgraphics.util.UnitConv;
  
+ import org.apache.fop.apps.FOUserAgent;
  import org.apache.fop.area.Area;
  import org.apache.fop.area.Block;
  import org.apache.fop.area.BlockViewport;
@@@ -48,8 -49,7 +48,9 @@@ import org.apache.fop.area.inline.Inlin
  import org.apache.fop.fo.Constants;
  import org.apache.fop.fo.extensions.ExtensionElementMapping;
  import org.apache.fop.fonts.FontMetrics;
 +import org.apache.fop.render.intermediate.BorderPainter;
  import org.apache.fop.traits.BorderProps;
++import org.apache.fop.util.UnitConv;
  
  /**
   * Abstract base class for renderers like PDF and PostScript where many painting operations
@@@ -152,21 -166,11 +167,21 @@@ public abstract class AbstractPathOrien
          BorderProps bpsStart = (BorderProps)borderArea.getTrait(Trait.BORDER_START);
          BorderProps bpsEnd = (BorderProps)borderArea.getTrait(Trait.BORDER_END);
  
 +        Trait.Background backgroundTrait
 +            = (Trait.Background)backgroundArea.getTrait(Trait.BACKGROUND);
 +
          drawBackground(startx, starty, width, height,
                  (Trait.Background) backgroundArea.getTrait(Trait.BACKGROUND),
-                 bpsBefore, bpsAfter, bpsStart, bpsEnd);
 -                    bpsBefore, bpsAfter, bpsStart, bpsEnd, backgroundArea.getBidiLevel());
++                bpsBefore, bpsAfter, bpsStart, bpsEnd, backgroundArea.getBidiLevel());
 +
 +        // TODO what is the default bg color?   Should we serialize it?
 +        Color bg = Color.white;
 +        if (backgroundTrait != null &&  backgroundTrait.getColor() != null) {
 +            bg = backgroundTrait.getColor();
 +        }
 +
          drawBorders(startx, starty, width, height,
-                 bpsBefore, bpsAfter, bpsStart, bpsEnd, bg);
 -                    bpsBefore, bpsAfter, bpsStart, bpsEnd, borderArea.getBidiLevel());
++                bpsBefore, bpsAfter, bpsStart, bpsEnd, backgroundArea.getBidiLevel(), bg);
      }
  
      /**
              float sy = starty;
              float paddRectWidth = width;
              float paddRectHeight = height;
-             if (bpsStart != null) {
-                 sx += bpsStart.width / 1000f;
-                 paddRectWidth -= bpsStart.width / 1000f;
+             if (bpsLeft != null) {
+                 sx += bpsLeft.width / 1000f;
+                 paddRectWidth -= bpsLeft.width / 1000f;
              }
-             if (bpsBefore != null) {
-                 sy += bpsBefore.width / 1000f;
-                 paddRectHeight -= bpsBefore.width / 1000f;
+             if (bpsTop != null) {
+                 sy += bpsTop.width / 1000f;
+                 paddRectHeight -= bpsTop.width / 1000f;
              }
-             if (bpsEnd != null) {
-                 paddRectWidth -= bpsEnd.width / 1000f;
+             if (bpsRight != null) {
+                 paddRectWidth -= bpsRight.width / 1000f;
              }
-             if (bpsAfter != null) {
-                 paddRectHeight -= bpsAfter.width / 1000f;
+             if (bpsBottom != null) {
+                 paddRectHeight -= bpsBottom.width / 1000f;
              }
  
-                         bpsBefore, bpsAfter, bpsStart,  bpsEnd);
 +            saveGraphicsState();
 +
 +            //TODO remove this choice
 +            if (BorderPainter.isRoundedCornersSupported()) {
 +                clipBackground(sx, sy,  paddRectWidth, paddRectHeight,
++                        bpsTop, bpsBottom, bpsLeft,  bpsRight);
 +            } else {
 +                clipRect(sx, sy,  paddRectWidth, paddRectHeight);
 +            }
 +
              if (back.getColor() != null) {
                  updateColor(back.getColor(), true);
                  fillRect(sx, sy, paddRectWidth, paddRectHeight);
       * @param starty the start y position
       * @param width the width of the area
       * @param height the height of the area
-      * @param bpsBefore the border-before traits
-      * @param bpsAfter the border-after traits
-      * @param bpsStart the border-start traits
-      * @param bpsEnd the border-end traits
-      * @param innerBackgroundColor the background color of the block
+      * @param bpsBefore the border traits associated with before edge
+      * @param bpsAfter the border traits associated with after edge
+      * @param bpsStart the border traits associated with start edge
+      * @param bpsEnd the border traits associated with end edge
+      * @param level of bidirectional embedding
++     * @param innerBackgroundColor the background color of the block 
       */
      protected void drawBorders(                                  // CSOK: ParameterNumber
              float startx, float starty, float width, float height,
              BorderProps bpsBefore, BorderProps bpsAfter,
-             BorderProps bpsStart, BorderProps bpsEnd, Color innerBackgroundColor) {
 -            BorderProps bpsStart, BorderProps bpsEnd, int level) {
++            BorderProps bpsStart, BorderProps bpsEnd, int level, Color innerBackgroundColor) {
          Rectangle2D.Float borderRect = new Rectangle2D.Float(startx, starty, width, height);
-         drawBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd, innerBackgroundColor);
+         BorderProps bpsTop = bpsBefore;
+         BorderProps bpsBottom = bpsAfter;
+         BorderProps bpsLeft;
+         BorderProps bpsRight;
+         if ( ( level == -1 ) || ( ( level & 1 ) == 0 ) ) {
+             bpsLeft = bpsStart;
+             bpsRight = bpsEnd;
+         } else {
+             bpsLeft = bpsEnd;
+             bpsRight = bpsStart;
+         }
 -        drawBorders(borderRect, bpsTop, bpsBottom, bpsLeft, bpsRight);
++        drawBorders(borderRect, bpsTop, bpsBottom, bpsLeft, bpsRight, innerBackgroundColor);
      }
  
-     private static final int BEFORE = 0;
-     private static final int END = 1;
-     private static final int AFTER = 2;
-     private static final int START = 3;
+     private static final int TOP = 0;
+     private static final int RIGHT = 1;
+     private static final int BOTTOM = 2;
+     private static final int LEFT = 3;
  
      /**
       * Draws borders.
       * @param borderRect the border rectangle
-      * @param bpsBefore the border specification on the before side
-      * @param bpsAfter the border specification on the after side
-      * @param bpsStart the border specification on the start side
-      * @param bpsEnd the border specification on the end side
+      * @param bpsTop the border specification on the top edge
+      * @param bpsBottom the border traits associated with bottom edge
+      * @param bpsLeft the border specification on the left edge
+      * @param bpsRight the border specification on the right edge
 +     * @param innerBackgroundColor the background color of the block
       */
      protected void drawBorders(                                  // CSOK: MethodLength
              Rectangle2D.Float borderRect,
-             BorderProps bpsBefore, BorderProps bpsAfter, BorderProps bpsStart, BorderProps bpsEnd,
 -            BorderProps bpsTop, BorderProps bpsBottom, BorderProps bpsLeft, BorderProps bpsRight) {
++            BorderProps bpsTop, BorderProps bpsBottom, BorderProps bpsLeft, BorderProps bpsRight,
 +            Color innerBackgroundColor) {
          //TODO generalize each of the four conditions into using a parameterized drawBorder()
          boolean[] border = new boolean[] {
-                 (bpsBefore != null), (bpsEnd != null),
-                 (bpsAfter != null), (bpsStart != null)};
+                 (bpsTop != null), (bpsRight != null),
+                 (bpsBottom != null), (bpsLeft != null)};
          float startx = borderRect.x;
          float starty = borderRect.y;
          float width = borderRect.width;
index e90f0b29a2ff232c5d994547724517b9a1469fff,2ae95dd4c91e090e53ff168fc5166c31d32a961a..d427f9d7fa37c9294e0887e660f902dec33dde7f
@@@ -23,7 -23,8 +23,9 @@@ import java.awt.Color
  import java.awt.Dimension;
  import java.awt.geom.AffineTransform;
  import java.io.IOException;
 +import java.util.HashMap;
+ import java.util.Iterator;
+ import java.util.List;
  import java.util.Map;
  
  import org.apache.fop.afp.AFPDitheredRectanglePainter;
@@@ -77,24 -80,18 +81,27 @@@ public class AFPDocumentHandler extend
      private DataStream dataStream;
  
      /** the map of page segments */
-     private Map/*<String,String>*/pageSegmentMap
-         = new java.util.HashMap/*<String,String>*/();
+     private Map<String, PageSegmentDescriptor> pageSegmentMap
+         = new java.util.HashMap<String, PageSegmentDescriptor>();
  
-     private Map/*<String, String>*/ roundedCornerNameCache
-             = new HashMap()/*<String, String>*/;
 +
 +    // Rounded corners are cached at the document level
++    private Map<String, String> roundedCornerNameCache
++            = new HashMap<String, String>();
 +
 +    private int roundedCornerCount = 0;
 +
 +    /** Medium Map referenced on previous page **/
 +    private String lastMediumMap;
+     private static enum Location {
+         ELSEWHERE, IN_DOCUMENT_HEADER, FOLLOWING_PAGE_SEQUENCE, IN_PAGE_HEADER
+     }
  
-     private static final int LOC_ELSEWHERE = 0;
-     private static final int LOC_FOLLOWING_PAGE_SEQUENCE = 1;
-     private static final int LOC_IN_PAGE_HEADER = 2;
+     private Location location = Location.ELSEWHERE;
  
-     private int location = LOC_ELSEWHERE;
+     /** temporary holds extensions that have to be deferred until the end of the page-sequence */
+     private List<AFPPageSetup> deferredPageSequenceExtensions
+         = new java.util.LinkedList<AFPPageSetup>();
  
      /** the shading mode for filled rectangles */
      private AFPShadingMode shadingMode = AFPShadingMode.COLOR;
          }
      }
  
 +    /**
 +     * Corner images can be reused by storing at the document level in the AFP
 +     * The cache is used to map cahced images to caller generated descriptions of the corner
 +     * @param cornerKey caller's identifier for the corner
 +     * @return document id of the corner image
 +     */
 +    public String cacheRoundedCorner(String cornerKey) {
 +
 +        // Make a unique id
 +        StringBuffer idBuilder = new StringBuffer("RC");
 +
 +        String tmp = Integer.toHexString(roundedCornerCount).toUpperCase();
 +        if (tmp.length() > 6) {
 +            //Will never happen
 +            //log.error("Rounded corners cache capacity exceeded");
 +            //We should get a visual clue
 +            roundedCornerCount = 0;
 +            tmp = "000000";
 +        } else if (tmp.length() < 6) {
 +            for (int i = 0; i < 6 - tmp.length(); i++) {
 +                idBuilder.append("0");
 +            }
 +            idBuilder.append(tmp);
 +        }
 +
 +       roundedCornerCount++;
 +
 +       String id =  idBuilder.toString();
 +
 +       //cache the corner id
 +       roundedCornerNameCache.put(cornerKey, id);
 +       return id;
 +    }
 +    /**
 +     * This method returns the an id that identifies a cached corner or null if non existent
 +     * @param cornerKey caller's identifier for the corner
 +     * @return document id of the corner image
 +     */
 +    public String getCachedRoundedCorner(String cornerKey) {
 +        return (String)roundedCornerNameCache.get(cornerKey);
 +    }
 +
 +
+     private void handleNOP(AFPPageSetup nop) {
+         String content = nop.getContent();
+         if (content != null) {
+             dataStream.createNoOperation(content);
+         }
+     }
      // ---=== AFPCustomizable ===---
  
      /** {@inheritDoc} */
index 0000000000000000000000000000000000000000,e318c49fbb523991cf45e8d1ea6e45f56c27b5e5..7508c8ca04be9bc895fd428b515e150ad1eec8c2
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,205 +1,205 @@@
 -        setResourceInformation(imageObjectInfo,
+ /*
+  * 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.render.afp;
+ import java.awt.Rectangle;
+ import java.awt.color.ColorSpace;
+ import java.io.IOException;
+ import java.io.InputStream;
+ import org.apache.commons.io.IOUtils;
+ import org.apache.commons.logging.Log;
+ import org.apache.commons.logging.LogFactory;
+ import org.apache.xmlgraphics.image.loader.Image;
+ import org.apache.xmlgraphics.image.loader.ImageFlavor;
+ import org.apache.xmlgraphics.image.loader.ImageSize;
+ import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG;
+ import org.apache.xmlgraphics.image.loader.impl.JPEGConstants;
+ import org.apache.xmlgraphics.util.MimeConstants;
+ import org.apache.fop.afp.AFPDataObjectInfo;
+ import org.apache.fop.afp.AFPImageObjectInfo;
+ import org.apache.fop.afp.AFPObjectAreaInfo;
+ import org.apache.fop.afp.AFPPaintingState;
+ import org.apache.fop.afp.AFPResourceInfo;
+ import org.apache.fop.afp.AFPResourceManager;
+ import org.apache.fop.afp.ioca.ImageContent;
+ import org.apache.fop.afp.modca.ResourceObject;
+ import org.apache.fop.render.ImageHandler;
+ import org.apache.fop.render.RenderingContext;
+ /**
+  * {@link ImageHandler} implementation which handles ImageRawJPEG instances. JPEG data is
+  * embedded directly (not decoded) into IOCA images (FS11 or FS45).
+  */
+ public class AFPImageHandlerRawJPEG extends AFPImageHandler implements ImageHandler {
+     /** logging instance */
+     private final Log log = LogFactory.getLog(AFPImageHandlerRawJPEG.class);
+     private void setDefaultResourceLevel(AFPImageObjectInfo imageObjectInfo,
+             AFPResourceManager resourceManager) {
+         AFPResourceInfo resourceInfo = imageObjectInfo.getResourceInfo();
+         if (!resourceInfo.levelChanged()) {
+             resourceInfo.setLevel(resourceManager.getResourceLevelDefaults()
+                     .getDefaultResourceLevel(ResourceObject.TYPE_IMAGE));
+         }
+     }
+     /** {@inheritDoc} */
+     @Override
+     protected AFPDataObjectInfo createDataObjectInfo() {
+         return new AFPImageObjectInfo();
+     }
+     /** {@inheritDoc} */
+     public int getPriority() {
+         return 150;
+     }
+     /** {@inheritDoc} */
+     public Class<?> getSupportedImageClass() {
+         return ImageRawJPEG.class;
+     }
+     /** {@inheritDoc} */
+     public ImageFlavor[] getSupportedImageFlavors() {
+         return new ImageFlavor[] {ImageFlavor.RAW_JPEG};
+     }
+     /** {@inheritDoc} */
+     public void handleImage(RenderingContext context, Image image, Rectangle pos)
+             throws IOException {
+         AFPRenderingContext afpContext = (AFPRenderingContext)context;
+         AFPImageObjectInfo imageObjectInfo = (AFPImageObjectInfo)createDataObjectInfo();
+         AFPPaintingState paintingState = afpContext.getPaintingState();
+         // set resource information
 -                afpContext.getForeignAttributes());
++        imageObjectInfo.setResourceInfo(createResourceInformation(
+                 image.getInfo().getOriginalURI(),
++                afpContext.getForeignAttributes()));
+         setDefaultResourceLevel(imageObjectInfo, afpContext.getResourceManager());
+         // Positioning
+         imageObjectInfo.setObjectAreaInfo(createObjectAreaInfo(paintingState, pos));
+         updateIntrinsicSize(imageObjectInfo, paintingState, image.getSize());
+         // Image content
+         ImageRawJPEG jpeg = (ImageRawJPEG)image;
+         imageObjectInfo.setCompression(ImageContent.COMPID_JPEG);
+         ColorSpace cs = jpeg.getColorSpace();
+         switch (cs.getType()) {
+         case ColorSpace.TYPE_GRAY:
+             imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS11);
+             imageObjectInfo.setColor(false);
+             imageObjectInfo.setBitsPerPixel(8);
+             break;
+         case ColorSpace.TYPE_RGB:
+             imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS11);
+             imageObjectInfo.setColor(true);
+             imageObjectInfo.setBitsPerPixel(24);
+             break;
+         case ColorSpace.TYPE_CMYK:
+             imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS45);
+             imageObjectInfo.setColor(true);
+             imageObjectInfo.setBitsPerPixel(32);
+             break;
+         default:
+             throw new IllegalStateException(
+                     "Color space of JPEG image not supported: " + cs);
+         }
+         boolean included = afpContext.getResourceManager().tryIncludeObject(imageObjectInfo);
+         if (!included) {
+             log.debug("Embedding undecoded JPEG as IOCA image...");
+             InputStream inputStream = jpeg.createInputStream();
+             try {
+                 imageObjectInfo.setData(IOUtils.toByteArray(inputStream));
+             } finally {
+                 IOUtils.closeQuietly(inputStream);
+             }
+             // Create image
+             afpContext.getResourceManager().createObject(imageObjectInfo);
+         }
+     }
+     private void updateIntrinsicSize(AFPImageObjectInfo imageObjectInfo,
+             AFPPaintingState paintingState, ImageSize targetSize) {
+         //Update image object info
+         imageObjectInfo.setDataHeightRes((int)Math.round(
+                 targetSize.getDpiHorizontal() * 10));
+         imageObjectInfo.setDataWidthRes((int)Math.round(
+                 targetSize.getDpiVertical() * 10));
+         imageObjectInfo.setDataHeight(targetSize.getHeightPx());
+         imageObjectInfo.setDataWidth(targetSize.getWidthPx());
+         // set object area info
+         int resolution = paintingState.getResolution();
+         AFPObjectAreaInfo objectAreaInfo = imageObjectInfo.getObjectAreaInfo();
+         objectAreaInfo.setResolution(resolution);
+     }
+     /** {@inheritDoc} */
+     public boolean isCompatible(RenderingContext targetContext, Image image) {
+         if (!(targetContext instanceof AFPRenderingContext)) {
+             return false; //AFP-specific image handler
+         }
+         AFPRenderingContext context = (AFPRenderingContext)targetContext;
+         AFPPaintingState paintingState = context.getPaintingState();
+         if (!paintingState.canEmbedJpeg()) {
+             return false;
+         }
+         if (paintingState.getBitsPerPixel() < 8) {
+             return false; //This would stand in the way of dithering and cause exceptions
+         }
+         if (image == null) {
+             return true; //Don't know the image format, yet
+         }
+         if (image instanceof ImageRawJPEG) {
+             ImageRawJPEG jpeg = (ImageRawJPEG)image;
+             ColorSpace cs = jpeg.getColorSpace();
+             switch (cs.getType()) {
+             case ColorSpace.TYPE_GRAY:
+             case ColorSpace.TYPE_RGB:
+                 //ok
+                 break;
+             case ColorSpace.TYPE_CMYK:
+                 if (!paintingState.isCMYKImagesSupported()) {
+                     return false; //CMYK is disabled
+                     //Note: you may need to disable this image handler through configuration
+                     //if you want to paint a CMYK JPEG on 24bit and less configurations.
+                 }
+                 break;
+             default:
+                 return false; //not supported
+             }
+             if (jpeg.getSOFType() != JPEGConstants.SOF0) {
+                 return false; //We'll let only baseline DCT through.
+             }
+             return true;
+         }
+         return false;
+     }
+ }
index 48eeb79bf86bf5a9fd24b3d7d32b8f6d2b45ade8,e5f41d232a6a86ed42936691b109617738dd197f..3e0780cbf246d11f186314b6b6ff9be91babd3e1
@@@ -315,11 -108,12 +108,12 @@@ public class AFPImageHandlerRenderedIma
          AFPRenderingContext afpContext = (AFPRenderingContext)context;
  
          AFPImageObjectInfo imageObjectInfo = (AFPImageObjectInfo)createDataObjectInfo();
+         AFPPaintingState paintingState = afpContext.getPaintingState();
  
          // set resource information
 -        setResourceInformation(imageObjectInfo,
 +        imageObjectInfo.setResourceInfo(createResourceInformation(
                  image.getInfo().getOriginalURI(),
 -                afpContext.getForeignAttributes());
 +                afpContext.getForeignAttributes()));
          setDefaultResourceLevel(imageObjectInfo, afpContext.getResourceManager());
  
          // Positioning
index c31a7ede3b94e10d37ee0209999697e2c93a24bf,8b2f3155514b04d29bc691ac6618d9fa826015ed..5d8c1a93ff0a70cc98fad815b43bf49930a63d2f
@@@ -26,12 -25,9 +26,14 @@@ import java.awt.Paint
  import java.awt.Point;
  import java.awt.Rectangle;
  import java.awt.geom.AffineTransform;
 +import java.awt.geom.Area;
 +import java.awt.geom.Ellipse2D;
 +import java.awt.geom.GeneralPath;
 +import java.awt.geom.Rectangle2D;
  import java.io.IOException;
+ import java.net.URI;
+ import java.net.URISyntaxException;
 +import java.security.MessageDigest;
  import java.util.Map;
  
  import org.w3c.dom.Document;
@@@ -68,7 -55,7 +72,8 @@@ import org.apache.fop.afp.util.Resource
  import org.apache.fop.fonts.Font;
  import org.apache.fop.fonts.FontInfo;
  import org.apache.fop.fonts.FontTriplet;
+ import org.apache.fop.fonts.Typeface;
 +import org.apache.fop.render.ImageHandlerUtil;
  import org.apache.fop.render.RenderingContext;
  import org.apache.fop.render.intermediate.AbstractIFPainter;
  import org.apache.fop.render.intermediate.BorderPainter;
@@@ -193,8 -179,9 +201,9 @@@ public class AFPPainter extends Abstrac
      }
  
      /** {@inheritDoc} */
+     @Override
      protected RenderingContext createRenderingContext() {
 -        AFPRenderingContext psContext = new AFPRenderingContext(
 +        AFPRenderingContext renderingContext = new AFPRenderingContext(
                  getUserAgent(),
                  documentHandler.getResourceManager(),
                  getPaintingState(),
          }
      }
  
--    /** {@inheritDoc} */
-     public void drawBorderRect(Rectangle rect, BorderProps before, BorderProps after,
-             BorderProps start, BorderProps end, Color innerBackgroundColor) throws IFException {
-         if (before != null || after != null || start != null || end != null) {
-             try {
-                 this.borderPainter.drawBorders(rect, before, after, start, end,
-                         innerBackgroundColor);
-             } catch (IFException ife) {
-                 throw new IFException("Error while painting borders", ife);
-             }
+     @Override
+     public void drawBorderRect(Rectangle rect, BorderProps top, BorderProps bottom,
 -            BorderProps left, BorderProps right) throws IFException {
++            BorderProps left, BorderProps right, Color innerBackgroundColor) throws IFException {
+         if (top != null || bottom != null || left != null || right != null) {
 -            try {
 -                this.borderPainter.drawBorders(rect, top, bottom, left, right);
 -            } catch (IOException ife) {
 -                throw new IFException("IO error while painting borders", ife);
 -            }
++            this.borderPainter.drawBorders(rect, top, bottom, left, right, innerBackgroundColor);
          }
      }
  
 +
      //TODO Try to resolve the name-clash between the AFPBorderPainter in the afp package
      //and this one. Not done for now to avoid a lot of re-implementation and code duplication.
 +
      private static class AFPBorderPainterAdapter extends BorderPainter {
  
 -        private final AFPBorderPainter delegate;
 +        private final class BorderImagePainter implements Graphics2DImagePainter {
 +            private final double esf;
 +            private final Rectangle borderRect;
 +            private final BorderProps bpsStart;
 +            private final BorderProps bpsEnd;
 +            private final BorderProps bpsBefore;
 +            private final BorderProps bpsAfter;
 +            private final boolean[] roundCorner;
 +            private final Color innerBackgroundColor;
 +
 +            /* TODO represent border related parameters in a class */
 +            private BorderImagePainter(double esf, Rectangle borderRect,
 +                    BorderProps bpsStart, BorderProps bpsEnd,
 +                    BorderProps bpsBefore, BorderProps bpsAfter,
 +                    boolean[] roundCorner, Color innerBackgroundColor) {
 +                this.esf = esf;
 +                this.borderRect = borderRect;
 +                this.bpsStart = bpsStart;
 +                this.bpsBefore = bpsBefore;
 +                this.roundCorner = roundCorner;
 +                this.bpsEnd = bpsEnd;
 +                this.bpsAfter = bpsAfter;
 +                this.innerBackgroundColor = innerBackgroundColor;
 +            }
 +
 +            public void paint(Graphics2D g2d, Rectangle2D area) {
 +
 +                //background
 +                Area background = new Area(area);
 +                Area cornerRegion = new Area();
 +                Area[] cornerBorder
 +                        = new Area[]{new Area(), new Area(), new Area(), new Area()};
 +
-                 if (roundCorner[BEFORE_START]) {
++                if (roundCorner[TOP_LEFT]) {
 +
 +                    AffineTransform transform =  new AffineTransform();
 +                    int beforeRadius = (int)(esf * bpsBefore.getRadiusStart());
 +                    int startRadius = (int)(esf * bpsStart.getRadiusStart());
 +
 +                    int beforeWidth = bpsBefore.width;
 +                    int startWidth = bpsStart.width;
-                     int corner = BEFORE_START;
++                    int corner = TOP_LEFT;
 +
 +                    background.subtract(makeCornerClip(beforeRadius, startRadius,
 +                            transform));
 +
 +                    Area clip = new Area(new Rectangle(0, 0, startRadius, beforeRadius));
 +                    clip.transform(transform);
 +                    cornerRegion.add(clip);
 +
-                     cornerBorder[BEFORE].add(makeCornerBorderBPD(beforeRadius,
++                    cornerBorder[TOP].add(makeCornerBorderBPD(beforeRadius,
 +                                    startRadius, beforeWidth, startWidth, transform));
 +
-                     cornerBorder[START].add(makeCornerBorderIPD(beforeRadius,
++                    cornerBorder[LEFT].add(makeCornerBorderIPD(beforeRadius,
 +                            startRadius, beforeWidth, startWidth, transform));
 +                }
 +
-                 if (roundCorner[BEFORE_END]) {
++                if (roundCorner[TOP_RIGHT]) {
 +                    AffineTransform transform
 +                            = new AffineTransform(-1, 0, 0, 1, borderRect.width, 0);
 +
 +                    int beforeRadius = (int)(esf * bpsBefore.getRadiusEnd());
 +                    int startRadius = (int)(esf * bpsEnd.getRadiusStart());
 +
 +                    int beforeWidth = bpsBefore.width;
 +                    int startWidth = bpsEnd.width;
-                     int corner = BEFORE_END;
++                    int corner = TOP_RIGHT;
 +
 +                    background.subtract(makeCornerClip(beforeRadius, startRadius,
 +                            transform));
 +
 +                    Area clip = new Area(new Rectangle(0, 0, startRadius, beforeRadius));
 +                    clip.transform(transform);
 +                    cornerRegion.add(clip);
 +
-                     cornerBorder[BEFORE].add(makeCornerBorderBPD(beforeRadius,
++                    cornerBorder[TOP].add(makeCornerBorderBPD(beforeRadius,
 +                                    startRadius, beforeWidth, startWidth, transform));
 +
-                     cornerBorder[END].add(makeCornerBorderIPD(beforeRadius,
++                    cornerBorder[RIGHT].add(makeCornerBorderIPD(beforeRadius,
 +                            startRadius, beforeWidth, startWidth, transform));
 +                }
 +
-                 if (roundCorner[AFTER_END]) {
++                if (roundCorner[BOTTOM_RIGHT]) {
 +                    AffineTransform transform = new AffineTransform(-1, 0, 0, -1,
 +                            borderRect.width, borderRect.height);
 +
 +                    int beforeRadius = (int)(esf * bpsAfter.getRadiusEnd());
 +                    int startRadius = (int)(esf * bpsEnd.getRadiusEnd());
 +
 +                    int beforeWidth = bpsAfter.width;
 +                    int startWidth = bpsEnd.width;
-                     int corner = AFTER_END;
++                    int corner = BOTTOM_RIGHT;
 +
 +                    background.subtract(makeCornerClip(beforeRadius, startRadius,
 +                            transform));
 +
 +                    Area clip = new Area(new Rectangle(0, 0, startRadius, beforeRadius));
 +                    clip.transform(transform);
 +                    cornerRegion.add(clip);
 +
-                     cornerBorder[AFTER].add(makeCornerBorderBPD(beforeRadius,
++                    cornerBorder[BOTTOM].add(makeCornerBorderBPD(beforeRadius,
 +                            startRadius, beforeWidth, startWidth, transform));
-                     cornerBorder[END].add(makeCornerBorderIPD(beforeRadius,
++                    cornerBorder[RIGHT].add(makeCornerBorderIPD(beforeRadius,
 +                            startRadius, beforeWidth, startWidth, transform));
 +                }
 +
-                 if (roundCorner[AFTER_START]) {
++                if (roundCorner[BOTTOM_LEFT]) {
 +                    AffineTransform transform
 +                            = new AffineTransform(1, 0, 0, -1, 0, borderRect.height);
 +
 +                    int beforeRadius = (int)(esf * bpsAfter.getRadiusStart());
 +                    int startRadius = (int)(esf * bpsStart.getRadiusEnd());
 +
 +                    int beforeWidth = bpsAfter.width;
 +                    int startWidth = bpsStart.width;
-                     int corner = AFTER_START;
++                    int corner = BOTTOM_LEFT;
 +
 +                    background.subtract(makeCornerClip(beforeRadius, startRadius,
 +                            transform));
 +
 +                    Area clip = new Area(new Rectangle(0, 0, startRadius, beforeRadius));
 +                    clip.transform(transform);
 +                    cornerRegion.add(clip);
 +
-                     cornerBorder[AFTER].add(makeCornerBorderBPD(beforeRadius,
++                    cornerBorder[BOTTOM].add(makeCornerBorderBPD(beforeRadius,
 +                                    startRadius, beforeWidth, startWidth, transform));
-                     cornerBorder[START].add(makeCornerBorderIPD(beforeRadius,
++                    cornerBorder[LEFT].add(makeCornerBorderIPD(beforeRadius,
 +                            startRadius, beforeWidth, startWidth, transform));
 +                }
 +
 +                g2d.setColor(innerBackgroundColor);
 +                g2d.fill(background);
 +
 +                //paint the borders
 +                //TODO refactor to repeating code into method
 +                if (bpsBefore != null && bpsBefore.width > 0) {
 +                    GeneralPath borderPath = new GeneralPath();
 +                    borderPath.moveTo(0, 0);
 +                    borderPath.lineTo(borderRect.width, 0);
 +                    borderPath.lineTo(
 +                            borderRect.width - (bpsEnd == null ? 0 : bpsEnd.width),
 +                            bpsBefore.width);
 +                    borderPath.lineTo(bpsStart == null ? 0 : bpsStart.width, bpsBefore.width);
 +
 +                    Area border = new Area(borderPath);
 +
 +                    border.subtract(cornerRegion);
 +
 +                    g2d.setColor(bpsBefore.color);
 +                    g2d.fill(border);
-                     g2d.fill(cornerBorder[BEFORE]);
++                    g2d.fill(cornerBorder[TOP]);
 +                }
 +
 +                if (bpsEnd != null && bpsEnd.width > 0) {
 +                    GeneralPath borderPath = new GeneralPath();
 +                    borderPath.moveTo(borderRect.width, 0);
 +                    borderPath.lineTo(borderRect.width, borderRect.height);
 +                    borderPath.lineTo(
 +                            borderRect.width - bpsEnd.width,
 +                            borderRect.height - (bpsAfter == null ? 0 : bpsAfter.width));
 +                    borderPath.lineTo(
 +                            borderRect.width - bpsEnd.width,
 +                            bpsBefore == null ? 0 : bpsBefore.width);
 +
 +                    Area border = new Area(borderPath);
 +
 +                    border.subtract(cornerRegion);
 +
 +                    g2d.setColor(bpsEnd.color);
 +                    g2d.fill(border);
-                     g2d.fill(cornerBorder[END]);
++                    g2d.fill(cornerBorder[RIGHT]);
 +                }
 +
 +                if (bpsAfter != null && bpsAfter.width > 0) {
 +                    GeneralPath borderPath = new GeneralPath();
 +                    borderPath.moveTo(0, borderRect.height);
 +                    borderPath.lineTo(borderRect.width, borderRect.height);
 +                    borderPath.lineTo(
 +                            borderRect.width - (bpsEnd == null ? 0 : bpsEnd.width),
 +                            borderRect.height - bpsAfter.width);
 +                    borderPath.lineTo(
 +                            bpsStart == null ? 0 : bpsStart.width,
 +                            borderRect.height - bpsAfter.width);
 +                    Area border = new Area(borderPath);
 +
 +                    border.subtract(cornerRegion);
 +
 +                    g2d.setColor(bpsAfter.color);
 +                    g2d.fill(border);
-                     g2d.fill(cornerBorder[AFTER]);
++                    g2d.fill(cornerBorder[BOTTOM]);
 +                }
  
 -        public AFPBorderPainterAdapter(AFPBorderPainter borderPainter) {
 +                if (bpsStart != null && bpsStart.width > 0) {
 +
 +                    GeneralPath borderPath = new GeneralPath();
 +                    borderPath.moveTo(bpsStart.width,
 +                            bpsBefore == null ? 0 : bpsBefore.width);
 +                    borderPath.lineTo(bpsStart.width,
 +                            borderRect.height - (bpsAfter == null ? 0 : bpsAfter.width));
 +                    borderPath.lineTo(0, borderRect.height);
 +                    borderPath.lineTo(0, 0);
 +
 +                    Area border = new Area(borderPath);
 +
 +                    border.subtract(cornerRegion);
 +
 +                    g2d.setColor(bpsStart.color);
 +                    g2d.fill(border);
-                     g2d.fill(cornerBorder[START]);
++                    g2d.fill(cornerBorder[LEFT]);
 +                }
 +            }
 +
 +            public Dimension getImageSize() {
 +                return borderRect.getSize();
 +            }
 +        }
 +
 +        public static final String CORNER_MODE_PROPERTY = "fop.round-corners.afp";
 +        public static final String MODE_SEPERATE = "seperate";
 +        public static final String MODE_ALL_IN_ONE = "all-in-one";
 +        public static final String MODE_DEFAULT = "all-in-one";
 +
 +        private AFPBorderPainter delegate;
 +        private final AFPPainter painter;
 +        private final AFPDocumentHandler documentHandler;
 +
 +        public AFPBorderPainterAdapter(AFPBorderPainter borderPainter, AFPPainter painter,
 +                AFPDocumentHandler documentHandler) {
              this.delegate = borderPainter;
-                 drawCorner(BEFORE_START, area, bpsBefore, bpsStart,
 +            this.painter = painter;
 +            this.documentHandler = documentHandler;
 +        }
 +
 +        public void drawBorders(final Rectangle borderRect,
 +                final BorderProps bpsBefore, final BorderProps bpsAfter,
 +                final BorderProps bpsStart, final BorderProps bpsEnd, Color innerBackgroundColor)
 +                throws IFException {
 +
 +            if (isRoundedCornersSupported()) {
 +                if (MODE_SEPERATE.equals(System.getProperty(CORNER_MODE_PROPERTY))) {
 +                    try {
 +                        drawRectangularBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd);
 +                    } catch (IOException ioe) {
 +                        throw new IFException("Error drawing border", ioe);
 +                    }
 +                    drawSeperateRoundedCorners(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd,
 +                            innerBackgroundColor);
 +                } else {
 +                    drawRoundedCorners(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd,
 +                            innerBackgroundColor);
 +                }
 +            } else {
 +                try {
 +                    drawRectangularBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd);
 +                } catch (IOException ioe) {
 +                    throw new IFException("Error drawing border", ioe);
 +                }
 +            }
 +        }
 +
 +        private boolean isModeSeperate() {
 +            return (MODE_SEPERATE.equals(System.getProperty(CORNER_MODE_PROPERTY, MODE_DEFAULT)));
 +        }
 +
 +        private boolean isModeAllInOne() {
 +            return (MODE_ALL_IN_ONE.equals(System.getProperty(CORNER_MODE_PROPERTY, MODE_DEFAULT)));
 +        }
 +
 +        private boolean isBackgroundRequired(BorderProps bpsBefore, BorderProps bpsAfter,
 +                BorderProps bpsStart, BorderProps bpsEnd) {
 +
 +            boolean rtn = !(isRoundedCornersSupported() && isModeAllInOne()
 +                    && hasRoundedCorners(bpsBefore,  bpsAfter,
 +                     bpsStart,  bpsEnd));
 +            return rtn;
 +        }
 +
 +        private boolean hasRoundedCorners( final BorderProps bpsBefore, final BorderProps bpsAfter,
 +                final BorderProps bpsStart, final BorderProps bpsEnd) {
 +
 +            return ((bpsStart == null ? false : bpsStart.getRadiusStart() > 0)
 +                        && (bpsBefore == null ? false : bpsBefore.getRadiusStart() > 0))
 +                || ((bpsBefore == null ? false : bpsBefore.getRadiusEnd() > 0)
 +                        && (bpsEnd == null ? false : bpsEnd.getRadiusStart() > 0))
 +                || ((bpsEnd == null ? false : bpsEnd.getRadiusEnd() > 0)
 +                        && (bpsAfter == null ? false : bpsAfter.getRadiusEnd() > 0))
 +                        || ((bpsAfter == null ? false : bpsAfter.getRadiusStart() > 0)
 +                        && (bpsStart == null ? false : bpsStart.getRadiusEnd() > 0));
 +        }
 +
 +        private void drawSeperateRoundedCorners(final Rectangle borderRect,
 +                final BorderProps bpsBefore, final BorderProps bpsAfter,
 +                final BorderProps bpsStart, final BorderProps bpsEnd,
 +                final Color innerBackgroundColor)
 +                    throws IFException {
 +
 +            double esf = cornerScaleFactor(borderRect.width, borderRect.height,
 +                    bpsBefore,  bpsAfter,
 +                    bpsStart,  bpsEnd);
 +
 +            if (bpsBefore != null && bpsStart != null) {
 +                int beforeRadiusStart = (int)(esf *  bpsBefore.getRadiusStart());
 +                int startRadiusStart = (int)(esf *  bpsStart.getRadiusStart());
 +
 +                Rectangle area = new Rectangle(borderRect.x, borderRect.y,
 +                        startRadiusStart,  beforeRadiusStart);
 +
-                 drawCorner(BEFORE_END, area, bpsBefore, bpsEnd,
++                drawCorner(TOP_LEFT, area, bpsBefore, bpsStart,
 +                        beforeRadiusStart, startRadiusStart, innerBackgroundColor);
 +            }
 +
 +            if (bpsEnd != null && bpsBefore != null) {
 +                int endRadiusStart = (int)(esf *  bpsEnd.getRadiusStart());
 +                int beforeRadiusEnd = (int)(esf *  bpsBefore.getRadiusEnd());
 +                Rectangle area = new Rectangle(borderRect.x + borderRect.width - endRadiusStart,
 +                        borderRect.y, endRadiusStart,  beforeRadiusEnd);
 +
-                 drawCorner(AFTER_END, area, bpsAfter, bpsEnd,
++                drawCorner(TOP_RIGHT, area, bpsBefore, bpsEnd,
 +                        beforeRadiusEnd, endRadiusStart, innerBackgroundColor);
 +            }
 +
 +
 +            if (bpsEnd != null && bpsAfter != null) {
 +                int endRadiusEnd = (int)(esf *  bpsEnd.getRadiusEnd());
 +                int afterRadiusEnd = (int)(esf *  bpsAfter.getRadiusEnd());
 +
 +                Rectangle area = new Rectangle(borderRect.x + borderRect.width - endRadiusEnd,
 +                        borderRect.y + borderRect.height - afterRadiusEnd,
 +                        endRadiusEnd,   afterRadiusEnd);
 +
-                 drawCorner(AFTER_START, area, bpsAfter, bpsStart,
++                drawCorner(BOTTOM_RIGHT, area, bpsAfter, bpsEnd,
 +                        afterRadiusEnd, endRadiusEnd, innerBackgroundColor);
 +
 +            }
 +
 +            if (bpsStart != null && bpsAfter != null) {
 +                int startRadiusEnd = (int)(esf *  bpsStart.getRadiusEnd());
 +                int afterRadiusStart = (int)(esf *  bpsAfter.getRadiusStart());
 +                Rectangle area = new Rectangle(borderRect.x ,
 +                        borderRect.y + borderRect.height - afterRadiusStart,
 +                        startRadiusEnd, afterRadiusStart);
 +
-             if (!roundCorner[BEFORE_START] && !roundCorner[BEFORE_END]
-                         && !roundCorner[AFTER_END] && !roundCorner[AFTER_START]) {
++                drawCorner(BOTTOM_LEFT, area, bpsAfter, bpsStart,
 +                        afterRadiusStart, startRadiusEnd, innerBackgroundColor);
 +            }
 +        }
 +
 +        private void drawRoundedCorners(final Rectangle borderRect,
 +                final BorderProps bpsBefore, final BorderProps bpsAfter,
 +                final BorderProps bpsStart, final BorderProps bpsEnd,
 +                final Color innerBackgroundColor)
 +        throws IFException {
 +
 +
 +            final double esf = cornerScaleFactor(borderRect.width, borderRect.height,
 +                    bpsBefore,  bpsAfter,
 +                    bpsStart,  bpsEnd);
 +
 +            final boolean[] roundCorner = new boolean[]{
 +                    bpsBefore != null  && bpsStart != null
 +                        && bpsBefore.getRadiusStart() > 0
 +                        && bpsStart.getRadiusStart() > 0
 +                        && bpsBefore.mode != BorderProps.COLLAPSE_OUTER
 +                        && bpsStart.mode != BorderProps.COLLAPSE_OUTER,
 +                    bpsEnd != null && bpsBefore != null
 +                        && bpsEnd.getRadiusStart() > 0
 +                        && bpsBefore.getRadiusEnd() > 0
 +                        && bpsEnd.mode != BorderProps.COLLAPSE_OUTER
 +                        && bpsBefore.mode != BorderProps.COLLAPSE_OUTER,
 +                    bpsEnd != null && bpsAfter != null
 +                        && bpsEnd.getRadiusEnd() > 0
 +                        && bpsAfter.getRadiusEnd() > 0
 +                        && bpsEnd.mode != BorderProps.COLLAPSE_OUTER
 +                        && bpsAfter.mode != BorderProps.COLLAPSE_OUTER,
 +                    bpsStart != null && bpsAfter != null
 +                        && bpsStart.getRadiusEnd() > 0
 +                        && bpsAfter.getRadiusStart() > 0
 +                        && bpsStart.mode != BorderProps.COLLAPSE_OUTER
 +                        && bpsAfter.mode != BorderProps.COLLAPSE_OUTER
 +                   };
 +
 +
-                             case BEFORE_START:
++            if (!roundCorner[TOP_LEFT] && !roundCorner[TOP_RIGHT]
++                        && !roundCorner[BOTTOM_RIGHT] && !roundCorner[BOTTOM_LEFT]) {
 +                try {
 +                    drawRectangularBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd);
 +                } catch (IOException ioe) {
 +                    throw new IFException("IO error drawing borders", ioe);
 +                }
 +                return;
 +            }
 +
 +            String areaKey = makeKey(borderRect,
 +                    bpsBefore, bpsEnd, bpsAfter,
 +                    bpsStart, innerBackgroundColor);
 +
 +            Graphics2DImagePainter painter = null;
 +            String name = documentHandler.getCachedRoundedCorner(areaKey);
 +
 +            if (name == null) {
 +
 +                name = documentHandler.cacheRoundedCorner(areaKey);
 +
 +                painter = new BorderImagePainter(esf, borderRect,
 +                        bpsStart, bpsEnd, bpsBefore, bpsAfter,
 +                        roundCorner, innerBackgroundColor);
 +            }
 +            paintCornersAsBitmap(painter, borderRect, name);
 +        }
 +
 +
 +        private Area makeCornerClip(final int beforeRadius, final int startRadius,
 +                 final AffineTransform transform) {
 +
 +            Rectangle clipR = new Rectangle(0, 0, startRadius, beforeRadius);
 +
 +            Area clip = new Area(clipR);
 +
 +            Ellipse2D.Double e = new  Ellipse2D.Double();
 +            e.x = 0;
 +            e.y = 0;
 +            e.width = 2 * startRadius;
 +            e.height = 2 * beforeRadius;
 +
 +            clip.subtract(new Area(e));
 +
 +            clip.transform(transform);
 +            return clip;
 +        }
 +
 +
 +        private Area makeCornerBorderBPD(final int beforeRadius, final int startRadius,
 +                final int beforeWidth, final int startWidth, final AffineTransform transform) {
 +
 +            Rectangle clipR = new Rectangle(0, 0, startRadius, beforeRadius);
 +
 +            Ellipse2D.Double e = new  Ellipse2D.Double();
 +            e.x = 0;
 +            e.y = 0;
 +            e.width = 2 * startRadius;
 +            e.height = 2 * beforeRadius;
 +
 +            Ellipse2D.Double i = new  Ellipse2D.Double();
 +            i.x = startWidth;
 +            i.y = beforeWidth;
 +            i.width = 2 * (startRadius - startWidth);
 +            i.height = 2 * (beforeRadius - beforeWidth);
 +
 +            Area clip = new Area(e);
 +            clip.subtract(new Area(i));
 +            clip.intersect(new Area(clipR));
 +
 +            GeneralPath cut = new GeneralPath();
 +            cut.moveTo(0, 0);
 +            float borderWidthRatio = ((float)beforeWidth) / startWidth;
 +            if (beforeWidth * startRadius > startWidth * beforeRadius) {
 +                cut.lineTo(startRadius, borderWidthRatio * startRadius);
 +                cut.lineTo(startRadius, 0);
 +
 +            } else {
 +                cut.lineTo(startRadius, borderWidthRatio * startRadius);
 +                cut.lineTo(startRadius, 0);
 +            }
 +
 +            clip.intersect(new Area(cut));
 +            clip.transform(transform);
 +            return clip;
 +        }
 +
 +
 +        private Area makeCornerBorderIPD(final int beforeRadius, final int startRadius,
 +                final int beforeWidth, final int startWidth, final AffineTransform transform) {
 +
 +            Rectangle clipR = new Rectangle(0, 0, startRadius, beforeRadius);
 +
 +
 +            Ellipse2D.Double e = new  Ellipse2D.Double();
 +            e.x = 0;
 +            e.y = 0;
 +            e.width = 2 * startRadius;
 +            e.height = 2 * beforeRadius;
 +
 +            Ellipse2D.Double i = new  Ellipse2D.Double();
 +            i.x = startWidth;
 +            i.y = beforeWidth;
 +            i.width = 2 * (startRadius - startWidth);
 +            i.height = 2 * (beforeRadius - beforeWidth);
 +
 +            Area clip = new Area(e);
 +            clip.subtract(new Area(i));
 +            clip.intersect(new Area(clipR));
 +
 +            GeneralPath cut = new GeneralPath();
 +            cut.moveTo(0, 0);
 +            float borderWidthRatio = ((float)beforeWidth) / startWidth;
 +            if (beforeWidth * startRadius > startWidth * beforeRadius) {
 +                cut.lineTo(startRadius, borderWidthRatio * startRadius);
 +                cut.lineTo(startRadius, 0);
 +
 +            } else {
 +                cut.lineTo(startRadius, borderWidthRatio * startRadius);
 +                cut.lineTo(startRadius, 0);
 +            }
 +
 +            clip.subtract(new Area(cut));
 +            clip.transform(transform);
 +            return clip;
 +        }
 +
 +        /* TODO collect  parameters in a useful structure */
 +        private void paintCorner(final Graphics2D g2d, final int beforeWidth,
 +                final int startWidth, final  int beforeRadius,
 +                final int startRadius, final Color innerBackgroundColor,
 +                final Color beforeColor, final Color startColor) {
 +
 +            //Draw the before-srart corner
 +            Ellipse2D.Double inner = new  Ellipse2D.Double();
 +            inner.x = startWidth;
 +            inner.y = beforeWidth;
 +            inner.width =  2 * (startRadius - startWidth);
 +            inner.height =  2 * (beforeRadius - beforeWidth);
 +
 +            Ellipse2D.Double outer = new  Ellipse2D.Double();
 +            outer.x = 0;
 +            outer.y = 0;
 +            outer.width =   2 * (startRadius);
 +            outer.height =  2 * (beforeRadius);
 +
 +            Area border = new Area(outer);
 +            border.subtract(new Area(inner));
 +
 +            GeneralPath afterCut = new GeneralPath();
 +            GeneralPath beforeCut = new GeneralPath();
 +            afterCut.moveTo(0, 0);
 +            beforeCut.moveTo(0, 0);
 +            float borderWidthRatio = ((float)beforeWidth) / startWidth;
 +            if (beforeWidth * startRadius > startWidth * beforeRadius) {
 +                afterCut.lineTo(startRadius, borderWidthRatio * startRadius);
 +                beforeCut.lineTo(1f / borderWidthRatio * beforeRadius, beforeRadius);
 +
 +                afterCut.lineTo(startRadius, 0);
 +                beforeCut.lineTo(0, beforeRadius);
 +            } else {
 +                afterCut.lineTo(startRadius, (borderWidthRatio * startRadius));
 +                beforeCut.lineTo(1f / borderWidthRatio * beforeRadius, beforeRadius);
 +
 +                afterCut.lineTo(startRadius, 0);
 +                beforeCut.lineTo(0, beforeRadius);
 +
 +            }
 +
 +            //start
 +            g2d.setColor(startColor);
 +            g2d.fill(border);
 +
 +            //before
 +            border = new Area(outer);
 +            border.subtract(new Area(inner));
 +            border.subtract(new Area(beforeCut));
 +
 +            //start
 +            g2d.setColor(beforeColor);
 +            g2d.fill(border);
 +
 +            //paint background
 +            if (innerBackgroundColor == null) {
 +                g2d.setColor(Color.white);
 +              //  log.warn("No background color set");
 +
 +            } else {
 +                g2d.setColor(innerBackgroundColor);
 +            }
 +
 +            g2d.fill(inner);
 +        }
 +
 +
 +        private void drawCorner(final int corner, final Rectangle area,
 +                final BorderProps before, final BorderProps start,
 +                final int beforeRadius, final int startRadius, final Color innerBackground)
 +                throws IFException {
 +
 +            if (beforeRadius > 0 && startRadius > 0) {
 +                String cornerKey = makeCornerKey(corner, before, start,
 +                        beforeRadius, startRadius, innerBackground);
 +
 +                Graphics2DImagePainter painter = null;
 +
 +                String name = documentHandler.getCachedRoundedCorner(cornerKey);
 +
 +                //  If the corner is not in the cache we construct a Graphics2DImagePainter
 +                //  that paints the corner
 +                if (name == null) {
 +                    //Cache the name
 +                    name = documentHandler.cacheRoundedCorner(cornerKey);
 +
 +                    // create the Graphics2DImagePainter
 +                    painter = new Graphics2DImagePainter() {
 +                        public void paint(Graphics2D g2d, Rectangle2D area) {
 +
 +                            int beforeWidth = before.width;
 +                            int startWidth = start.width;
 +
 +                            Color beforeColor = before.color;
 +                            Color startColor = start.color;
 +
 +                            //No transformation
 +                            AffineTransform t;
 +                            switch(corner) {
-                             case BEFORE_END:
++                            case TOP_LEFT:
 +                                //No transform required
 +                                break;
-                             case AFTER_END:
++                            case TOP_RIGHT:
 +                                t = new AffineTransform(-1, 0, 0, 1, startRadius, 0);
 +                                g2d.transform(t);
 +                                break;
-                             case AFTER_START:
++                            case BOTTOM_RIGHT:
 +                                t = new AffineTransform(-1, 0, 0, -1, startRadius, beforeRadius);
 +                                g2d.transform(t);
 +                                break;
++                            case BOTTOM_LEFT:
 +                                t = new AffineTransform(1, 0, 0, -1, 0, beforeRadius);
 +                                g2d.transform(t);
 +                                break;
 +                            default: break;
 +                            }
 +
 +                            paintCorner(g2d, beforeWidth, startWidth,
 +                                    beforeRadius, startRadius, innerBackground,
 +                                    beforeColor,  startColor);
 +                        }
 +
 +                        public Dimension getImageSize() {
 +                            return area.getSize();
 +                        }
 +                    };
 +                }
 +                paintCornersAsBitmap(painter, area, name);
 +            }
 +        }
 +
 +
 +        private String makeCornerKey(int corner, BorderProps beforeProps, BorderProps startProps,
 +                int beforeRadius, int startRadius, Color innerBackgroundColor) {
 +
 +           return hash(new StringBuffer()
 +                   .append(corner)
 +                   .append(":")
 +                   .append(beforeRadius)
 +                   .append(":")
 +                   .append(startRadius)
 +                   .append(":")
 +                   .append(beforeProps.width)
 +                   .append(":")
 +                   .append(startProps.width)
 +                   .append(":")
 +                   .append(beforeProps.color)
 +                   .append(":")
 +                   .append(startProps.color)
 +                   .append(":")
 +                   .append(innerBackgroundColor)
 +                   .toString());
 +        }
 +
 +
 +        private String makeKey(Rectangle area, BorderProps beforeProps,
 +                BorderProps endProps, BorderProps afterProps, BorderProps startProps,
 +                 Color innerBackgroundColor) {
 +
 +            return hash(new StringBuffer()
 +                    .append(area.width)
 +                    .append(":")
 +                    .append(area.height)
 +                    .append(":")
 +                    .append(beforeProps)
 +                    .append(":")
 +                    .append(endProps)
 +                    .append(":")
 +                    .append(afterProps)
 +                    .append(":")
 +                    .append(startProps)
 +                    .append(":")
 +                    .append(innerBackgroundColor)
 +                    .toString());
 +        }
 +
 +
 +        private String hash(String text) {
 +
 +            MessageDigest md;
 +            try {
 +                md = MessageDigest.getInstance("MD5");
 +            } catch (Exception e) {
 +                throw new RuntimeException("Internal error", e);
 +            }
 +
 +            byte[] result = md.digest(text.getBytes());
 +
 +            StringBuffer sb = new StringBuffer();
 +            char[] digits = {'0', '1', '2', '3', '4', '5', '6',
 +                    '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
 +            for (int idx = 0; idx < 6; ++idx) {
 +              byte b = result[idx];
 +              sb.append(digits[(b & 0xf0) >> 4]);
 +              sb.append(digits[b & 0x0f]);
 +            }
 +            return sb.toString();
 +        }
 +
 +        private void paintCornersAsBitmap(Graphics2DImagePainter painter,
 +                Rectangle boundingBox, String name) throws IFException {
 +            //TODO parameters ok?
 +            ImageInfo info = new ImageInfo(name, null);
 +
 +            ImageSize size = new ImageSize();
 +            size.setSizeInMillipoints(boundingBox.width, boundingBox.height);
 +
 +            //Use the foreign attributes map to set image handling hints
 +            Map map = new java.util.HashMap(2);
 +            map.put(AFPForeignAttributeReader.RESOURCE_NAME, name);
 +            map.put(AFPForeignAttributeReader.RESOURCE_LEVEL, "print-file");
 +
 +            AFPRenderingContext context = (AFPRenderingContext)
 +                    this.painter.createRenderingContext(/*map*/);
 +
 +            size.setResolution(context.getPaintingState().getResolution());
 +            size.calcPixelsFromSize();
 +            info.setSize(size);
 +            ImageGraphics2D img = new ImageGraphics2D(info, painter);
 +
 +            Map hints = new java.util.HashMap();
 +
 +            hints.put(ImageHandlerUtil.CONVERSION_MODE, ImageHandlerUtil.CONVERSION_MODE_BITMAP);
 +            hints.put("TARGET_RESOLUTION",
 +                    new Integer(context.getPaintingState().getResolution()));
 +
 +
 +            try {
 +                this.painter.drawImage(img, boundingBox, context, true, hints);
 +            } catch (IOException ioe) {
 +                throw new IFException(
 +                        "I/O error while painting corner using a bitmap", ioe);
 +            } catch (ImageException ie) {
 +                throw new IFException(
 +                        "Image error while painting corner using a bitmap", ie);
 +            }
          }
  
+         @Override
          protected void clip() throws IOException {
              //not supported by AFP
          }
              delegate.paint(borderPaintInfo);
          }
  
+         @Override
          public void drawLine(Point start, Point end, int width, Color color, RuleStyle style)
 -                throws IOException {
 +        throws IOException {
              if (start.y != end.y) {
                  //TODO Support arbitrary lines if necessary
                  throw new UnsupportedOperationException(
      }
  
      /** {@inheritDoc} */
+     @Override
      public void drawLine(Point start, Point end, int width, Color color, RuleStyle style)
 -                throws IFException {
 +    throws IFException {
          try {
              this.borderPainter.drawLine(start, end, width, color, style);
          } catch (IOException ioe) {
index ca907eb0d76301c5f3734aa34b9f767a2f83eacc,c696e552d7e1c004b3116a6fe62ae4cdcdf63579..9651cf4461d0e551aefb4abd3a3bbdba0daf24a3
@@@ -314,31 -315,31 +315,31 @@@ public abstract class AbstractIFPainte
      }
  
      /** {@inheritDoc} */
-     public void drawBorderRect(Rectangle rect, BorderProps before, BorderProps after,
-             BorderProps start, BorderProps end, Color innerBackgroundColor) throws IFException {
-         if (before != null) {
+     public void drawBorderRect(Rectangle rect, BorderProps top, BorderProps bottom,
 -            BorderProps left, BorderProps right) throws IFException {
++            BorderProps left, BorderProps right, Color innerBackgroundColor) throws IFException {
+         if (top != null) {
              Rectangle b = new Rectangle(
                      rect.x, rect.y,
-                     rect.width, before.width);
-             fillRect(b, before.color);
+                     rect.width, top.width);
+             fillRect(b, top.color);
          }
-         if (end != null) {
+         if (right != null) {
              Rectangle b = new Rectangle(
-                     rect.x + rect.width - end.width, rect.y,
-                     end.width, rect.height);
-             fillRect(b, end.color);
+                     rect.x + rect.width - right.width, rect.y,
+                     right.width, rect.height);
+             fillRect(b, right.color);
          }
-         if (after != null) {
+         if (bottom != null) {
              Rectangle b = new Rectangle(
-                     rect.x, rect.y + rect.height - after.width,
-                     rect.width, after.width);
-             fillRect(b, after.color);
+                     rect.x, rect.y + rect.height - bottom.width,
+                     rect.width, bottom.width);
+             fillRect(b, bottom.color);
          }
-         if (start != null) {
+         if (left != null) {
              Rectangle b = new Rectangle(
                      rect.x, rect.y,
-                     start.width, rect.height);
-             fillRect(b, start.color);
+                     left.width, rect.height);
+             fillRect(b, left.color);
          }
      }
  
index 5cf50ecbbe93f4c510d9f55353d8ecc507756f16,cc28028ef892b85217f05d7c6d051d43d15c6fcf..0ff5c20361695ae461153a3cbfdba771d6fb5d37
@@@ -32,69 -32,18 +32,70 @@@ import org.apache.fop.traits.RuleStyle
   */
  public abstract class BorderPainter {
  
-      * convention index of before, end, after and start borders */
-     protected static final int BEFORE = 0, END = 1, AFTER = 2, START = 3;
 +    /** TODO remove before integration*/
 +    public static final String ROUNDED_CORNERS = "fop.round-corners";
 +
 +    /** TODO Use a class to model border instead of an array
-      convention index of before_start, before_end, after_end and after_start border corners*/
-     protected static final int BEFORE_START = 0, BEFORE_END = 1, AFTER_END = 2, AFTER_START = 3;
++     * convention index of top, bottom, right and left borders */
++    protected static final int TOP = 0, RIGHT = 1, BOTTOM = 2, LEFT = 3;
 +    /** TODO Use a class to model border corners instead of an array
++     convention index of top-left, top-right, bottom-right and bottom-left border corners*/
++    protected static final int TOP_LEFT = 0, TOP_RIGHT = 1, BOTTOM_RIGHT = 2, BOTTOM_LEFT = 3;
 +
 +
      /**
       * Draws borders.
       * @param borderRect the border rectangle
-      * @param bpsBefore the border specification on the before side
-      * @param bpsAfter the border specification on the after side
-      * @param bpsStart the border specification on the start side
-      * @param bpsEnd the border specification on the end side
+      * @param bpsTop the border specification on the top side
+      * @param bpsBottom the border specification on the bottom side
+      * @param bpsLeft the border specification on the left side
+      * @param bpsRight the border specification on the end side
 -     * @throws IOException if an I/O error occurs while creating the borders
 +     * @param innerBackgroundColor the inner background color
 +     * @throws IFException if an error occurs while drawing the borders
       */
      public void drawBorders(Rectangle borderRect,               // CSOK: MethodLength
-             BorderProps bpsBefore, BorderProps bpsAfter,
-             BorderProps bpsStart, BorderProps bpsEnd, Color innerBackgroundColor)
++            BorderProps bpsTop, BorderProps bpsBottom,
++            BorderProps bpsLeft, BorderProps bpsRight, Color innerBackgroundColor)
 +                throws IFException {
 +
 +        try {
 +            if (isRoundedCornersSupported()) {
-                 drawRoundedBorders(borderRect, bpsBefore, bpsAfter,
-                         bpsStart, bpsEnd);
++                drawRoundedBorders(borderRect, bpsTop, bpsBottom,
++                        bpsLeft, bpsRight);
 +
 +            } else {
-                 drawRectangularBorders(borderRect, bpsBefore, bpsAfter,
-                         bpsStart, bpsEnd);
++                drawRectangularBorders(borderRect, bpsTop, bpsBottom,
++                        bpsLeft, bpsRight);
 +            }
 +
 +        } catch (IOException ioe) {
 +            throw new IFException("IO error drawing borders", ioe);
 +        }
 +    }
 +
 +    private BorderProps sanitizeBorderProps(BorderProps bps) {
 +        return bps == null ? bps : bps.width == 0 ? (BorderProps)null : bps;
 +    }
 +
 +    /**
 +     * TODO merge with drawRoundedBorders()?
 +     * @param borderRect the border rectangle
-      * @param bpsBefore the border specification on the before side
-      * @param bpsAfter the border specification on the after side
-      * @param bpsStart the border specification on the start side
-      * @param bpsEnd the border specification on the end side
++     * @param bpsTop the border specification on the top side
++     * @param bpsBottom the border specification on the bottom side
++     * @param bpsLeft the border specification on the left side
++     * @param bpsRight the border specification on the end side
 +     * @throws IOException
 +     */
 +    protected void drawRectangularBorders(Rectangle borderRect,
-             BorderProps bpsBefore, BorderProps bpsAfter,
-             BorderProps bpsStart, BorderProps bpsEnd) throws IOException {
+             BorderProps bpsTop, BorderProps bpsBottom,
+             BorderProps bpsLeft, BorderProps bpsRight) throws IOException {
++
++        bpsTop = sanitizeBorderProps(bpsTop);
++        bpsBottom = sanitizeBorderProps(bpsBottom);
++        bpsLeft = sanitizeBorderProps(bpsLeft);
++        bpsRight = sanitizeBorderProps(bpsRight);
 +
-         bpsBefore = sanitizeBorderProps(bpsBefore);
-         bpsAfter = sanitizeBorderProps(bpsAfter);
-         bpsStart = sanitizeBorderProps(bpsStart);
-         bpsEnd = sanitizeBorderProps(bpsEnd);
 +
          int startx = borderRect.x;
          int starty = borderRect.y;
          int width = borderRect.width;
              return;
          }
          int[] bw = new int[] {
-                 (b[BEFORE] ? bpsBefore.width : 0),
-                 (b[END] ? bpsEnd.width : 0),
-                 (b[AFTER] ? bpsAfter.width : 0),
-                 (b[3] ? bpsStart.width : 0)};
+             (b[0] ? bpsTop.width : 0),
+             (b[1] ? bpsRight.width : 0),
+             (b[2] ? bpsBottom.width : 0),
+             (b[3] ? bpsLeft.width : 0)};
          int[] clipw = new int[] {
-                 BorderProps.getClippedWidth(bpsBefore),
-                 BorderProps.getClippedWidth(bpsEnd),
-                 BorderProps.getClippedWidth(bpsAfter),
-                 BorderProps.getClippedWidth(bpsStart)};
-         starty += clipw[BEFORE];
-         height -= clipw[BEFORE];
-         height -= clipw[AFTER];
-         startx += clipw[START];
-         width -= clipw[START];
-         width -= clipw[END];
+             BorderProps.getClippedWidth(bpsTop),
+             BorderProps.getClippedWidth(bpsRight),
+             BorderProps.getClippedWidth(bpsBottom),
+             BorderProps.getClippedWidth(bpsLeft)};
+         starty += clipw[0];
+         height -= clipw[0];
+         height -= clipw[2];
+         startx += clipw[3];
+         width -= clipw[3];
+         width -= clipw[1];
  
          boolean[] slant = new boolean[] {
-                 (b[START] && b[BEFORE]),
-                 (b[BEFORE] && b[END]),
-                 (b[END] && b[AFTER]),
-                 (b[AFTER] && b[START])};
-         if (bpsBefore != null) {
+             (b[3] && b[0]), (b[0] && b[1]), (b[1] && b[2]), (b[2] && b[3])};
+         if (bpsTop != null) {
              int sx1 = startx;
-             int sx2 = (slant[BEFORE_START] ? sx1 + bw[START] - clipw[START] : sx1);
 -            int sx2 = (slant[0] ? sx1 + bw[3] - clipw[3] : sx1);
++            int sx2 = (slant[TOP_LEFT] ? sx1 + bw[LEFT] - clipw[LEFT] : sx1);
              int ex1 = startx + width;
-             int ex2 = (slant[BEFORE_END] ? ex1 - bw[END] + clipw[END] : ex1);
-             int outery = starty - clipw[BEFORE];
-             int clipy = outery + clipw[BEFORE];
-             int innery = outery + bw[BEFORE];
 -            int ex2 = (slant[1] ? ex1 - bw[1] + clipw[1] : ex1);
 -            int outery = starty - clipw[0];
 -            int clipy = outery + clipw[0];
 -            int innery = outery + bw[0];
++            int ex2 = (slant[TOP_RIGHT] ? ex1 - bw[RIGHT] + clipw[RIGHT] : ex1);
++            int outery = starty - clipw[TOP];
++            int clipy = outery + clipw[TOP];
++            int innery = outery + bw[TOP];
  
              saveGraphicsState();
              moveTo(sx1, clipy);
 +
 +
              int sx1a = sx1;
              int ex1a = ex1;
-             if (bpsBefore.mode == BorderProps.COLLAPSE_OUTER) {
-                 if (bpsStart != null && bpsStart.mode == BorderProps.COLLAPSE_OUTER) {
-                     sx1a -= clipw[START];
+             if (bpsTop.mode == BorderProps.COLLAPSE_OUTER) {
+                 if (bpsLeft != null && bpsLeft.mode == BorderProps.COLLAPSE_OUTER) {
+                     sx1a -= clipw[3];
                  }
-                 if (bpsEnd != null && bpsEnd.mode == BorderProps.COLLAPSE_OUTER) {
-                     ex1a += clipw[END];
+                 if (bpsRight != null && bpsRight.mode == BorderProps.COLLAPSE_OUTER) {
+                     ex1a += clipw[1];
                  }
                  lineTo(sx1a, outery);
                  lineTo(ex1a, outery);
              closePath();
              clip();
              drawBorderLine(sx1a, outery, ex1a, innery, true, true,
-                     bpsBefore.style, bpsBefore.color);
+                     bpsTop.style, bpsTop.color);
              restoreGraphicsState();
          }
-         if (bpsEnd != null) {
+         if (bpsRight != null) {
              int sy1 = starty;
-             int sy2 = (slant[BEFORE_END] ? sy1 + bw[BEFORE] - clipw[BEFORE] : sy1);
 -            int sy2 = (slant[1] ? sy1 + bw[0] - clipw[0] : sy1);
++            int sy2 = (slant[TOP_RIGHT] ? sy1 + bw[TOP] - clipw[TOP] : sy1);
              int ey1 = starty + height;
-             int ey2 = (slant[AFTER_END] ? ey1 - bw[AFTER] + clipw[AFTER] : ey1);
-             int outerx = startx + width + clipw[END];
-             int clipx = outerx - clipw[END];
-             int innerx = outerx - bw[END];
 -            int ey2 = (slant[2] ? ey1 - bw[2] + clipw[2] : ey1);
 -            int outerx = startx + width + clipw[1];
 -            int clipx = outerx - clipw[1];
 -            int innerx = outerx - bw[1];
++            int ey2 = (slant[BOTTOM_RIGHT] ? ey1 - bw[BOTTOM] + clipw[BOTTOM] : ey1);
++            int outerx = startx + width + clipw[RIGHT];
++            int clipx = outerx - clipw[RIGHT];
++            int innerx = outerx - bw[RIGHT];
  
              saveGraphicsState();
              moveTo(clipx, sy1);
              int sy1a = sy1;
              int ey1a = ey1;
-             if (bpsEnd.mode == BorderProps.COLLAPSE_OUTER) {
-                 if (bpsBefore != null && bpsBefore.mode == BorderProps.COLLAPSE_OUTER) {
-                     sy1a -= clipw[BEFORE];
+             if (bpsRight.mode == BorderProps.COLLAPSE_OUTER) {
+                 if (bpsTop != null && bpsTop.mode == BorderProps.COLLAPSE_OUTER) {
 -                    sy1a -= clipw[0];
++                    sy1a -= clipw[TOP];
                  }
-                 if (bpsAfter != null && bpsAfter.mode == BorderProps.COLLAPSE_OUTER) {
-                     ey1a += clipw[AFTER];
+                 if (bpsBottom != null && bpsBottom.mode == BorderProps.COLLAPSE_OUTER) {
 -                    ey1a += clipw[2];
++                    ey1a += clipw[BOTTOM];
                  }
                  lineTo(outerx, sy1a);
                  lineTo(outerx, ey1a);
              lineTo(innerx, sy2);
              closePath();
              clip();
-             drawBorderLine(innerx, sy1a, outerx, ey1a, false, false, bpsEnd.style, bpsEnd.color);
+             drawBorderLine(innerx, sy1a, outerx, ey1a, false, false,
+                            bpsRight.style, bpsRight.color);
              restoreGraphicsState();
          }
-         if (bpsAfter != null) {
+         if (bpsBottom != null) {
              int sx1 = startx;
-             int sx2 = (slant[AFTER_START] ? sx1 + bw[START] - clipw[START] : sx1);
 -            int sx2 = (slant[3] ? sx1 + bw[3] - clipw[3] : sx1);
++            int sx2 = (slant[BOTTOM_LEFT] ? sx1 + bw[LEFT] - clipw[LEFT] : sx1);
              int ex1 = startx + width;
-             int ex2 = (slant[AFTER_END] ? ex1 - bw[END] + clipw[END] : ex1);
-             int outery = starty + height + clipw[AFTER];
-             int clipy = outery - clipw[AFTER];
-             int innery = outery - bw[AFTER];
 -            int ex2 = (slant[2] ? ex1 - bw[1] + clipw[1] : ex1);
 -            int outery = starty + height + clipw[2];
 -            int clipy = outery - clipw[2];
 -            int innery = outery - bw[2];
++            int ex2 = (slant[BOTTOM_RIGHT] ? ex1 - bw[RIGHT] + clipw[RIGHT] : ex1);
++            int outery = starty + height + clipw[BOTTOM];
++            int clipy = outery - clipw[BOTTOM];
++            int innery = outery - bw[BOTTOM];
  
              saveGraphicsState();
              moveTo(ex1, clipy);
              int sx1a = sx1;
              int ex1a = ex1;
-             if (bpsAfter.mode == BorderProps.COLLAPSE_OUTER) {
-                 if (bpsStart != null && bpsStart.mode == BorderProps.COLLAPSE_OUTER) {
-                     sx1a -= clipw[START];
+             if (bpsBottom.mode == BorderProps.COLLAPSE_OUTER) {
+                 if (bpsLeft != null && bpsLeft.mode == BorderProps.COLLAPSE_OUTER) {
 -                    sx1a -= clipw[3];
++                    sx1a -= clipw[LEFT];
                  }
-                 if (bpsEnd != null && bpsEnd.mode == BorderProps.COLLAPSE_OUTER) {
-                     ex1a += clipw[END];
+                 if (bpsRight != null && bpsRight.mode == BorderProps.COLLAPSE_OUTER) {
 -                    ex1a += clipw[1];
++                    ex1a += clipw[RIGHT];
                  }
                  lineTo(ex1a, outery);
                  lineTo(sx1a, outery);
              lineTo(ex2, innery);
              closePath();
              clip();
-             drawBorderLine(sx1a, innery, ex1a, outery, true, false, bpsAfter.style, bpsAfter.color);
+             drawBorderLine(sx1a, innery, ex1a, outery, true, false,
+                            bpsBottom.style, bpsBottom.color);
              restoreGraphicsState();
          }
-         if (bpsStart != null) {
+         if (bpsLeft != null) {
              int sy1 = starty;
-             int sy2 = (slant[BEFORE_START] ? sy1 + bw[BEFORE] - clipw[BEFORE] : sy1);
 -            int sy2 = (slant[0] ? sy1 + bw[0] - clipw[0] : sy1);
++            int sy2 = (slant[TOP_LEFT] ? sy1 + bw[TOP] - clipw[TOP] : sy1);
              int ey1 = sy1 + height;
-             int ey2 = (slant[AFTER_START] ? ey1 - bw[AFTER] + clipw[AFTER] : ey1);
-             int outerx = startx - clipw[START];
-             int clipx = outerx + clipw[START];
-             int innerx = outerx + bw[START];
 -            int ey2 = (slant[3] ? ey1 - bw[2] + clipw[2] : ey1);
 -            int outerx = startx - clipw[3];
 -            int clipx = outerx + clipw[3];
 -            int innerx = outerx + bw[3];
++            int ey2 = (slant[BOTTOM_LEFT] ? ey1 - bw[BOTTOM] + clipw[BOTTOM] : ey1);
++            int outerx = startx - clipw[LEFT];
++            int clipx = outerx + clipw[LEFT];
++            int innerx = outerx + bw[LEFT];
  
              saveGraphicsState();
 +
              moveTo(clipx, ey1);
 +
              int sy1a = sy1;
              int ey1a = ey1;
-             if (bpsStart.mode == BorderProps.COLLAPSE_OUTER) {
-                 if (bpsBefore != null && bpsBefore.mode == BorderProps.COLLAPSE_OUTER) {
-                     sy1a -= clipw[BEFORE];
+             if (bpsLeft.mode == BorderProps.COLLAPSE_OUTER) {
+                 if (bpsTop != null && bpsTop.mode == BorderProps.COLLAPSE_OUTER) {
 -                    sy1a -= clipw[0];
++                    sy1a -= clipw[TOP];
                  }
-                 if (bpsAfter != null && bpsAfter.mode == BorderProps.COLLAPSE_OUTER) {
-                     ey1a += clipw[AFTER];
+                 if (bpsBottom != null && bpsBottom.mode == BorderProps.COLLAPSE_OUTER) {
 -                    ey1a += clipw[2];
++                    ey1a += clipw[BOTTOM];
                  }
                  lineTo(outerx, ey1a);
                  lineTo(outerx, sy1a);
          }
      }
  
-         if (!b[BEFORE] && !b[END] && !b[AFTER] && !b[START]) {
 +    /** TODO merge with drawRectangularBorders?
 +     * @param borderRect the border rectangle
 +     * @param bpsBefore the border specification on the before side
 +     * @param bpsAfter the border specification on the after side
 +     * @param bpsStart the border specification on the start side
 +     * @param bpsEnd the border specification on the end side
 +     * @throws IOException on io exception
 +     * */
 +    protected void drawRoundedBorders(Rectangle borderRect,
 +            BorderProps bpsBefore, BorderProps bpsAfter,
 +            BorderProps bpsStart, BorderProps bpsEnd) throws IOException {
 +
 +        bpsBefore = sanitizeBorderProps(bpsBefore);
 +        bpsAfter = sanitizeBorderProps(bpsAfter);
 +        bpsStart = sanitizeBorderProps(bpsStart);
 +        bpsEnd = sanitizeBorderProps(bpsEnd);
 +
 +        boolean[] b = new boolean[] {
 +                (bpsBefore != null), (bpsEnd != null),
 +                (bpsAfter != null), (bpsStart != null)};
-                 (b[BEFORE] ? bpsBefore.width : 0),
-                 (b[END] ? bpsEnd.width : 0),
-                 (b[AFTER] ? bpsAfter.width : 0),
-                 (b[START] ? bpsStart.width : 0)};
++        if (!b[TOP] && !b[RIGHT] && !b[BOTTOM] && !b[LEFT]) {
 +            return;
 +        }
 +        int[] bw = new int[] {
-         final int startx = borderRect.x + clipw[START];
-         final int starty = borderRect.y + clipw[BEFORE];
-         final int width = borderRect.width - clipw[START] - clipw[END];
-         final int height = borderRect.height - clipw[BEFORE] - clipw[AFTER];
++                (b[TOP] ? bpsBefore.width : 0),
++                (b[RIGHT] ? bpsEnd.width : 0),
++                (b[BOTTOM] ? bpsAfter.width : 0),
++                (b[LEFT] ? bpsStart.width : 0)};
 +
 +        int[] clipw = new int[] {
 +                BorderProps.getClippedWidth(bpsBefore),
 +                BorderProps.getClippedWidth(bpsEnd),
 +                BorderProps.getClippedWidth(bpsAfter),
 +                BorderProps.getClippedWidth(bpsStart)};
 +
-                 (b[START] && b[BEFORE]), (b[BEFORE] && b[END]),
-                 (b[END] && b[AFTER]), (b[START] && b[AFTER])};
++        final int startx = borderRect.x + clipw[LEFT];
++        final int starty = borderRect.y + clipw[TOP];
++        final int width = borderRect.width - clipw[LEFT] - clipw[RIGHT];
++        final int height = borderRect.height - clipw[TOP] - clipw[BOTTOM];
 +
 +        boolean[] slant = new boolean[] {
-             final int sx2 = (slant[BEFORE_START] ? bw[START] - clipw[START] : 0);
++                (b[LEFT] && b[TOP]), (b[TOP] && b[RIGHT]),
++                (b[RIGHT] && b[BOTTOM]), (b[LEFT] && b[BOTTOM])};
 +
 +        //Determine scale factor if any adjacent elliptic corners overlap
 +        double esf = cornerScaleFactor(width, height, bpsBefore, bpsAfter, bpsStart, bpsEnd);
 +
 +        if (bpsBefore != null) {
 +            //Let x increase in the START->END direction
-             final int ex2 = (slant[BEFORE_END] ? ex1 - bw[END] + clipw[END] : ex1);
-             final int outery = -clipw[BEFORE];
-             final int innery = outery + bw[BEFORE];
-             final int clipy = outery + clipw[BEFORE];
++            final int sx2 = (slant[TOP_LEFT] ? bw[LEFT] - clipw[LEFT] : 0);
 +            final int ex1 =  width;
-                     clipw[START], clipw[END],
++            final int ex2 = (slant[TOP_RIGHT] ? ex1 - bw[RIGHT] + clipw[RIGHT] : ex1);
++            final int outery = -clipw[TOP];
++            final int innery = outery + bw[TOP];
++            final int clipy = outery + clipw[TOP];
 +            final int ellipseSBW = bpsStart == null ? 0 : (int)(esf * bpsStart.getRadiusStart());
 +            final int ellipseSBH = (int)(esf * bpsBefore.getRadiusStart());
 +            final int ellipseSBX = ellipseSBW;
 +            final int ellipseSBY = clipy + ellipseSBH;
 +            final int ellipseBEW = bpsEnd == null ? 0 : (int)(esf * bpsEnd.getRadiusStart());
 +            final int ellipseBEH = (int)(esf * bpsBefore.getRadiusEnd());
 +            final int ellipseBEX = ex1 - ellipseBEW;
 +            final int ellipseBEY = clipy + ellipseBEH;
 +
 +            saveGraphicsState();
 +            translateCoordinates(startx, starty);
 +            drawBorderSegment( sx2, ex1, ex2,  outery, innery,
-             final int sx2 = (slant[AFTER_START] ?  bw[AFTER] - clipw[AFTER] : 0);
++                    clipw[LEFT], clipw[RIGHT],
 +                    ellipseSBX, ellipseSBY, ellipseSBW, ellipseSBH,
 +                    ellipseBEX, ellipseBEY, ellipseBEW, ellipseBEH,
 +                    bpsBefore, bpsStart, bpsEnd
 +            );
 +            restoreGraphicsState();
 +        }
 +
 +        if (bpsStart != null) {
 +            //Let x increase in the AFTER->BEFORE direction
-             final int ex2 = (slant[BEFORE_START] ? ex1 - bw[BEFORE] + clipw[BEFORE] : ex1);
-             final int outery = -clipw[START];
-             final int innery = outery + bw[START];
-             final int clipy = outery + clipw[START];
++            final int sx2 = (slant[BOTTOM_LEFT] ?  bw[BOTTOM] - clipw[BOTTOM] : 0);
 +            final int ex1 = height;
-                     clipw[AFTER],  clipw[BEFORE],
++            final int ex2 = (slant[TOP_LEFT] ? ex1 - bw[TOP] + clipw[TOP] : ex1);
++            final int outery = -clipw[LEFT];
++            final int innery = outery + bw[LEFT];
++            final int clipy = outery + clipw[LEFT];
 +            final int ellipseSBW = bpsAfter == null ? 0 : (int)(esf * bpsAfter.getRadiusStart());
 +            final int ellipseSBH = (int)(esf * bpsStart.getRadiusEnd());
 +            final int ellipseSBX = ellipseSBW;
 +            final int ellipseSBY = clipy + ellipseSBH;
 +            final int ellipseBEW = bpsBefore == null ? 0 : (int)(esf * bpsBefore.getRadiusStart());
 +            final int ellipseBEH = (int)(esf * bpsStart.getRadiusStart());
 +            final int ellipseBEX = ex1 - ellipseBEW;
 +            final int ellipseBEY = clipy + ellipseBEH;
 +
 +            saveGraphicsState();
 +            translateCoordinates(startx, starty + height);
 +            rotateCoordinates(Math.PI * 3d / 2d);
 +            drawBorderSegment( sx2, ex1, ex2, outery, innery,
-             final int sx2 = (slant[AFTER_START] ?  bw[START] - clipw[START] : 0);
++                    clipw[BOTTOM],  clipw[TOP],
 +                    ellipseSBX, ellipseSBY, ellipseSBW, ellipseSBH,
 +                    ellipseBEX, ellipseBEY, ellipseBEW, ellipseBEH,
 +                    bpsStart, bpsAfter, bpsBefore
 +            );
 +            restoreGraphicsState();
 +
 +        }
 +
 +
 +        if (bpsAfter != null) {
 +            //Let x increase in the START->END direction
-             final int ex2 = (slant[AFTER_END] ? ex1 - bw[END] + clipw[END] : ex1);
-             final int outery = -clipw[AFTER];
-             final int innery = outery + bw[AFTER];
-             final int clipy = outery + clipw[AFTER];
++            final int sx2 = (slant[BOTTOM_LEFT] ?  bw[LEFT] - clipw[LEFT] : 0);
 +            final int ex1 = width;
-                     clipw[START], clipw[END],
++            final int ex2 = (slant[BOTTOM_RIGHT] ? ex1 - bw[RIGHT] + clipw[RIGHT] : ex1);
++            final int outery = -clipw[BOTTOM];
++            final int innery = outery + bw[BOTTOM];
++            final int clipy = outery + clipw[BOTTOM];
 +            final int ellipseSBW = bpsStart == null ? 0 : (int)(esf * bpsStart.getRadiusEnd());
 +            final int ellipseSBH =  (int)(esf * bpsAfter.getRadiusStart());
 +            final int ellipseSBX = ellipseSBW;
 +            final int ellipseSBY =  clipy + ellipseSBH;
 +            final int ellipseBEW = bpsEnd == null ? 0 : (int)(esf * bpsEnd.getRadiusEnd());
 +            final int ellipseBEH = (int)(esf * bpsAfter.getRadiusEnd());
 +            final int ellipseBEX = ex1 - ellipseBEW;
 +            final int ellipseBEY = clipy + ellipseBEH;
 +
 +            saveGraphicsState();
 +            translateCoordinates(startx, starty + height);
 +            scaleCoordinates(1, -1);
 +            drawBorderSegment( sx2, ex1, ex2, outery, innery,
-             final int sx2 = (slant[BEFORE_END] ?  bw[BEFORE] - clipw[BEFORE] : 0);
++                    clipw[LEFT], clipw[RIGHT],
 +                    ellipseSBX, ellipseSBY, ellipseSBW, ellipseSBH,
 +                    ellipseBEX, ellipseBEY, ellipseBEW, ellipseBEH,
 +                    bpsAfter, bpsStart, bpsEnd
 +            );
 +            restoreGraphicsState();
 +        }
 +
 +        if (bpsEnd != null) {
 +            //Let x increase in the BEFORE-> AFTER direction
-             final int ex2 = (slant[AFTER_END] ? ex1 - bw[AFTER] + clipw[AFTER] : ex1);
-             final int outery = -clipw[END];
-             final int innery = outery + bw[END];
-             final int clipy = outery + clipw[END];
++            final int sx2 = (slant[TOP_RIGHT] ?  bw[TOP] - clipw[TOP] : 0);
 +            final int ex1 = height;
-                     clipw[BEFORE], clipw[AFTER],
++            final int ex2 = (slant[BOTTOM_RIGHT] ? ex1 - bw[BOTTOM] + clipw[BOTTOM] : ex1);
++            final int outery = -clipw[RIGHT];
++            final int innery = outery + bw[RIGHT];
++            final int clipy = outery + clipw[RIGHT];
 +            final int ellipseSBW = bpsBefore == null ? 0 : (int)(esf * bpsBefore.getRadiusEnd());
 +            final int ellipseSBH = (int)(esf * bpsEnd.getRadiusStart());
 +            final int ellipseSBX = ellipseSBW;
 +            final int ellipseSBY = clipy + ellipseSBH;
 +            final int ellipseBEW = bpsAfter == null ? 0 : (int)(esf * bpsAfter.getRadiusEnd());
 +            final int ellipseBEH = (int)(esf * bpsEnd.getRadiusEnd());
 +            final int ellipseBEX = ex1 - ellipseBEW;
 +            final int ellipseBEY = clipy + ellipseBEH;
 +
 +            saveGraphicsState();
 +            translateCoordinates(startx + width, starty);
 +            rotateCoordinates(Math.PI / 2d);
 +            drawBorderSegment( sx2, ex1, ex2, outery, innery,
++                    clipw[TOP], clipw[BOTTOM],
 +                    ellipseSBX, ellipseSBY, ellipseSBW, ellipseSBH,
 +                    ellipseBEX, ellipseBEY, ellipseBEW, ellipseBEH,
 +                    bpsEnd,  bpsBefore, bpsAfter
 +            );
 +            restoreGraphicsState();
 +        }
 +    }
 +
 +    /** TODO collect parameters into useful data structures*/
 +    private void drawBorderSegment(final int sx2, final int ex1, final int ex2,
 +            final int outery, final int innery,
 +            final int clipWidthStart, final int clipWidthEnd,
 +            final int ellipseSBX, final int ellipseSBY,
 +            final int ellipseSBRadiusX, final int ellipseSBRadiusY,
 +            final int ellipseBEX,  final int ellipseBEY,
 +            final int ellipseBERadiusX, final int ellipseBERadiusY,
 +            final BorderProps bpsThis, final BorderProps bpsStart, final BorderProps bpsEnd )
 +    throws IOException {
 +
 +        int sx1a = 0;
 +        int ex1a = ex1;
 +
 +
 +        if (ellipseSBRadiusX != 0 && ellipseSBRadiusY != 0 ) {
 +
 +            final double[] joinMetrics = getCornerBorderJoinMetrics(ellipseSBRadiusX,
 +                    ellipseSBRadiusY, (double)innery / sx2);
 +
 +            final double outerJoinPointX = joinMetrics[0];
 +            final double outerJoinPointY = joinMetrics[1];
 +            final double sbJoinAngle = joinMetrics[2];
 +
 +            moveTo((int)outerJoinPointX, (int)outerJoinPointY);
 +            arcTo(Math.PI + sbJoinAngle, Math.PI * 3 / 2,
 +                    ellipseSBX, ellipseSBY, ellipseSBRadiusX, ellipseSBRadiusY);
 +        }  else {
 +
 +            moveTo(0, 0);
 +
 +            if (bpsThis.mode == BorderProps.COLLAPSE_OUTER) {
 +
 +                if (bpsStart != null && bpsStart.mode == BorderProps.COLLAPSE_OUTER) {
 +                    sx1a -= clipWidthStart;
 +                }
 +                if (bpsEnd != null && bpsEnd.mode == BorderProps.COLLAPSE_OUTER) {
 +                    ex1a += clipWidthEnd;
 +                }
 +
 +                lineTo(sx1a, outery);
 +                lineTo(ex1a, outery);
 +            }
 +        }
 +
 +        if (ellipseBERadiusX != 0 && ellipseBERadiusY != 0) {
 +
 +            final double[] outerJoinMetrics = getCornerBorderJoinMetrics(
 +                    ellipseBERadiusX, ellipseBERadiusY, (double)innery / (ex1 - ex2));
 +            final double beJoinAngle = Math.PI / 2 - outerJoinMetrics[2];
 +
 +            lineTo(ellipseBEX, 0);
 +            arcTo( Math.PI * 3 / 2 , Math.PI * 3 / 2 + beJoinAngle,
 +                    ellipseBEX, ellipseBEY, ellipseBERadiusX, ellipseBERadiusY);
 +
 +            if (ellipseBEX < ex2 && ellipseBEY > innery) {
 +
 +                final double[] innerJoinMetrics = getCornerBorderJoinMetrics(
 +                        (double)ex2 - ellipseBEX, (double)ellipseBEY - innery,
 +                        (double)innery / (ex1 - ex2));
 +                final double innerJoinPointX = innerJoinMetrics[0];
 +                final double innerJoinPointY = innerJoinMetrics[1];
 +                final double beInnerJoinAngle = Math.PI / 2 - innerJoinMetrics[2];
 +
 +                lineTo((int) (ex2 - innerJoinPointX), (int)(innerJoinPointY + innery));
 +                arcTo(beInnerJoinAngle + Math.PI * 3 / 2, Math.PI * 3 / 2,
 +                        ellipseBEX, ellipseBEY, ex2 - ellipseBEX, ellipseBEY - innery);
 +            } else {
 +                lineTo(ex2, innery);
 +            }
 +
 +        } else {
 +            lineTo(ex1, 0);
 +            lineTo(ex2, innery);
 +        }
 +
 +        if (ellipseSBRadiusX == 0) {
 +            lineTo(sx2, innery);
 +        } else {
 +            if (ellipseSBX > sx2 &&  ellipseSBY > innery) {
 +
 +
 +                final double[] innerJoinMetrics = getCornerBorderJoinMetrics(ellipseSBRadiusX - sx2,
 +                        ellipseSBRadiusY - innery, (double)innery / sx2);
 +
 +                final double sbInnerJoinAngle = innerJoinMetrics[2];
 +
 +                lineTo(ellipseSBX, innery);
 +                arcTo(Math.PI * 3 / 2, sbInnerJoinAngle + Math.PI,
 +                        ellipseSBX, ellipseSBY, ellipseSBX - sx2, ellipseSBY - innery);
 +            } else {
 +                lineTo(sx2, innery);
 +            }
 +        }
 +
 +        closePath();
 +        clip();
 +
 +        if (ellipseBERadiusY == 0 && ellipseSBRadiusY == 0) {
 +            drawBorderLine(sx1a, outery, ex1a, innery, true, true,
 +                    bpsThis.style, bpsThis.color);
 +
 +        } else {
 +            int innerFillY = Math.max(Math.max(ellipseBEY, ellipseSBY), innery);
 +            drawBorderLine(sx1a, outery, ex1a, innerFillY, true, true,
 +                    bpsThis.style, bpsThis.color);
 +        }
 +    }
 +
 +    private double[] getCornerBorderJoinMetrics(double ellipseCenterX, double ellipseCenterY,
 +            double borderWidthRatio) {
 +
 +        //TODO decide on implementation
 +        boolean invert = System.getProperty("fop.round-corners.border-invert") != null;
 +        if (invert) {
 +            borderWidthRatio = 1d / borderWidthRatio;
 +        }
 +        String cornerJoinStyle = System.getProperty("fop.round-corners.corner-join-style");
 +        if ("css".equals(cornerJoinStyle)) {
 +            return getCSSCornerBorderJoinMetrics(ellipseCenterX, ellipseCenterY, borderWidthRatio);
 +        } else {
 +            if (invert) { throw new RuntimeException("non css AND bw inverted!"); }
 +            return getDefaultCornerBorderJoinMetrics(
 +                    ellipseCenterX, ellipseCenterY, borderWidthRatio);
 +        }
 +
 +    }
 +
 +    private double[] getCSSCornerBorderJoinMetrics(double ellipseCenterX, double ellipseCenterY,
 +            double borderWidthRatio) {
 +
 +        double angle = Math.atan(borderWidthRatio);
 +        double x = ellipseCenterX * Math.cos(Math.atan(ellipseCenterX
 +                / ellipseCenterY * borderWidthRatio));
 +        double y = ellipseCenterY * Math.sqrt(1d - x * x / ellipseCenterX / ellipseCenterX);
 +
 +        return new double[]{ellipseCenterX - x, ellipseCenterY - y, angle};
 +    }
 +    private double[] getDefaultCornerBorderJoinMetrics(double ellipseCenterX, double ellipseCenterY,
 +            double borderWidthRatio) {
 +
 +        double x = ellipseCenterY * ellipseCenterX * (
 +                ellipseCenterY + ellipseCenterX * borderWidthRatio
 +                - Math.sqrt(2d * ellipseCenterX * ellipseCenterY * borderWidthRatio)
 +        )
 +        / (ellipseCenterY * ellipseCenterY
 +                + ellipseCenterX * ellipseCenterX * borderWidthRatio * borderWidthRatio);
 +        double y = borderWidthRatio * x;
 +
 +        return new double[]{x, y, Math.atan((ellipseCenterY - y) / (ellipseCenterX - x))};
 +    }
 +
 +    /**
 +     * Clip the background to the inner border
 +     * @param rect clipping rectangle
 +     * @param bpsBefore before border
 +     * @param bpsAfter after border
 +     * @param bpsStart start border
 +     * @param bpsEnd end border
 +     * @throws IOException if an I/O error occurs
 +     */
 +    public void clipBackground(Rectangle rect,
 +            BorderProps bpsBefore, BorderProps bpsAfter,
 +            BorderProps bpsStart, BorderProps bpsEnd) throws IOException {
 +        int startx = rect.x;
 +        int starty = rect.y;
 +        int width = rect.width;
 +        int height = rect.height;
 +
 +
 +        int fullWidth = width + ( bpsStart == null ? 0 : bpsStart.width )
 +            + (bpsStart == null ? 0 : bpsStart.width);
 +        int fullHeight = height + ( bpsBefore == null ? 0 : bpsBefore.width )
 +            + (bpsAfter == null ? 0 : bpsAfter.width);
 +
 +        double esf = cornerScaleFactor( fullWidth,  fullHeight,   bpsBefore,  bpsAfter,
 +                bpsStart,  bpsEnd);
 +
 +        int ellipseSS = 0;
 +        int ellipseBS = 0;
 +        int ellipseBE = 0;
 +        int ellipseES = 0;
 +        int ellipseEE = 0;
 +        int ellipseAE = 0;
 +        int ellipseAS = 0;
 +        int ellipseSE = 0;
 +
 +        if (bpsBefore != null && bpsBefore.getRadiusStart() > 0
 +                && bpsStart != null && bpsStart.getRadiusStart() > 0) {
 +            ellipseSS = Math.max((int)(bpsStart.getRadiusStart() * esf) - bpsStart.width, 0);
 +            ellipseBS = Math.max((int)(bpsBefore.getRadiusStart() * esf) - bpsBefore.width, 0);
 +        }
 +
 +        if (bpsBefore != null && bpsBefore.getRadiusEnd() > 0
 +                && bpsEnd != null && bpsEnd.getRadiusStart() > 0) {
 +            ellipseBE = Math.max((int)(bpsBefore.getRadiusEnd() * esf) - bpsBefore.width, 0);
 +            ellipseES = Math.max((int)(bpsEnd.getRadiusStart() * esf) - bpsEnd.width, 0);
 +        }
 +
 +        if (bpsEnd != null && bpsEnd.getRadiusEnd() > 0
 +                && bpsAfter != null && bpsAfter.getRadiusEnd() > 0) {
 +            ellipseEE = Math.max((int)(bpsEnd.getRadiusEnd() * esf) - bpsEnd.width, 0);
 +            ellipseAE = Math.max((int)(bpsAfter.getRadiusEnd() * esf) - bpsAfter.width, 0);
 +        }
 +
 +        if (bpsAfter != null && bpsAfter.getRadiusStart() > 0
 +                && bpsStart != null && bpsStart.getRadiusEnd() > 0) {
 +            ellipseAS = Math.max((int)(bpsAfter.getRadiusStart() * esf) - bpsAfter.width, 0);
 +            ellipseSE = Math.max((int)(bpsStart.getRadiusEnd() * esf) - bpsStart.width, 0);
 +        }
 +
 +        // Draw clipping region in the order: Before->End->After->Start
 +        moveTo(startx + ellipseSS, starty);
 +
 +        lineTo(startx + width - ellipseES, starty);
 +
 +        if (ellipseBE > 0 && ellipseES > 0) {
 +            arcTo(Math.PI * 3 / 2, Math.PI * 2,
 +                    startx + width - ellipseES, starty + ellipseBE, ellipseES, ellipseBE);
 +        }
 +
 +        lineTo(startx + width,  starty + height - ellipseAE);
 +
 +        if (ellipseEE > 0 && ellipseAE > 0) {
 +            arcTo(0, Math.PI / 2, startx + width - ellipseEE,
 +                    starty + height - ellipseAE, ellipseEE, ellipseAE);
 +        }
 +
 +        lineTo(startx + ellipseSE, starty + height);
 +
 +        if (ellipseSE > 0 && ellipseAS > 0) {
 +            arcTo( Math.PI / 2, Math.PI, startx + ellipseSE,
 +                    starty + height - ellipseAS, ellipseSE, ellipseAS);
 +        }
 +
 +        lineTo( startx, starty + ellipseBS);
 +
 +        if (ellipseSS > 0 && ellipseBS > 0) {
 +            arcTo( Math.PI, Math.PI * 3 / 2,
 +                    startx +  ellipseSS, starty + ellipseBS, ellipseSS, ellipseBS);
 +        }
 +
 +        clip();
 +
 +    }
 +
 +    /**
 +     * TODO javadocs
 +     * If an ellipse radii exceed the border edge length then all ellipses must be  rescaled.
 +     */
 +    protected double cornerScaleFactor(int width, int height,
 +            BorderProps bpsBefore, BorderProps bpsAfter,
 +            BorderProps bpsStart, BorderProps bpsEnd) {
 +        // Ellipse scale factor
 +        double esf = 1d;
 +
 +        if (bpsBefore != null) {
 +            double ellipseExtent = (bpsStart == null ? 0 :  bpsStart.getRadiusStart())
 +                    + (bpsEnd == null ? 0 :  bpsEnd.getRadiusStart());
 +
 +            if (ellipseExtent > 0) {
 +                double f = width / ellipseExtent;
 +                if (f < esf) {
 +                    esf = f;
 +                }
 +            }
 +        }
 +
 +        if (bpsStart != null) {
 +            double ellipseExtent = (bpsAfter == null ? 0 :  bpsAfter.getRadiusStart())
 +                    + (bpsBefore == null ? 0 :  bpsBefore.getRadiusStart());
 +
 +            if (ellipseExtent > 0) {
 +                double f = height / ellipseExtent;
 +                if ( f < esf) {
 +                    esf = f;
 +                }
 +            }
 +        }
 +
 +        if (bpsAfter != null) {
 +            double ellipseExtent = (bpsStart == null ? 0 :  bpsStart.getRadiusEnd())
 +                    + (bpsEnd == null ? 0 :  bpsEnd.getRadiusEnd());
 +
 +            if (ellipseExtent > 0) {
 +                double f = width / ellipseExtent;
 +                if (f < esf) {
 +                    esf = f;
 +                }
 +            }
 +        }
 +
 +        if (bpsEnd != null) {
 +            double ellipseExtent = (bpsAfter == null ? 0 :  bpsAfter.getRadiusEnd())
 +                    + (bpsBefore == null ? 0 :  bpsBefore.getRadiusEnd());
 +
 +            if (ellipseExtent > 0) {
 +                double f = height / ellipseExtent;
 +                if (f < esf) {
 +                    esf = f;
 +                }
 +            }
 +        }
 +
 +        return esf;
 +    }
  
      /**
       * Draws a border line.
index 8d92d1ca9c872b99ad8beb103907bb451319cbca,06dfbd18168d1b549c157f0d28babd5d7dd67488..5d2beb65c1c11713c89176b9e44f14542a466b9c
@@@ -206,16 -180,15 +208,16 @@@ public interface IFPainter 
       * Draws a border rectangle. The border segments are specified through {@link BorderProps}
       * instances.
       * @param rect the rectangle's coordinates and extent
-      * @param before the border segment on the before-side (top)
-      * @param after the border segment on the after-side (bottom)
-      * @param start the border segment on the start-side (left)
-      * @param end the border segment on the end-side (right)
+      * @param top the border segment on the top edge
+      * @param bottom the border segment on the bottom edge
+      * @param left the border segment on the left edge
+      * @param right the border segment on the right edge
 +     * @param innerBackgroundColor the color of the inner background
       * @throws IFException if an error occurs while handling this event
       */
      void drawBorderRect(Rectangle rect,
-             BorderProps before, BorderProps after,
-             BorderProps start, BorderProps end, Color innerBackgroundColor) throws IFException;
+             BorderProps top, BorderProps bottom,
 -            BorderProps left, BorderProps right) throws IFException;
++            BorderProps left, BorderProps right, Color innerBackgroundColor) throws IFException;
  
      /**
       * Draws a line. NOTE: Currently, only horizontal lines are implemented!
index 1d20da51979b2d4ffb46550c138e2b043a6c5230,e5c1f98c7028ab2423a15873f6a9bcd8f3b0d2dc..45b0c3a93f67a5d257904b3e59d5c053c9445fe9
@@@ -37,10 -37,8 +37,9 @@@ import java.util.Stack
  import javax.xml.transform.stream.StreamResult;
  
  import org.w3c.dom.Document;
  import org.xml.sax.SAXException;
  
 +import org.apache.batik.parser.AWTTransformProducer;
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  
@@@ -1268,12 -1343,21 +1368,21 @@@ public class IFRenderer extends Abstrac
              float startx, float starty,
              float width, float height,
              BorderProps bpsBefore, BorderProps bpsAfter,
-             BorderProps bpsStart, BorderProps bpsEnd, Color innerBackgroundColor) {
-       //TODO lose scale?
 -            BorderProps bpsStart, BorderProps bpsEnd, int level) {
++            BorderProps bpsStart, BorderProps bpsEnd, int level, Color innerBackgroundColor) {
          Rectangle rect = toMillipointRectangle(startx, starty, width, height);
          try {
-             painter.drawBorderRect(rect, bpsBefore, bpsAfter, bpsStart, bpsEnd,
-                     innerBackgroundColor);
+             BorderProps bpsTop = bpsBefore;
+             BorderProps bpsBottom = bpsAfter;
+             BorderProps bpsLeft;
+             BorderProps bpsRight;
+             if ( ( level == -1 ) || ( ( level & 1 ) == 0 ) ) {
+                 bpsLeft = bpsStart;
+                 bpsRight = bpsEnd;
+             } else {
+                 bpsLeft = bpsEnd;
+                 bpsRight = bpsStart;
+             }
 -            painter.drawBorderRect(rect, bpsTop, bpsBottom, bpsLeft, bpsRight);
++            painter.drawBorderRect(rect, bpsTop, bpsBottom, bpsLeft, bpsRight, innerBackgroundColor);
          } catch (IFException ife) {
              handleIFException(ife);
          }
index 4af90faedd6485bbc148c4a8b92e5e0d79a17dbf,7114f51e36580e12878f6fde14741b9006a8f564..4c678170635df3d11ddbeb59ce7c76b91b8ae9b7
@@@ -520,39 -531,10 +562,39 @@@ public class IFSerializer extends Abstr
          }
      }
  
 +    //TODO create a class representing all borders should exist
 +    //with query methods like this
 +    private boolean hasRoundedCorners(BorderProps bpsBefore, BorderProps bpsAfter,
 +            BorderProps bpsStart, BorderProps bpsEnd) {
 +        boolean rtn = false;
 +
 +        if (bpsBefore != null && bpsBefore.getRadiusStart() > 0
 +                && bpsStart != null && bpsStart.getRadiusStart() > 0) {
 +            rtn = true;
 +        }
 +
 +        if (bpsBefore != null && bpsBefore.getRadiusEnd() > 0
 +                && bpsEnd != null && bpsEnd.getRadiusStart() > 0) {
 +            rtn = true;
 +        }
 +
 +        if (bpsEnd != null && bpsEnd.getRadiusEnd() > 0
 +                && bpsAfter != null && bpsAfter.getRadiusEnd() > 0) {
 +            rtn = true;
 +        }
 +
 +        if (bpsAfter != null && bpsAfter.getRadiusStart() > 0
 +                && bpsStart != null && bpsStart.getRadiusEnd() > 0) {
 +            rtn = true;
 +        }
 +
 +        return rtn;
 +    }
 +
      /** {@inheritDoc} */
-     public void drawBorderRect(Rectangle rect, BorderProps before, BorderProps after,
-             BorderProps start, BorderProps end, Color innerBackgroundColor) throws IFException {
-         if (before == null && after == null && start == null && end == null) {
+     public void drawBorderRect(Rectangle rect, BorderProps top, BorderProps bottom,
 -            BorderProps left, BorderProps right) throws IFException {
++            BorderProps left, BorderProps right, Color innerBackgroundColor) throws IFException {
+         if (top == null && bottom == null && left == null && right == null) {
              return;
          }
          try {
              addAttribute(atts, "y", Integer.toString(rect.y));
              addAttribute(atts, "width", Integer.toString(rect.width));
              addAttribute(atts, "height", Integer.toString(rect.height));
-             if (before != null) {
-                 addAttribute(atts, "before", before.toString());
+             if (top != null) {
+                 addAttribute(atts, "top", top.toString());
              }
-             if (after != null) {
-                 addAttribute(atts, "after", after.toString());
+             if (bottom != null) {
+                 addAttribute(atts, "bottom", bottom.toString());
              }
-             if (start != null) {
-                 addAttribute(atts, "start", start.toString());
+             if (left != null) {
+                 addAttribute(atts, "left", left.toString());
              }
-             if (end != null) {
-                 addAttribute(atts, "end", end.toString());
+             if (right != null) {
+                 addAttribute(atts, "right", right.toString());
              }
 +
 +            if (innerBackgroundColor != null) {
 +                addAttribute(atts, "inner-background-color",
 +                        ColorUtil.colorToString(innerBackgroundColor));
 +            }
 +
              handler.element(EL_BORDER_RECT, atts);
          } catch (SAXException e) {
              throw new IFException("SAX error in drawBorderRect()", e);
              throw new IFException("SAX error serializing object", e);
          }
      }
-     public boolean isBackgroundRequired(BorderProps bpsBefore, BorderProps bpsAfter,
-             BorderProps bpsStart, BorderProps bpsEnd) {
 +
 +    /** {@inheritDoc} */
++    public boolean isBackgroundRequired(BorderProps bpsTop, BorderProps bpsBottom,
++            BorderProps bpsLeft, BorderProps bpsRight) {
 +        return true;
 +    }
  }
index 461b6e5bf380ba3e7ce730a71b3be311d2cd254b,575242d3897aec6a48170607515b2a2d7b5eb8eb..7e4d72c14730bef70332b1a7c20fb17d10fea8a4
@@@ -191,15 -185,15 +192,10 @@@ public class Java2DPainter extends Abst
      }
  
      /** {@inheritDoc} */
-     public void drawBorderRect(Rectangle rect, BorderProps before, BorderProps after,
-             BorderProps start, BorderProps end) throws IFException {
-         if (before != null || after != null || start != null || end != null) {
-             try {
-                 this.borderPainter.drawBorders(rect, before, after, start, end, null);
-             } catch (IFException e) {
-                 //Won't happen with Java2D
-                 throw new IllegalStateException("Unexpected IF error");
-             }
+     public void drawBorderRect(Rectangle rect, BorderProps top, BorderProps bottom,
+             BorderProps left, BorderProps right) throws IFException {
+         if (top != null || bottom != null || left != null || right != null) {
 -            try {
 -                this.borderPainter.drawBorders(rect, top, bottom, left, right);
 -            } catch (IOException e) {
 -                //Won't happen with Java2D
 -                throw new IllegalStateException("Unexpected I/O error");
 -            }
++            this.borderPainter.drawBorders(rect, top, bottom, left, right, null);
          }
      }
  
index 8adb0f12d17946e2f084fef634350665d0be1947,0d630826c38ddc012b8d8540a8ddead0bbddc0ce..a057252d63047ba8665597e204eba3f14871e502
@@@ -214,13 -207,13 +215,13 @@@ public class PCLPainter extends Abstrac
  
      /** {@inheritDoc} */
      public void drawBorderRect(final Rectangle rect,
-             final BorderProps before, final BorderProps after,
-             final BorderProps start, final BorderProps end) throws IFException {
+             final BorderProps top, final BorderProps bottom,
+             final BorderProps left, final BorderProps right) throws IFException {
          if (isSpeedOptimized()) {
-             super.drawBorderRect(rect, before, after, start, end, null);
 -            super.drawBorderRect(rect, top, bottom, left, right);
++            super.drawBorderRect(rect, top, bottom, left, right, null);
              return;
          }
-         if (before != null || after != null || start != null || end != null) {
+         if (top != null || bottom != null || left != null || right != null) {
              final Rectangle boundingBox = rect;
              final Dimension dim = boundingBox.getSize();
  
index 273426c0bf23cd2d7ed1336e4cd5bff0706da7a5,4928e7251b82119fb78422571afe8ef55e2f7335..d7a335dccde0ee05d46f72a220a2472d8623ce7e
@@@ -269,23 -260,21 +274,20 @@@ public class PDFPainter extends Abstrac
      }
  
      /** {@inheritDoc} */
-     public void drawBorderRect(Rectangle rect, BorderProps before, BorderProps after,
-             BorderProps start, BorderProps end, Color innerBackgroundColor) throws IFException {
-         if (before != null || after != null || start != null || end != null) {
+     @Override
+     public void drawBorderRect(Rectangle rect, BorderProps top, BorderProps bottom,
 -            BorderProps left, BorderProps right) throws IFException {
++            BorderProps left, BorderProps right, Color innerBackgroundColor) throws IFException {
+         if (top != null || bottom != null || left != null || right != null) {
              generator.endTextObject();
--            try {
-                 this.borderPainter.drawBorders(rect, before, after, start, end,
-                         innerBackgroundColor);
-             } catch (IFException ioe) {
-                 throw new IFException("IF error while drawing borders", ioe);
 -                this.borderPainter.drawBorders(rect, top, bottom, left, right);
 -            } catch (IOException ioe) {
 -                throw new IFException("I/O error while drawing borders", ioe);
--            }
++            this.borderPainter.drawBorders(rect, top, bottom, left, right, innerBackgroundColor);
          }
      }
  
 +
 +
 +
      /** {@inheritDoc} */
+     @Override
      public void drawLine(Point start, Point end, int width, Color color, RuleStyle style)
          throws IFException {
          generator.endTextObject();
index 72501528e17cf9581d3a669a1b1c84b857a628ce,c2288019ac47db0fb476d5380354f39a9abc1464..9d16cb4285e833d543296d5a4eef9be4aec802df
@@@ -248,13 -241,17 +255,17 @@@ public class PSPainter extends Abstract
      }
  
      /** {@inheritDoc} */
-     public void drawBorderRect(Rectangle rect, BorderProps before, BorderProps after,
-             BorderProps start, BorderProps end, Color innerBackgroundColor) throws IFException {
-         if (before != null || after != null || start != null || end != null) {
+     public void drawBorderRect(Rectangle rect, BorderProps top, BorderProps bottom,
 -            BorderProps left, BorderProps right) throws IFException {
++            BorderProps left, BorderProps right, Color innerBackgroundColor) throws IFException {
+         if (top != null || bottom != null || left != null || right != null) {
              try {
                  endTextObject();
-                 this.borderPainter.drawBorders(rect, before, after, start, end,
-                         innerBackgroundColor);
+                 if (getPSUtil().getRenderingMode() == PSRenderingMode.SIZE
+                     && hasOnlySolidBorders(top, bottom, left, right)) {
 -                    super.drawBorderRect(rect, top, bottom, left, right);
++                    super.drawBorderRect(rect, top, bottom, left, right, innerBackgroundColor);
+                 } else {
 -                    this.borderPainter.drawBorders(rect, top, bottom, left, right);
++                    this.borderPainter.drawBorders(rect, top, bottom, left, right, innerBackgroundColor);
+                 }
              } catch (IOException ioe) {
                  throw new IFException("I/O error in drawBorderRect()", ioe);
              }
index dc60bb0ad189256caa5cbee343b8eec9b410ae1d,ae7a9a434827484f870bca4e0f9c95a677ff93b2..051041c1d01fcdb24be6170e58a36ef78c653dc0
@@@ -147,11 -114,10 +151,12 @@@ public class BorderProps implements Ser
              if (obj instanceof BorderProps) {
                  BorderProps other = (BorderProps)obj;
                  return (style == other.style)
-                         && color.equals(other.color)
+                         && org.apache.xmlgraphics.java2d.color.ColorUtil.isSameColor(
+                                 color, other.color)
                          && width == other.width
 -                        && mode == other.mode;
 +                        && mode == other.mode
 +                        && radiusStart == other.radiusStart
 +                        && radiusEnd == other.radiusEnd;
              }
          }
          return false;