aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/documentation/intermediate-format-ng/fop-intermediate-format-ng-content.xsd13
-rw-r--r--src/java/org/apache/fop/afp/AFPResourceManager.java158
-rw-r--r--src/java/org/apache/fop/area/Trait.java1
-rw-r--r--src/java/org/apache/fop/fo/Constants.java29
-rw-r--r--src/java/org/apache/fop/fo/FOPropertyMapping.java71
-rw-r--r--src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java11
-rw-r--r--src/java/org/apache/fop/fo/properties/BoxCornerPropShorthandParser.java66
-rw-r--r--src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java175
-rw-r--r--src/java/org/apache/fop/layoutmgr/TraitSetter.java55
-rw-r--r--src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java65
-rw-r--r--src/java/org/apache/fop/render/afp/AFPDocumentHandler.java53
-rw-r--r--src/java/org/apache/fop/render/afp/AFPImageHandler.java52
-rw-r--r--src/java/org/apache/fop/render/afp/AFPImageHandlerGraphics2D.java5
-rw-r--r--src/java/org/apache/fop/render/afp/AFPImageHandlerRawJPEG.java4
-rw-r--r--src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java4
-rw-r--r--src/java/org/apache/fop/render/afp/AFPPainter.java875
-rw-r--r--src/java/org/apache/fop/render/afp/AbstractAFPImageHandlerRawStream.java6
-rw-r--r--src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java8
-rw-r--r--src/java/org/apache/fop/render/intermediate/BorderPainter.java701
-rw-r--r--src/java/org/apache/fop/render/intermediate/IFException.java12
-rw-r--r--src/java/org/apache/fop/render/intermediate/IFPainter.java31
-rw-r--r--src/java/org/apache/fop/render/intermediate/IFParser.java43
-rw-r--r--src/java/org/apache/fop/render/intermediate/IFRenderer.java35
-rw-r--r--src/java/org/apache/fop/render/intermediate/IFSerializer.java74
-rw-r--r--src/java/org/apache/fop/render/java2d/Java2DBorderPainter.java39
-rw-r--r--src/java/org/apache/fop/render/java2d/Java2DPainter.java16
-rw-r--r--src/java/org/apache/fop/render/pcl/PCLPainter.java14
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFBorderPainter.java40
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFPainter.java25
-rw-r--r--src/java/org/apache/fop/render/ps/PSBorderPainter.java54
-rw-r--r--src/java/org/apache/fop/render/ps/PSPainter.java20
-rw-r--r--src/java/org/apache/fop/traits/BorderProps.java72
-rw-r--r--src/sandbox/org/apache/fop/render/svg/SVGPainter.java17
33 files changed, 2630 insertions, 214 deletions
diff --git a/src/documentation/intermediate-format-ng/fop-intermediate-format-ng-content.xsd b/src/documentation/intermediate-format-ng/fop-intermediate-format-ng-content.xsd
index eae7a88af..5e58c8208 100644
--- a/src/documentation/intermediate-format-ng/fop-intermediate-format-ng-content.xsd
+++ b/src/documentation/intermediate-format-ng/fop-intermediate-format-ng-content.xsd
@@ -81,6 +81,7 @@
<xs:complexType>
<xs:attributeGroup ref="mf:rectAtts"/>
<xs:attributeGroup ref="mf:fillAtts"/>
+ <xs:attributeGroup ref="mf:borderAtts"/>
</xs:complexType>
</xs:element>
<xs:element name="line">
@@ -97,10 +98,8 @@
<xs:element name="border-rect">
<xs:complexType>
<xs:attributeGroup ref="mf:rectAtts"/>
- <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:attribute name="inner-background-color" type="mf:colorType"/>
+ <xs:attributeGroup ref="mf:borderAtts"/>
</xs:complexType>
</xs:element>
<xs:element name="image">
@@ -128,6 +127,12 @@
<xs:attributeGroup ref="mf:posAtts"/>
<xs:attributeGroup ref="mf:sizeAtts"/>
</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"/>
</xs:attributeGroup>
diff --git a/src/java/org/apache/fop/afp/AFPResourceManager.java b/src/java/org/apache/fop/afp/AFPResourceManager.java
index 89341588c..9544f76c7 100644
--- a/src/java/org/apache/fop/afp/AFPResourceManager.java
+++ b/src/java/org/apache/fop/afp/AFPResourceManager.java
@@ -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, AbstractCachedObject>();
private AFPResourceLevelDefaults resourceLevelDefaults = new AFPResourceLevelDefaults();
@@ -138,21 +134,7 @@ public class AFPResourceManager {
public boolean tryIncludeObject(AFPDataObjectInfo dataObjectInfo) throws IOException {
AFPResourceInfo resourceInfo = dataObjectInfo.getResourceInfo();
updateResourceInfoUri(resourceInfo);
-
- 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;
+ return includeCachedObject(resourceInfo, dataObjectInfo.getObjectAreaInfo());
}
/**
@@ -193,7 +175,7 @@ public class AFPResourceManager {
useInclude &= resourceGroup != null;
if (useInclude) {
- boolean usePageSegment = dataObjectInfo.isCreatePageSegment();
+ final boolean usePageSegment = dataObjectInfo.isCreatePageSegment();
// if it is to reside within a resource group at print-file or external level
if (resourceLevel.isPrintFile() || resourceLevel.isExternal()) {
@@ -211,23 +193,109 @@ public class AFPResourceManager {
// 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);
}
}
+ private abstract class AbstractCachedObject {
+ protected String objectName;
+ protected AFPDataObjectInfo dataObjectInfo;
+
+ public AbstractCachedObject(String objectName, AFPDataObjectInfo dataObjectInfo) {
+ this.objectName = objectName;
+ this.dataObjectInfo = dataObjectInfo;
+
+
+ }
+ protected abstract void includeObject();
+ }
+
+ private class CachedPageSegment extends AbstractCachedObject {
+
+ public CachedPageSegment(String objectName, AFPDataObjectInfo dataObjectInfo) {
+ super(objectName, dataObjectInfo);
+ }
+
+ protected void includeObject() {
+ includePageSegment(dataObjectInfo, objectName);
+ }
+
+ }
+
+ private class CachedObject extends AbstractCachedObject {
+
+ public CachedObject(String objectName, AFPDataObjectInfo dataObjectInfo) {
+ super(objectName, dataObjectInfo);
+ }
+
+ protected void includeObject() {
+ AFPResourceManager.this.includeObject(dataObjectInfo, objectName);
+ }
+
+ }
+
+
+ private void includeObject(AbstractNamedAFPObject namedObj, AFPDataObjectInfo dataObjectInfo) {
+
+ // create the include object
+ AFPResourceInfo resourceInfo = dataObjectInfo.getResourceInfo();
+ String objectName = namedObj.getName();
+
+ AbstractCachedObject cachedObject;
+
+ if (dataObjectInfo.isCreatePageSegment()) {
+ cachedObject = new CachedPageSegment(objectName, dataObjectInfo);
+ } else {
+ cachedObject = new CachedObject(objectName, dataObjectInfo);
+ }
+
+ cachedObject.includeObject();
+
+ includeObjectCache.put(dataObjectInfo.getResourceInfo(), cachedObject);
+
+ //The data field of dataObjectInfo is not further required
+ // therefore we are safe to null the reference, saving memory
+ dataObjectInfo.setData(null);
+
+ }
+
+ /**
+ * TODO
+ * @param resourceInfo
+ * @return
+ */
+ public boolean isObjectCached(AFPResourceInfo resourceInfo) {
+ return includeObjectCache.containsKey(resourceInfo);
+ }
+
+ /**
+ * TODO
+ * @param resourceInfo
+ * @param areaInfo
+ * @return
+ */
+ public boolean includeCachedObject(AFPResourceInfo resourceInfo, AFPObjectAreaInfo areaInfo) {
+
+ String objectName;
+
+ AbstractCachedObject cachedObject = (AbstractCachedObject)includeObjectCache.get(resourceInfo);
+
+ if (cachedObject != null) {
+ if (areaInfo != null) {
+ cachedObject.dataObjectInfo.setObjectAreaInfo(areaInfo);
+ }
+ cachedObject.includeObject();
+
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+
private void updateResourceInfoUri(AFPResourceInfo resourceInfo) {
String uri = resourceInfo.getUri();
if (uri == null) {
@@ -314,8 +382,9 @@ public class AFPResourceManager {
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 (log.isDebugEnabled()) {
log.debug("Adding included resource: " + resourceName);
}
@@ -328,8 +397,12 @@ public class AFPResourceManager {
ResourceGroup resourceGroup = streamer.getResourceGroup(resourceLevel);
resourceGroup.addObject(resourceObject);
+
+ //TODO what is the data object?
+ cachedObject = new CachedObject(resourceName, null);
+
// record mapping of resource info to data object resource name
- includeNameMap.put(resourceInfo, resourceName);
+ includeObjectCache.put(resourceInfo, cachedObject);
} else {
//skip, already created
}
@@ -352,8 +425,10 @@ public class AFPResourceManager {
resourceInfo.setName(resourceName);
resourceInfo.setUri(uri.toASCIIString());
- String resource = includeNameMap.get(resourceInfo);
- if (resource == null) {
+ AbstractCachedObject cachedObject = (AbstractCachedObject)
+ includeObjectCache.get(resourceInfo);
+
+ if (cachedObject == null) {
ResourceGroup resourceGroup = streamer.getResourceGroup(resourceLevel);
@@ -382,9 +457,8 @@ public class AFPResourceManager {
};
resourceGroup.addObject(resourceObject);
-
- includeNameMap.put(resourceInfo, resourceName);
-
+ cachedObject = new CachedObject(resourceName, null);
+ includeObjectCache.put(resourceInfo, cachedObject);
}
}
diff --git a/src/java/org/apache/fop/area/Trait.java b/src/java/org/apache/fop/area/Trait.java
index 65320fd48..cd0d4becf 100644
--- a/src/java/org/apache/fop/area/Trait.java
+++ b/src/java/org/apache/fop/area/Trait.java
@@ -169,6 +169,7 @@ public final class Trait implements Serializable {
/** shift direction trait */
public static final Integer SHIFT_DIRECTION = 42;
+
/** Maximum value used by trait keys */
public static final int MAX_TRAIT_KEY = 42;
diff --git a/src/java/org/apache/fop/fo/Constants.java b/src/java/org/apache/fop/fo/Constants.java
index 2d10dcdd9..324a470f5 100644
--- a/src/java/org/apache/fop/fo/Constants.java
+++ b/src/java/org/apache/fop/fo/Constants.java
@@ -778,15 +778,38 @@ public interface Constants {
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 = 276;
+ int PROPERTY_COUNT = 285;
// compound property constants
diff --git a/src/java/org/apache/fop/fo/FOPropertyMapping.java b/src/java/org/apache/fop/fo/FOPropertyMapping.java
index b29571b09..8934a7594 100644
--- a/src/java/org/apache/fop/fo/FOPropertyMapping.java
+++ b/src/java/org/apache/fop/fo/FOPropertyMapping.java
@@ -29,6 +29,7 @@ import org.apache.fop.fo.flow.table.TableFObj.ColumnNumberPropertyMaker;
import org.apache.fop.fo.properties.BackgroundPositionShorthand;
import org.apache.fop.fo.properties.BorderSpacingShorthandParser;
import org.apache.fop.fo.properties.BorderWidthPropertyMaker;
+import org.apache.fop.fo.properties.BoxCornerPropShorthandParser;
import org.apache.fop.fo.properties.BoxPropShorthandParser;
import org.apache.fop.fo.properties.CharacterProperty;
import org.apache.fop.fo.properties.ColorProperty;
@@ -98,6 +99,7 @@ public final class FOPropertyMapping implements Constants {
private PropertyMaker genericCondBorderWidth = null;
private PropertyMaker genericBorderWidth = null;
private PropertyMaker genericBorderStyle = null;
+ private PropertyMaker genericCondCornerRadius = null;
private PropertyMaker genericBreak = null;
private PropertyMaker genericSpace = null;
@@ -202,6 +204,15 @@ public final class FOPropertyMapping implements Constants {
genericBorderStyle.addEnum("outset", getEnumProperty(EN_OUTSET, "OUTSET"));
genericBorderStyle.setDefault("none");
+ // GenericCondCornerRadius
+ genericCondCornerRadius = new CondLengthProperty.Maker(0);
+ genericCondCornerRadius.useGeneric(genericCondLength);
+ genericCondCornerRadius.setInherited(false);
+ genericCondCornerRadius.getSubpropMaker(CP_LENGTH).setDefault("0pt");
+ genericCondCornerRadius.setPercentBase(LengthBase.CONTAINING_BLOCK_HEIGHT);
+ genericCondCornerRadius.addShorthand(generics[PR_X_BORDER_RADIUS]);
+
+
// GenericBreak
genericBreak = new EnumProperty.Maker(0);
genericBreak.setInherited(false);
@@ -2597,6 +2608,59 @@ public final class FOPropertyMapping implements Constants {
m.setDefault("");
addPropertyMaker("fox:alt-text", m);
+
+ // fox:border-*-radius-*
+
+ // border-before-radius-start
+ m = new CondLengthProperty.Maker(PR_X_BORDER_BEFORE_RADIUS_START);
+ m.useGeneric(genericCondCornerRadius);
+ m.getSubpropMaker(CP_CONDITIONALITY).setDefault("discard");
+
+ addPropertyMaker("fox:border-before-radius-start", m);
+
+ // border-before-radius-end
+ m = new CondLengthProperty.Maker(PR_X_BORDER_BEFORE_RADIUS_END);
+ m.useGeneric(genericCondCornerRadius);
+ m.getSubpropMaker(CP_CONDITIONALITY).setDefault("discard");
+ addPropertyMaker("fox:border-before-radius-end", m);
+
+ // border-after-radius-start
+ m = new CondLengthProperty.Maker(PR_X_BORDER_AFTER_RADIUS_START);
+ m.useGeneric(genericCondCornerRadius);
+ m.getSubpropMaker(CP_CONDITIONALITY).setDefault("discard");
+ addPropertyMaker("fox:border-after-radius-start", m);
+
+ // border-after-radius-end
+ m = new CondLengthProperty.Maker(PR_X_BORDER_AFTER_RADIUS_END);
+ m.useGeneric(genericCondCornerRadius);
+ m.getSubpropMaker(CP_CONDITIONALITY).setDefault("discard");
+ addPropertyMaker("fox:border-after-radius-end", m);
+
+ // border-start-radius-before
+ m = new CondLengthProperty.Maker(PR_X_BORDER_START_RADIUS_START);
+ m.useGeneric(genericCondCornerRadius);
+ m.getSubpropMaker(CP_CONDITIONALITY).setDefault("discard");
+ addPropertyMaker("fox:border-start-radius-before", m);
+
+ // border-start-radius-after
+ m = new CondLengthProperty.Maker(PR_X_BORDER_START_RADIUS_END);
+ m.useGeneric(genericCondCornerRadius);
+ m.getSubpropMaker(CP_CONDITIONALITY).setDefault("discard");
+ addPropertyMaker("fox:border-start-radius-after", m);
+
+ // border-end-radius-before
+ m = new CondLengthProperty.Maker(PR_X_BORDER_END_RADIUS_START);
+ m.useGeneric(genericCondCornerRadius);
+ m.getSubpropMaker(CP_CONDITIONALITY).setDefault("discard");
+ addPropertyMaker("fox:border-end-radius-before", m);
+
+ // border-end-radius-after
+ m = new CondLengthProperty.Maker(PR_X_BORDER_END_RADIUS_END);
+ m.useGeneric(genericCondCornerRadius);
+ m.getSubpropMaker(CP_CONDITIONALITY).setDefault("discard");
+ addPropertyMaker("fox:border-end-radius-after", m);
+
+
// provisional-label-separation
m = new LengthProperty.Maker(PR_PROVISIONAL_LABEL_SEPARATION);
m.setInherited(true);
@@ -2749,6 +2813,13 @@ public final class FOPropertyMapping implements Constants {
m.setDatatypeParser(new BoxPropShorthandParser());
addPropertyMaker("border-width", m);
+ // fox:border-radius
+ m = new ListProperty.Maker(PR_X_BORDER_RADIUS);
+ m.setInherited(false);
+ m.setDatatypeParser(new BoxCornerPropShorthandParser());
+ m.setPercentBase(LengthBase.CONTAINING_BLOCK_WIDTH);
+ addPropertyMaker("fox:border-radius", m);
+
// cue
m = new ToBeImplementedProperty.Maker(PR_CUE);
m.setInherited(false);
diff --git a/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java b/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java
index f0e03399f..1e0755233 100644
--- a/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java
+++ b/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java
@@ -52,6 +52,17 @@ public class ExtensionElementMapping extends ElementMapping {
PROPERTY_ATTRIBUTES.add("disable-column-balancing");
//These are FOP's extension properties for accessibility
PROPERTY_ATTRIBUTES.add("alt-text");
+
+ //fox:border-*-radius-*
+ PROPERTY_ATTRIBUTES.add("border-before-radius-start");
+ PROPERTY_ATTRIBUTES.add("border-before-radius-end");
+ PROPERTY_ATTRIBUTES.add("border-after-radius-start");
+ PROPERTY_ATTRIBUTES.add("border-after-radius-end");
+ PROPERTY_ATTRIBUTES.add("border-start-radius-before");
+ PROPERTY_ATTRIBUTES.add("border-start-radius-after");
+ PROPERTY_ATTRIBUTES.add("border-end-radius-before");
+ PROPERTY_ATTRIBUTES.add("border-end-radius-after");
+ PROPERTY_ATTRIBUTES.add("border-radius");
}
/**
diff --git a/src/java/org/apache/fop/fo/properties/BoxCornerPropShorthandParser.java b/src/java/org/apache/fop/fo/properties/BoxCornerPropShorthandParser.java
new file mode 100644
index 000000000..d3e37a7c9
--- /dev/null
+++ b/src/java/org/apache/fop/fo/properties/BoxCornerPropShorthandParser.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fo.properties;
+
+import org.apache.fop.fo.FOPropertyMapping;
+import org.apache.fop.fo.PropertyList;
+import org.apache.fop.fo.expr.PropertyException;
+
+/**
+ * Shorthand property parser for Box rounded corner properties
+ */
+public class BoxCornerPropShorthandParser extends GenericShorthandParser {
+
+ /**
+ * Default constructor.
+ */
+ public BoxCornerPropShorthandParser() {
+ }
+
+ /**
+ * Stores 1 or 2 values of same type representing rounded corner radii.
+ * If 2 value are present the first is the corner radius in the IP direction,
+ * the second in the BP direction.
+ * {@inheritDoc}
+ * int, Property, PropertyMaker, PropertyList)
+ */
+ protected Property convertValueForProperty(int propId,
+ Property property,
+ PropertyMaker maker,
+ PropertyList propertyList)
+ throws PropertyException {
+ String name = FOPropertyMapping.getPropertyName(propId);
+ Property p = null;
+ int count = property.getList().size();
+
+ if (name.indexOf("border-start") > -1 || name.indexOf("border-end") > -1) {
+ p = getElement(property, 0);
+ } else if (name.indexOf("border-before") > -1 || name.indexOf("border-after") > -1) {
+ p = getElement(property, count > 1 ? 1 : 0);
+ }
+
+ // if p not null, try to convert it to a value of the correct type
+ if (p != null) {
+ return maker.convertShorthandProperty(propertyList, p, null);
+ }
+ return p;
+ }
+
+}
diff --git a/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java b/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java
index 0e7f3d978..050da71bb 100644
--- a/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java
+++ b/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java
@@ -98,6 +98,8 @@ public class CommonBorderPaddingBackground {
/** the "end" edge */
public static final int END = 3;
+
+
/**
* Utility class to express border info.
*/
@@ -110,32 +112,40 @@ public class CommonBorderPaddingBackground {
private int mStyle; // Enum for border style
private Color mColor; // Border color
private CondLengthProperty mWidth;
+ private CondLengthProperty radiusStart;
+ private CondLengthProperty radiusEnd;
private int hash = -1;
/**
* Hidden constructor
*/
- private BorderInfo(int style, CondLengthProperty width, Color color) {
+ private BorderInfo(int style, CondLengthProperty width, Color color,
+ CondLengthProperty radiusStart, CondLengthProperty radiusEnd) {
mStyle = style;
mWidth = width;
mColor = color;
+ this.radiusStart = radiusStart;
+ this.radiusEnd = radiusEnd;
}
/**
- * Returns a BorderInfo instance corresponding to the given values
+ * Returns a BorderInfo instance corresponding to the given values.
*
* @param style the border-style
* @param width the border-width
* @param color the border-color
+ * @param radiusStart the start radius for rounded borders
+ * @param radiusEnd the end radius for rounded borders
* @return a cached BorderInfo instance
*/
- public static BorderInfo getInstance(int style, CondLengthProperty width, Color color) {
- return CACHE.fetch(new BorderInfo(style, width, color));
+ public static BorderInfo getInstance(int style, CondLengthProperty width, Color color,
+ CondLengthProperty radiusStart, CondLengthProperty radiusEnd) {
+ return CACHE.fetch(new BorderInfo(style, width, color, radiusStart, radiusEnd));
}
/**
- * @return the border-style
+ * @return the border-style
*/
public int getStyle() {
return this.mStyle;
@@ -170,6 +180,20 @@ public class CommonBorderPaddingBackground {
}
}
+ /**
+ * @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");
@@ -179,6 +203,10 @@ public class CommonBorderPaddingBackground {
sb.append(mColor);
sb.append(", ");
sb.append(mWidth);
+ sb.append(", ");
+ sb.append(radiusStart);
+ sb.append(", ");
+ sb.append(radiusEnd);
sb.append("}");
return sb.toString();
}
@@ -188,8 +216,13 @@ public class CommonBorderPaddingBackground {
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);
}
BorderInfo other = (BorderInfo) obj;
return CompareUtil.equal(mColor, other.mColor)
@@ -204,18 +237,27 @@ public class CommonBorderPaddingBackground {
hash = 37 * hash + (mColor == null ? 0 : mColor.hashCode());
hash = 37 * hash + mStyle;
hash = 37 * hash + (mWidth == null ? 0 : mWidth.hashCode());
+ hash = 37 * hash + (radiusStart == null ? 0 : radiusStart.hashCode());
+ hash = 37 * hash + (radiusEnd == null ? 0 : radiusEnd.hashCode());
this.hash = hash;
}
return this.hash;
}
}
+
+
+
/**
* A border info with style "none". Used as a singleton, in the collapsing-border model,
* for elements which don't specify any border on some of their sides.
*/
private static final BorderInfo DEFAULT_BORDER_INFO
- = BorderInfo.getInstance(Constants.EN_NONE, new ConditionalNullLength(), null);
+ = BorderInfo.getInstance(Constants.EN_NONE, new ConditionalNullLength(), null,
+ new ConditionalNullLength(), new ConditionalNullLength());
+
+
+
/**
* A conditional length of value 0. Returned by the
@@ -292,8 +334,11 @@ public class CommonBorderPaddingBackground {
backgroundAttachment = pList.get(Constants.PR_BACKGROUND_ATTACHMENT).getEnum();
+
+
+
Color bc = pList.get(Constants.PR_BACKGROUND_COLOR).getColor(
- pList.getFObj().getUserAgent());
+ pList.getFObj().getUserAgent());
if (bc.getAlpha() == 0) {
backgroundColor = null;
} else {
@@ -319,22 +364,30 @@ public class CommonBorderPaddingBackground {
Constants.PR_BORDER_BEFORE_COLOR,
Constants.PR_BORDER_BEFORE_STYLE,
Constants.PR_BORDER_BEFORE_WIDTH,
- Constants.PR_PADDING_BEFORE);
+ Constants.PR_PADDING_BEFORE,
+ Constants.PR_X_BORDER_BEFORE_RADIUS_START,
+ Constants.PR_X_BORDER_BEFORE_RADIUS_END);
initBorderInfo(pList, AFTER,
Constants.PR_BORDER_AFTER_COLOR,
Constants.PR_BORDER_AFTER_STYLE,
Constants.PR_BORDER_AFTER_WIDTH,
- Constants.PR_PADDING_AFTER);
+ Constants.PR_PADDING_AFTER,
+ Constants.PR_X_BORDER_AFTER_RADIUS_START,
+ Constants.PR_X_BORDER_AFTER_RADIUS_END);
initBorderInfo(pList, START,
Constants.PR_BORDER_START_COLOR,
Constants.PR_BORDER_START_STYLE,
Constants.PR_BORDER_START_WIDTH,
- Constants.PR_PADDING_START);
+ Constants.PR_PADDING_START,
+ Constants.PR_X_BORDER_START_RADIUS_START,
+ Constants.PR_X_BORDER_START_RADIUS_END);
initBorderInfo(pList, END,
Constants.PR_BORDER_END_COLOR,
Constants.PR_BORDER_END_STYLE,
Constants.PR_BORDER_END_WIDTH,
- Constants.PR_PADDING_END);
+ Constants.PR_PADDING_END,
+ Constants.PR_X_BORDER_END_RADIUS_START,
+ Constants.PR_X_BORDER_END_RADIUS_END);
}
@@ -346,8 +399,7 @@ public class CommonBorderPaddingBackground {
* @return a CommonBorderPaddingBackground instance (cached if possible)
* @throws PropertyException in case of an error
*/
- public static CommonBorderPaddingBackground getInstance(PropertyList 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
@@ -400,21 +452,26 @@ public class CommonBorderPaddingBackground {
}
private void initBorderInfo(PropertyList pList, int side,
- int colorProp, int styleProp, int widthProp, int paddingProp)
- throws PropertyException {
+ int colorProp, int styleProp, int widthProp, int paddingProp,
+ int radiusStartProp, int radiusEndProp)
+ throws PropertyException {
padding[side] = pList.get(paddingProp).getCondLength();
// If style = none, force width to 0, don't get Color (spec 7.7.20)
int style = pList.get(styleProp).getEnum();
- if (style != Constants.EN_NONE) {
+ // if (style != Constants.EN_NONE) {
FOUserAgent ua = pList.getFObj().getUserAgent();
setBorderInfo(BorderInfo.getInstance(style,
- pList.get(widthProp).getCondLength(),
- pList.get(colorProp).getColor(ua)), side);
- }
+ pList.get(widthProp).getCondLength(),
+ pList.get(colorProp).getColor(ua),
+ pList.get(radiusStartProp).getCondLength(),
+ pList.get(radiusEndProp).getCondLength()), side);
+ // }
}
+
+
/**
* Sets a border.
* @param info the border information
@@ -538,6 +595,40 @@ public class CommonBorderPaddingBackground {
}
/**
+ * Returns the border corner radius of the starting edge
+ * i.e. the edge either adjacent to the before or start border.
+ * @param side the border side
+ * @param discard indicates whether the .conditionality component should be
+ * considered (end of a reference-area)
+ * @param context the context for percentage calculations
+ * @return the border radius of the of the starting corner
+ */
+ public int getBorderRadiusStart(int side, boolean discard, PercentBaseContext context) {
+ if (borderInfo[side] == null) {
+ return 0;
+ } else {
+ return borderInfo[side].radiusStart.getLengthValue(context);
+ }
+ }
+
+ /**
+ * Returns the border corner radius of the ending edge
+ * i.e. the edge either adjacent to the after or end border
+ * @param side the border side
+ * @param discard indicates whether the .conditionality component should be
+ * considered (end of a reference-area)
+ * @param context the context for percentage calculations
+ * @return the border radius of the of the ending corner
+ */
+ public int getBorderRadiusEnd(int side, boolean discard, PercentBaseContext context) {
+ if (borderInfo[side] == null) {
+ return 0;
+ } else {
+ return borderInfo[side].radiusEnd.getLengthValue(context);
+ }
+ }
+
+ /**
* The border-color for the given side
*
* @param side one of {@link #BEFORE}, {@link #AFTER}, {@link #START}, {@link #END}
@@ -601,9 +692,9 @@ public class CommonBorderPaddingBackground {
*/
public int getIPPaddingAndBorder(boolean discard, PercentBaseContext context) {
return getPaddingStart(discard, context)
- + getPaddingEnd(discard, context)
- + getBorderStartWidth(discard)
- + getBorderEndWidth(discard);
+ + getPaddingEnd(discard, context)
+ + getBorderStartWidth(discard)
+ + getBorderEndWidth(discard);
}
/**
@@ -615,18 +706,18 @@ public class CommonBorderPaddingBackground {
*/
public int getBPPaddingAndBorder(boolean discard, PercentBaseContext context) {
return getPaddingBefore(discard, context) + getPaddingAfter(discard, context)
- + getBorderBeforeWidth(discard) + getBorderAfterWidth(discard);
+ + getBorderBeforeWidth(discard) + getBorderAfterWidth(discard);
}
@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";
}
/**
@@ -734,19 +825,19 @@ public class CommonBorderPaddingBackground {
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
+ && Arrays.equals(borderInfo, cbpb.borderInfo)
+ && Arrays.equals(padding, cbpb.padding));
+ } else {
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);
}
@Override
diff --git a/src/java/org/apache/fop/layoutmgr/TraitSetter.java b/src/java/org/apache/fop/layoutmgr/TraitSetter.java
index 0ae499478..3648f7091 100644
--- a/src/java/org/apache/fop/layoutmgr/TraitSetter.java
+++ b/src/java/org/apache/fop/layoutmgr/TraitSetter.java
@@ -80,19 +80,19 @@ public final class TraitSetter {
addBorderTrait(area, bpProps, isNotFirst,
CommonBorderPaddingBackground.START,
- BorderProps.SEPARATE, Trait.BORDER_START);
+ BorderProps.SEPARATE, Trait.BORDER_START, context);
addBorderTrait(area, bpProps, isNotLast,
CommonBorderPaddingBackground.END,
- BorderProps.SEPARATE, Trait.BORDER_END);
+ BorderProps.SEPARATE, Trait.BORDER_END, context);
addBorderTrait(area, bpProps, false,
CommonBorderPaddingBackground.BEFORE,
- BorderProps.SEPARATE, Trait.BORDER_BEFORE);
+ BorderProps.SEPARATE, Trait.BORDER_BEFORE, context);
addBorderTrait(area, bpProps, false,
CommonBorderPaddingBackground.AFTER,
- BorderProps.SEPARATE, Trait.BORDER_AFTER);
+ BorderProps.SEPARATE, Trait.BORDER_AFTER, context);
}
/*
@@ -104,14 +104,18 @@ public final class TraitSetter {
*/
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,
+ 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);
}
}
@@ -126,19 +130,19 @@ public final class TraitSetter {
*/
public static void addBorders(Area area, CommonBorderPaddingBackground borderProps,
PercentBaseContext 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(borderProps, CommonBorderPaddingBackground.AFTER);
+ bps = getBorderProps(borderProps, CommonBorderPaddingBackground.AFTER, context);
if (bps != null) {
area.addTrait(Trait.BORDER_AFTER, bps);
}
- bps = getBorderProps(borderProps, CommonBorderPaddingBackground.START);
+ bps = getBorderProps(borderProps, CommonBorderPaddingBackground.START, context);
if (bps != null) {
area.addTrait(Trait.BORDER_START, bps);
}
- bps = getBorderProps(borderProps, CommonBorderPaddingBackground.END);
+ bps = getBorderProps(borderProps, CommonBorderPaddingBackground.END, context);
if (bps != null) {
area.addTrait(Trait.BORDER_END, bps);
}
@@ -163,22 +167,23 @@ public final class TraitSetter {
boolean discardBefore, boolean discardAfter,
boolean discardStart, boolean discardEnd,
PercentBaseContext 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(borderProps, CommonBorderPaddingBackground.AFTER);
+ bps = getBorderProps(borderProps, CommonBorderPaddingBackground.AFTER, context);
if (bps != null && !discardAfter) {
area.addTrait(Trait.BORDER_AFTER, bps);
}
- bps = getBorderProps(borderProps, CommonBorderPaddingBackground.START);
+ bps = getBorderProps(borderProps, CommonBorderPaddingBackground.START, context);
if (bps != null && !discardStart) {
area.addTrait(Trait.BORDER_START, bps);
}
- bps = getBorderProps(borderProps, CommonBorderPaddingBackground.END);
+ bps = getBorderProps(borderProps, CommonBorderPaddingBackground.END, context);
if (bps != null && !discardEnd) {
area.addTrait(Trait.BORDER_END, bps);
}
+
}
/**
@@ -262,14 +267,19 @@ public final class TraitSetter {
}
- private static BorderProps getBorderProps(CommonBorderPaddingBackground bordProps, int side) {
+ private static BorderProps getBorderProps(CommonBorderPaddingBackground bordProps,
+ int side, PercentBaseContext context) {
int width = bordProps.getBorderWidth(side, false);
- if (width != 0) {
+ int radiusStart = bordProps.getBorderRadiusStart(side, false, context);
+ int radiusEnd = bordProps.getBorderRadiusEnd(side, false, context);
+ if (width != 0 || radiusStart != 0 || radiusEnd != 0) {
BorderProps bps;
bps = new BorderProps(bordProps.getBorderStyle(side),
width,
bordProps.getBorderColor(side),
BorderProps.SEPARATE);
+ bps.setRadiusStart(radiusStart);
+ bps.setRadiusEnd(radiusEnd);
return bps;
} else {
return null;
@@ -287,6 +297,7 @@ public final class TraitSetter {
}
}
+
/**
* Add background to an area. This method is mainly used by table-related layout
* managers to add background for column, body or row. Since the area corresponding to
diff --git a/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java b/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java
index cb66f2abb..042efccc5 100644
--- a/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java
+++ b/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java
@@ -32,7 +32,6 @@ import org.apache.batik.parser.AWTTransformProducer;
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;
@@ -49,7 +48,9 @@ import org.apache.fop.area.inline.InlineViewport;
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
@@ -166,11 +167,21 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer {
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, 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, borderArea.getBidiLevel());
+ bpsBefore, bpsAfter, bpsStart, bpsEnd, backgroundArea.getBidiLevel(), bg);
}
/**
@@ -247,14 +258,23 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer {
paddRectHeight -= bpsBottom.width / 1000f;
}
+ 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);
}
+
if (back.getImageInfo() != null) {
ImageSize imageSize = back.getImageInfo().getSize();
- saveGraphicsState();
- clipRect(sx, sy, paddRectWidth, paddRectHeight);
int horzCount = (int)((paddRectWidth
* 1000 / imageSize.getWidthMpt()) + 1.0f);
int vertCount = (int)((paddRectHeight
@@ -290,13 +310,35 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer {
drawImage(back.getURL(), pos);
}
}
-
- restoreGraphicsState();
}
+ restoreGraphicsState();
}
}
/**
+ * TODO represent border related parameters in a class
+ * Clip the background to the inner border.
+ * This draws the border traits given the position and the traits.
+ *
+ * @param startx the start x position
+ * @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
+ */
+ protected void clipBackground (float startx, float starty,
+ float width, float height,
+ BorderProps bpsBefore, BorderProps bpsAfter,
+ BorderProps bpsStart, BorderProps bpsEnd) {
+
+ clipRect(startx, starty, width, height);
+
+ }
+
+ /**
* Draw the borders.
* This draws the border traits given the position and the traits.
*
@@ -309,11 +351,12 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer {
* @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, int level) {
+ BorderProps bpsStart, BorderProps bpsEnd, int level, Color innerBackgroundColor) {
Rectangle2D.Float borderRect = new Rectangle2D.Float(startx, starty, width, height);
BorderProps bpsTop = bpsBefore;
BorderProps bpsBottom = bpsAfter;
@@ -326,7 +369,7 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer {
bpsLeft = bpsEnd;
bpsRight = bpsStart;
}
- drawBorders(borderRect, bpsTop, bpsBottom, bpsLeft, bpsRight);
+ drawBorders(borderRect, bpsTop, bpsBottom, bpsLeft, bpsRight, innerBackgroundColor);
}
private static final int TOP = 0;
@@ -341,10 +384,12 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer {
* @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 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[] {
(bpsTop != null), (bpsRight != null),
diff --git a/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java b/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java
index 2ae95dd4c..d427f9d7f 100644
--- a/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java
+++ b/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java
@@ -23,6 +23,7 @@ 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;
@@ -83,6 +84,15 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler
private Map<String, PageSegmentDescriptor> pageSegmentMap
= new java.util.HashMap<String, PageSegmentDescriptor>();
+
+ // 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
}
@@ -394,6 +404,49 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler
}
}
+ /**
+ * 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) {
diff --git a/src/java/org/apache/fop/render/afp/AFPImageHandler.java b/src/java/org/apache/fop/render/afp/AFPImageHandler.java
index 118207d38..6404924a1 100644
--- a/src/java/org/apache/fop/render/afp/AFPImageHandler.java
+++ b/src/java/org/apache/fop/render/afp/AFPImageHandler.java
@@ -19,7 +19,10 @@
package org.apache.fop.render.afp;
+import java.awt.Point;
import java.awt.Rectangle;
+import java.awt.geom.Rectangle2D;
+import java.io.IOException;
import java.util.Map;
import org.apache.fop.afp.AFPDataObjectInfo;
@@ -37,21 +40,60 @@ public abstract class AFPImageHandler implements ImageHandlerBase {
private static final int Y = 1;
/** foreign attribute reader */
- private final AFPForeignAttributeReader foreignAttributeReader
+ private static final AFPForeignAttributeReader FOREIGN_ATTRIBUTE_READER
= new AFPForeignAttributeReader();
/**
+ * Generates an intermediate AFPDataObjectInfo that is later used to construct
+ * the appropriate data object in the AFP DataStream.
+ *
+ * @param rendererImageInfo the renderer image info
+ * @return a data object info object
+ * @throws IOException thrown if an I/O exception of some sort has occurred.
+ */
+ public AFPDataObjectInfo generateDataObjectInfo(
+ AFPRendererImageInfo rendererImageInfo) throws IOException {
+ AFPDataObjectInfo dataObjectInfo = createDataObjectInfo();
+
+ // set resource information
+ dataObjectInfo.setResourceInfo(createResourceInformation(
+ rendererImageInfo.getURI(),
+ rendererImageInfo.getForeignAttributes()));
+
+
+ Point origin = rendererImageInfo.getOrigin();
+ Rectangle2D position = rendererImageInfo.getPosition();
+ int srcX = Math.round(origin.x + (float)position.getX());
+ int srcY = Math.round(origin.y + (float)position.getY());
+ Rectangle targetRect = new Rectangle(
+ srcX,
+ srcY,
+ (int)Math.round(position.getWidth()),
+ (int)Math.round(position.getHeight()));
+
+ AFPRendererContext rendererContext
+ = (AFPRendererContext)rendererImageInfo.getRendererContext();
+ AFPInfo afpInfo = rendererContext.getInfo();
+ AFPPaintingState paintingState = afpInfo.getPaintingState();
+
+ dataObjectInfo.setObjectAreaInfo(createObjectAreaInfo(paintingState, targetRect));
+
+ return dataObjectInfo;
+ }
+
+ /**
* Sets resource information on the data object info.
- * @param dataObjectInfo the data object info instance
* @param uri the image's URI (or null if no URI is available)
* @param foreignAttributes a Map of foreign attributes (or null)
+ * @return the resource information object
*/
- protected void setResourceInformation(AFPDataObjectInfo dataObjectInfo,
+ public static AFPResourceInfo createResourceInformation(
String uri, Map foreignAttributes) {
AFPResourceInfo resourceInfo
- = foreignAttributeReader.getResourceInfo(foreignAttributes);
+ = FOREIGN_ATTRIBUTE_READER.getResourceInfo(foreignAttributes);
resourceInfo.setUri(uri);
- dataObjectInfo.setResourceInfo(resourceInfo);
+
+ return resourceInfo;
}
/**
diff --git a/src/java/org/apache/fop/render/afp/AFPImageHandlerGraphics2D.java b/src/java/org/apache/fop/render/afp/AFPImageHandlerGraphics2D.java
index f60e271cb..2a0db08bb 100644
--- a/src/java/org/apache/fop/render/afp/AFPImageHandlerGraphics2D.java
+++ b/src/java/org/apache/fop/render/afp/AFPImageHandlerGraphics2D.java
@@ -85,9 +85,10 @@ public class AFPImageHandlerGraphics2D extends AFPImageHandler implements ImageH
AFPGraphicsObjectInfo graphicsObjectInfo = (AFPGraphicsObjectInfo)createDataObjectInfo();
// set resource information
- setResourceInformation(graphicsObjectInfo,
+
+ graphicsObjectInfo.setResourceInfo(createResourceInformation(
image.getInfo().getOriginalURI(),
- afpContext.getForeignAttributes());
+ afpContext.getForeignAttributes()));
// Positioning
graphicsObjectInfo.setObjectAreaInfo(
diff --git a/src/java/org/apache/fop/render/afp/AFPImageHandlerRawJPEG.java b/src/java/org/apache/fop/render/afp/AFPImageHandlerRawJPEG.java
index e318c49fb..7508c8ca0 100644
--- a/src/java/org/apache/fop/render/afp/AFPImageHandlerRawJPEG.java
+++ b/src/java/org/apache/fop/render/afp/AFPImageHandlerRawJPEG.java
@@ -94,9 +94,9 @@ public class AFPImageHandlerRawJPEG extends AFPImageHandler implements ImageHand
AFPPaintingState paintingState = afpContext.getPaintingState();
// set resource information
- setResourceInformation(imageObjectInfo,
+ imageObjectInfo.setResourceInfo(createResourceInformation(
image.getInfo().getOriginalURI(),
- afpContext.getForeignAttributes());
+ afpContext.getForeignAttributes()));
setDefaultResourceLevel(imageObjectInfo, afpContext.getResourceManager());
// Positioning
diff --git a/src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java b/src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java
index e5f41d232..3e0780cbf 100644
--- a/src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java
+++ b/src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java
@@ -111,9 +111,9 @@ public class AFPImageHandlerRenderedImage extends AFPImageHandler implements Ima
AFPPaintingState paintingState = afpContext.getPaintingState();
// set resource information
- setResourceInformation(imageObjectInfo,
+ imageObjectInfo.setResourceInfo(createResourceInformation(
image.getInfo().getOriginalURI(),
- afpContext.getForeignAttributes());
+ afpContext.getForeignAttributes()));
setDefaultResourceLevel(imageObjectInfo, afpContext.getResourceManager());
// Positioning
diff --git a/src/java/org/apache/fop/render/afp/AFPPainter.java b/src/java/org/apache/fop/render/afp/AFPPainter.java
index 8b2f31555..5d8c1a93f 100644
--- a/src/java/org/apache/fop/render/afp/AFPPainter.java
+++ b/src/java/org/apache/fop/render/afp/AFPPainter.java
@@ -21,22 +21,39 @@ package org.apache.fop.render.afp;
import java.awt.Color;
import java.awt.Dimension;
+import java.awt.Graphics2D;
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;
+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.ImageException;
+import org.apache.xmlgraphics.image.loader.ImageInfo;
import org.apache.xmlgraphics.image.loader.ImageProcessingHints;
import org.apache.xmlgraphics.image.loader.ImageSessionContext;
+import org.apache.xmlgraphics.image.loader.ImageSize;
+import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D;
+import org.apache.xmlgraphics.java2d.Graphics2DImagePainter;
import org.apache.fop.afp.AFPBorderPainter;
+import org.apache.fop.afp.AFPObjectAreaInfo;
import org.apache.fop.afp.AFPPaintingState;
+import org.apache.fop.afp.AFPResourceInfo;
import org.apache.fop.afp.AFPUnitConverter;
import org.apache.fop.afp.AbstractAFPPainter;
import org.apache.fop.afp.BorderPaintingInfo;
@@ -56,6 +73,7 @@ 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;
@@ -72,8 +90,11 @@ import org.apache.fop.util.CharUtilities;
*/
public class AFPPainter extends AbstractIFPainter {
+
+
+
//** logging instance */
- //private static Log log = LogFactory.getLog(AFPPainter.class);
+ private static Log log = LogFactory.getLog(AFPPainter.class);
private static final int X = 0;
private static final int Y = 1;
@@ -96,8 +117,9 @@ public class AFPPainter extends AbstractIFPainter {
super();
this.documentHandler = documentHandler;
this.state = IFState.create();
+
this.borderPainter = new AFPBorderPainterAdapter(
- new AFPBorderPainter(getPaintingState(), getDataStream()));
+ new AFPBorderPainter(getPaintingState(), getDataStream()), this, documentHandler);
this.rectanglePainter = documentHandler.createRectanglePainter();
this.unitConv = getPaintingState().getUnitConverter();
}
@@ -122,7 +144,7 @@ public class AFPPainter extends AbstractIFPainter {
/** {@inheritDoc} */
public void startViewport(AffineTransform transform, Dimension size, Rectangle clipRect)
- throws IFException {
+ throws IFException {
//AFP doesn't support clipping, so we treat viewport like a group
//this is the same code as for startGroup()
try {
@@ -181,13 +203,13 @@ public class AFPPainter extends AbstractIFPainter {
/** {@inheritDoc} */
@Override
protected RenderingContext createRenderingContext() {
- AFPRenderingContext psContext = new AFPRenderingContext(
+ AFPRenderingContext renderingContext = new AFPRenderingContext(
getUserAgent(),
documentHandler.getResourceManager(),
getPaintingState(),
getFontInfo(),
getContext().getForeignAttributes());
- return psContext;
+ return renderingContext;
}
/** {@inheritDoc} */
@@ -226,6 +248,32 @@ public class AFPPainter extends AbstractIFPainter {
}
/** {@inheritDoc} */
+ protected void drawImage(Image image, Rectangle rect,
+ RenderingContext context, boolean convert, Map additionalHints)
+ throws IOException, ImageException {
+
+
+ AFPRenderingContext afpContext = (AFPRenderingContext)context;
+
+ AFPResourceInfo resourceInfo = AFPImageHandler.createResourceInformation(
+ image.getInfo().getOriginalURI(),
+ afpContext.getForeignAttributes());
+
+ //Check if the image is cached before processing it again
+ if (afpContext.getResourceManager().isObjectCached(resourceInfo)) {
+
+ AFPObjectAreaInfo areaInfo = AFPImageHandler.createObjectAreaInfo(
+ afpContext.getPaintingState(), rect);
+
+ afpContext.getResourceManager().includeCachedObject(resourceInfo, areaInfo);
+
+ } else {
+ super.drawImage(image, rect, context, convert, additionalHints);
+ }
+
+ }
+
+ /** {@inheritDoc} */
public void drawImage(Document doc, Rectangle rect) throws IFException {
drawImageUsingDocument(doc, rect);
}
@@ -260,27 +308,766 @@ public class AFPPainter extends AbstractIFPainter {
}
}
- /** {@inheritDoc} */
@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[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 = 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[TOP].add(makeCornerBorderBPD(beforeRadius,
+ startRadius, beforeWidth, startWidth, transform));
+
+ cornerBorder[LEFT].add(makeCornerBorderIPD(beforeRadius,
+ startRadius, beforeWidth, startWidth, transform));
+ }
+
+ 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 = 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[TOP].add(makeCornerBorderBPD(beforeRadius,
+ startRadius, beforeWidth, startWidth, transform));
+
+ cornerBorder[RIGHT].add(makeCornerBorderIPD(beforeRadius,
+ startRadius, beforeWidth, startWidth, transform));
+ }
+
+ 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 = 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[BOTTOM].add(makeCornerBorderBPD(beforeRadius,
+ startRadius, beforeWidth, startWidth, transform));
+ cornerBorder[RIGHT].add(makeCornerBorderIPD(beforeRadius,
+ startRadius, beforeWidth, startWidth, transform));
+ }
+
+ 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 = 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[BOTTOM].add(makeCornerBorderBPD(beforeRadius,
+ startRadius, beforeWidth, startWidth, transform));
+ 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[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[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[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[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;
+ 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(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(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(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);
+
+ 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
+ };
+
+
+ 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 TOP_LEFT:
+ //No transform required
+ break;
+ case TOP_RIGHT:
+ t = new AffineTransform(-1, 0, 0, 1, startRadius, 0);
+ g2d.transform(t);
+ break;
+ 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
@@ -329,11 +1116,11 @@ public class AFPPainter extends AbstractIFPainter {
@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(
- "Can only deal with horizontal lines right now");
+ "Can only deal with horizontal lines right now");
}
//Simply delegates to drawBorderLine() as AFP line painting is not very sophisticated.
@@ -342,12 +1129,46 @@ public class AFPPainter extends AbstractIFPainter {
true, true, style.getEnumValue(), color);
}
+
+ protected void arcTo(double startAngle, double endAngle, int cx, int cy, int width,
+ int height) throws IOException {
+ throw new UnsupportedOperationException(
+ "Can only deal with horizontal lines right now");
+
+ }
+
+
+ protected void changeCoords(double a, double b, double c, double d, double e, double f) {
+ throw new UnsupportedOperationException(
+ "Can only deal with horizontal lines right now");
+ }
+
+ protected void cubicBezierTo(int p1x, int p1y, int p2x, int p2y, int p3x, int p3y)
+ throws IOException {
+ throw new UnsupportedOperationException(
+ "Cannot handle cubic Bezier");
+ }
+
+ protected void rotateCoordinates(double angle) throws IOException {
+ throw new UnsupportedOperationException(
+ "Cannot handle coordinate rotation");
+ }
+
+ protected void scaleCoordinates(float xScale, float yScale) throws IOException {
+ throw new UnsupportedOperationException(
+ "Cannot handle coordinate scaling");
+ }
+
+ protected void translateCoordinates(int xTranslate, int yTranslate) throws IOException {
+ throw new UnsupportedOperationException(
+ "Cannot handle coordinate translation");
+ }
}
/** {@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) {
@@ -539,4 +1360,24 @@ public class AFPPainter extends AbstractIFPainter {
getPaintingState().restore();
}
+
+ /** {@inheritDoc} */
+ public void clipBackground(Rectangle rect, BorderProps bpsBefore, BorderProps bpsAfter,
+ BorderProps bpsStart, BorderProps bpsEnd) throws IFException {
+
+ //not supported by AFP
+ }
+
+ /** {@inheritDoc} */
+ public boolean isBackgroundRequired(BorderProps bpsBefore, BorderProps bpsAfter,
+ BorderProps bpsStart, BorderProps bpsEnd) {
+ return borderPainter.isBackgroundRequired( bpsBefore, bpsAfter,
+ bpsStart, bpsEnd);
+ }
+
+ /** {@inheritDoc} */
+ public void fillBackground(Rectangle rect, Paint fill, BorderProps bpsBefore,
+ BorderProps bpsAfter, BorderProps bpsStart, BorderProps bpsEnd) throws IFException {
+ // not supported in AFP
+ }
}
diff --git a/src/java/org/apache/fop/render/afp/AbstractAFPImageHandlerRawStream.java b/src/java/org/apache/fop/render/afp/AbstractAFPImageHandlerRawStream.java
index b36646117..e2d779192 100644
--- a/src/java/org/apache/fop/render/afp/AbstractAFPImageHandlerRawStream.java
+++ b/src/java/org/apache/fop/render/afp/AbstractAFPImageHandlerRawStream.java
@@ -91,9 +91,11 @@ public abstract class AbstractAFPImageHandlerRawStream extends AFPImageHandler
AFPDataObjectInfo dataObjectInfo = createDataObjectInfo();
// set resource information
- setResourceInformation(dataObjectInfo,
+
+ dataObjectInfo.setResourceInfo(createResourceInformation(
image.getInfo().getOriginalURI(),
- afpContext.getForeignAttributes());
+ afpContext.getForeignAttributes()));
+
// Positioning
dataObjectInfo.setObjectAreaInfo(createObjectAreaInfo(afpContext.getPaintingState(), pos));
diff --git a/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java b/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java
index c696e552d..9651cf446 100644
--- a/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java
+++ b/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java
@@ -316,7 +316,7 @@ public abstract class AbstractIFPainter implements IFPainter {
/** {@inheritDoc} */
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,
@@ -438,4 +438,10 @@ public abstract class AbstractIFPainter implements IFPainter {
return new AffineTransform(matrix);
}
+ /** {@inheritDoc} */
+ public boolean isBackgroundRequired( BorderProps bpsBefore, BorderProps bpsAfter,
+ BorderProps bpsStart, BorderProps bpsEnd) {
+ return true;
+ }
+
}
diff --git a/src/java/org/apache/fop/render/intermediate/BorderPainter.java b/src/java/org/apache/fop/render/intermediate/BorderPainter.java
index cc28028ef..0ff5c2036 100644
--- a/src/java/org/apache/fop/render/intermediate/BorderPainter.java
+++ b/src/java/org/apache/fop/render/intermediate/BorderPainter.java
@@ -32,6 +32,17 @@ import org.apache.fop.traits.RuleStyle;
*/
public abstract class BorderPainter {
+ /** 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 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
@@ -39,11 +50,52 @@ public abstract class BorderPainter {
* @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 bpsTop, BorderProps bpsBottom,
+ BorderProps bpsLeft, BorderProps bpsRight, Color innerBackgroundColor)
+ throws IFException {
+
+ try {
+ if (isRoundedCornersSupported()) {
+ drawRoundedBorders(borderRect, bpsTop, bpsBottom,
+ bpsLeft, bpsRight);
+
+ } else {
+ 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 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 bpsTop, BorderProps bpsBottom,
BorderProps bpsLeft, BorderProps bpsRight) throws IOException {
+
+ bpsTop = sanitizeBorderProps(bpsTop);
+ bpsBottom = sanitizeBorderProps(bpsBottom);
+ bpsLeft = sanitizeBorderProps(bpsLeft);
+ bpsRight = sanitizeBorderProps(bpsRight);
+
+
int startx = borderRect.x;
int starty = borderRect.y;
int width = borderRect.width;
@@ -75,15 +127,17 @@ public abstract class BorderPainter {
(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[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[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 (bpsTop.mode == BorderProps.COLLAPSE_OUTER) {
@@ -107,12 +161,12 @@ public abstract class BorderPainter {
}
if (bpsRight != null) {
int sy1 = starty;
- 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[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);
@@ -120,10 +174,10 @@ public abstract class BorderPainter {
int ey1a = ey1;
if (bpsRight.mode == BorderProps.COLLAPSE_OUTER) {
if (bpsTop != null && bpsTop.mode == BorderProps.COLLAPSE_OUTER) {
- sy1a -= clipw[0];
+ sy1a -= clipw[TOP];
}
if (bpsBottom != null && bpsBottom.mode == BorderProps.COLLAPSE_OUTER) {
- ey1a += clipw[2];
+ ey1a += clipw[BOTTOM];
}
lineTo(outerx, sy1a);
lineTo(outerx, ey1a);
@@ -139,12 +193,12 @@ public abstract class BorderPainter {
}
if (bpsBottom != null) {
int sx1 = startx;
- 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[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);
@@ -152,10 +206,10 @@ public abstract class BorderPainter {
int ex1a = ex1;
if (bpsBottom.mode == BorderProps.COLLAPSE_OUTER) {
if (bpsLeft != null && bpsLeft.mode == BorderProps.COLLAPSE_OUTER) {
- sx1a -= clipw[3];
+ sx1a -= clipw[LEFT];
}
if (bpsRight != null && bpsRight.mode == BorderProps.COLLAPSE_OUTER) {
- ex1a += clipw[1];
+ ex1a += clipw[RIGHT];
}
lineTo(ex1a, outery);
lineTo(sx1a, outery);
@@ -171,23 +225,25 @@ public abstract class BorderPainter {
}
if (bpsLeft != null) {
int sy1 = starty;
- 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[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 (bpsLeft.mode == BorderProps.COLLAPSE_OUTER) {
if (bpsTop != null && bpsTop.mode == BorderProps.COLLAPSE_OUTER) {
- sy1a -= clipw[0];
+ sy1a -= clipw[TOP];
}
if (bpsBottom != null && bpsBottom.mode == BorderProps.COLLAPSE_OUTER) {
- ey1a += clipw[2];
+ ey1a += clipw[BOTTOM];
}
lineTo(outerx, ey1a);
lineTo(outerx, sy1a);
@@ -202,6 +258,477 @@ public abstract class BorderPainter {
}
}
+ /** 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)};
+ if (!b[TOP] && !b[RIGHT] && !b[BOTTOM] && !b[LEFT]) {
+ return;
+ }
+ int[] bw = new int[] {
+ (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)};
+
+ 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[] {
+ (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 sx2 = (slant[TOP_LEFT] ? bw[LEFT] - clipw[LEFT] : 0);
+ final int ex1 = width;
+ 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,
+ 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 sx2 = (slant[BOTTOM_LEFT] ? bw[BOTTOM] - clipw[BOTTOM] : 0);
+ final int ex1 = height;
+ 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,
+ 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 sx2 = (slant[BOTTOM_LEFT] ? bw[LEFT] - clipw[LEFT] : 0);
+ final int ex1 = width;
+ 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,
+ 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 sx2 = (slant[TOP_RIGHT] ? bw[TOP] - clipw[TOP] : 0);
+ final int ex1 = height;
+ 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.
@@ -252,6 +779,118 @@ public abstract class BorderPainter {
protected abstract void lineTo(int x, int y) throws IOException;
/**
+ * Draw a cubic bezier from current position to (p3x, p3y) using the control points
+ * (p1x, p1y) and (p2x, p2y)
+ * @param p1x x coordinate of the first control point
+ * @param p1y y coordinate of the first control point
+ * @param p2x x coordinate of the second control point
+ * @param p2y y coordinate of the second control point
+ * @param p3x x coordinate of the end point
+ * @param p3y y coordinate of the end point
+ * @throws IOException if an I/O error occurs
+ */
+ protected abstract void cubicBezierTo(int p1x, int p1y, int p2x, int p2y, int p3x, int p3y)
+ throws IOException;
+
+ /**
+ * Draws an arc on the ellipse centered at (cx, cy) with width width and height height
+ * from start angle startAngle (with respect to the x-axis counter-clockwise)
+ * to the end angle endAngle.
+ * The ellipses major axis are assumed to coincide with the coordinate axis.
+ * The current position MUST coincide with the starting position on the ellipse.
+ * @param startAngle the start angle
+ * @param endAngle the end angle
+ * @param cx the x coordinate of the ellipse center
+ * @param cy the y coordinate of the ellipse center
+ * @param width the extent of the ellipse in the x direction
+ * @param height the extent of the ellipse in the y direction
+ * @throws IOException if an I/O error occurs
+ */
+ protected void arcTo(final double startAngle, final double endAngle, final int cx, final int cy,
+ final int width, final int height)
+ throws IOException {
+
+ // Implementation follows http://www.spaceroots.org/documents/ellipse/ -
+ // Drawing an elliptical arc using polylines, quadratic or cubic Bézier curves
+ // L. Maisonobe, July 21, 2003
+
+ // Scaling the coordinate system to represent the ellipse as a circle:
+ final double etaStart = Math.atan(Math.tan(startAngle) * width / height)
+ + quadrant(startAngle);
+ final double etaEnd = Math.atan(Math.tan(endAngle) * width / height)
+ + quadrant(endAngle);
+
+ final double sinStart = Math.sin(etaStart);
+ final double cosStart = Math.cos(etaStart);
+ final double sinEnd = Math.sin(etaEnd);
+ final double cosEnd = Math.cos(etaEnd);
+
+ final double p0x = cx + cosStart * width;
+ final double p0y = cy + sinStart * height;
+ final double p3x = cx + cosEnd * width;
+ final double p3y = cy + sinEnd * height;
+
+
+ double etaDiff = Math.abs(etaEnd - etaStart);
+ double tan = Math.tan((etaDiff) / 2d);
+ final double alpha = Math.sin(etaDiff) * (Math.sqrt(4d + 3d * tan * tan) - 1d) / 3d;
+
+
+ int order = etaEnd > etaStart ? 1 : -1;
+
+ // p1 = p0 + alpha*(-sin(startAngle), cos(startAngle))
+ final double p1x = p0x - alpha * sinStart * width * order;
+ final double p1y = p0y + alpha * cosStart * height * order;
+
+ // p1 = p3 + alpha*(sin(endAngle), -cos(endAngle))
+ final double p2x = p3x + alpha * sinEnd * width * order;
+ final double p2y = p3y - alpha * cosEnd * height * order;
+
+ //Draw the curve in original coordinate system
+ cubicBezierTo((int)p1x, (int)p1y, (int)p2x, (int)p2y, (int)p3x, (int)p3y);
+ }
+
+ private double quadrant(double angle) {
+ if (angle <= Math.PI ) {
+ if (angle <= Math.PI / 2d) {
+ return 0;
+ } else {
+ return Math.PI;
+ }
+ } else {
+ if (angle > Math.PI * 3d / 2d) {
+ return 2d * Math.PI;
+ } else {
+ return Math.PI;
+ }
+ }
+ }
+
+ /**
+ * Rotate the coordinate frame
+ * @param angle angle in radians to rotate the coordinate frame
+ * @throws IOException if an I/O error occurs
+ */
+ protected abstract void rotateCoordinates(double angle) throws IOException;
+
+ /**
+ * Translate the coordinate frame
+ * @param xTranslate translation in the x direction
+ * @param yTranslate translation in the y direction
+ * @throws IOException if an I/O error occurs
+ */
+ protected abstract void translateCoordinates(int xTranslate, int yTranslate) throws IOException;
+
+ /**
+ * Scale the coordinate frame
+ * @param xScale scale factor in the x direction
+ * @param yScale scale factor in the y direction
+ * @throws IOException if an I/O error occurs
+ */
+ protected abstract void scaleCoordinates(float xScale, float yScale) throws IOException;
+
+
+ /**
* Closes the current path.
* @throws IOException if an I/O error occurs
*/
@@ -275,4 +914,12 @@ public abstract class BorderPainter {
*/
protected abstract void restoreGraphicsState() throws IOException;
+ /**
+ * TODO remove the System.props when rounded corners code is stable
+ * @return true iff in rounded corners mode
+ */
+ public static boolean isRoundedCornersSupported() {
+ return "true".equalsIgnoreCase(System.getProperty(ROUNDED_CORNERS, "true"));
+ }
+
}
diff --git a/src/java/org/apache/fop/render/intermediate/IFException.java b/src/java/org/apache/fop/render/intermediate/IFException.java
index 52c650765..7e12c301b 100644
--- a/src/java/org/apache/fop/render/intermediate/IFException.java
+++ b/src/java/org/apache/fop/render/intermediate/IFException.java
@@ -43,4 +43,16 @@ public class IFException extends Exception {
super(message, cause);
}
+ /**
+ * Constructs a new exception with the cause.
+ *
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method). (A <code>null</code> value is
+ * permitted, and indicates that the cause is nonexistent or
+ * unknown.)
+ */
+ /*public IFException( Exception cause) {
+ super(cause);
+ }*/
+
}
diff --git a/src/java/org/apache/fop/render/intermediate/IFPainter.java b/src/java/org/apache/fop/render/intermediate/IFPainter.java
index 06dfbd181..5d2beb65c 100644
--- a/src/java/org/apache/fop/render/intermediate/IFPainter.java
+++ b/src/java/org/apache/fop/render/intermediate/IFPainter.java
@@ -168,6 +168,34 @@ public interface IFPainter {
void clipRect(Rectangle rect) throws IFException;
//TODO clipRect() shall be considered temporary until verified with SVG and PCL
+
+ /**
+ * Restricts the current clipping region to the inner border.
+ * @param rect the rectangle's coordinates and extent
+ * @param bpsBefore the border segment on the before-side (top)
+ * @param bpsAfter the border segment on the after-side (bottom)
+ * @param bpsStart the border segment on the start-side (left)
+ * @param bpsEnd the border segment on the end-side (right)
+ * @throws IFException if an error occurs while handling this event
+ */
+ void clipBackground (Rectangle rect,
+ BorderProps bpsBefore, BorderProps bpsAfter,
+ BorderProps bpsStart, BorderProps bpsEnd) throws IFException;
+
+
+ /**
+ * TODO Painter-specific rounded borders logic required background drawing to be
+ * made optional. A future refactoring of the rounded borders code should aim to make
+ * the need for this abstraction obsolete
+ * @param bpsBefore the before border
+ * @param bpsAfter the after border
+ * @param bpsStart the start border
+ * @param bpsEnd the end border
+ * @return true if and only if background drawing is required
+ */
+ boolean isBackgroundRequired(BorderProps bpsBefore, BorderProps bpsAfter,
+ BorderProps bpsStart, BorderProps bpsEnd);
+
/**
* Fills a rectangular area.
* @param rect the rectangle's coordinates and extent
@@ -184,11 +212,12 @@ public interface IFPainter {
* @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 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!
diff --git a/src/java/org/apache/fop/render/intermediate/IFParser.java b/src/java/org/apache/fop/render/intermediate/IFParser.java
index 827eec820..293487ac2 100644
--- a/src/java/org/apache/fop/render/intermediate/IFParser.java
+++ b/src/java/org/apache/fop/render/intermediate/IFParser.java
@@ -650,6 +650,19 @@ public class IFParser implements IFConstants {
int y = Integer.parseInt(attributes.getValue("y"));
int width = Integer.parseInt(attributes.getValue("width"));
int height = Integer.parseInt(attributes.getValue("height"));
+ BorderProps[] borders = new BorderProps[4];
+ for (int i = 0; i < 4; i++) {
+ String b = attributes.getValue(SIDES[i]);
+ if (b != null) {
+ borders[i] = BorderProps.valueOf(userAgent, b);
+ }
+ }
+
+ if (!(borders[0] == null && borders[1] == null
+ && borders[2] == null && borders[3] == null)) {
+ painter.clipBackground(new Rectangle(x, y, width, height),
+ borders[0], borders[1], borders[2], borders[3]);
+ }
painter.clipRect(new Rectangle(x, y, width, height));
}
@@ -668,7 +681,26 @@ public class IFParser implements IFConstants {
} catch (PropertyException pe) {
throw new IFException("Error parsing the fill attribute", pe);
}
- painter.fillRect(new Rectangle(x, y, width, height), fillColor);
+
+ Rectangle rectangularArea = new Rectangle(x, y, width, height);
+
+ //TODO should rect be overloaded to include rounded corners
+ // or should we introduce a new IF element?
+ BorderProps[] borders = new BorderProps[4];
+ for (int i = 0; i < 4; i++) {
+ String b = attributes.getValue(SIDES[i]);
+ if (b != null) {
+ borders[i] = BorderProps.valueOf(userAgent, b);
+ }
+ }
+
+ if (!(borders[0] == null && borders[1] == null
+ && borders[2] == null && borders[3] == null)) {
+ painter.clipBackground(rectangularArea,
+ borders[0], borders[1], borders[2], borders[3]);
+ }
+
+ painter.fillRect(rectangularArea , fillColor);
}
}
@@ -709,9 +741,16 @@ public class IFParser implements IFConstants {
borders[i] = BorderProps.valueOf(userAgent, b);
}
}
+ Color backgroundColor;
+
+ try {
+ backgroundColor = getAttributeAsColor(attributes, "inner-background-color");
+ } catch (PropertyException pe) {
+ throw new IFException("Error parsing the color attribute", pe);
+ }
painter.drawBorderRect(new Rectangle(x, y, width, height),
- borders[0], borders[1], borders[2], borders[3]);
+ borders[0], borders[1], borders[2], borders[3], backgroundColor);
}
}
diff --git a/src/java/org/apache/fop/render/intermediate/IFRenderer.java b/src/java/org/apache/fop/render/intermediate/IFRenderer.java
index e5c1f98c7..45b0c3a93 100644
--- a/src/java/org/apache/fop/render/intermediate/IFRenderer.java
+++ b/src/java/org/apache/fop/render/intermediate/IFRenderer.java
@@ -39,11 +39,10 @@ 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;
-import org.apache.batik.parser.AWTTransformProducer;
-
import org.apache.xmlgraphics.xmp.Metadata;
import org.apache.xmlgraphics.xmp.schemas.DublinCoreAdapter;
import org.apache.xmlgraphics.xmp.schemas.DublinCoreSchema;
@@ -1332,18 +1331,44 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
handleIFException(ife);
}
}
-
+ /** {@inheritDoc} */
+ protected void clipBackground(float startx, float starty,
+ float width, float height,
+ BorderProps bpsBefore, BorderProps bpsAfter,
+ BorderProps bpsStart, BorderProps bpsEnd) {
+ pushGroup(new IFGraphicContext.Group());
+ Rectangle rect = toMillipointRectangle(startx, starty, width, height);
+ try {
+ painter.clipBackground( rect,
+ bpsBefore, bpsAfter, bpsStart, bpsEnd);
+ } catch (IFException ife) {
+ handleIFException(ife);
+ }
+ }
/** {@inheritDoc} */
protected void closePath() {
throw new IllegalStateException("Not used");
}
/** {@inheritDoc} */
+ protected void drawBackground(float startx, float starty,
+ float width, float height,
+ Trait.Background back,
+ BorderProps bpsBefore, BorderProps bpsAfter,
+ BorderProps bpsStart, BorderProps bpsEnd) {
+ if (painter.isBackgroundRequired(bpsBefore, bpsAfter, bpsStart, bpsEnd)) {
+ super.drawBackground(startx, starty, width, height,
+ back, bpsBefore, bpsAfter,
+ bpsStart, bpsEnd);
+ }
+ }
+
+ /** {@inheritDoc} */
protected void drawBorders( // CSOK: ParameterNumber
float startx, float starty,
float width, float height,
BorderProps bpsBefore, BorderProps bpsAfter,
- BorderProps bpsStart, BorderProps bpsEnd, int level) {
+ BorderProps bpsStart, BorderProps bpsEnd, int level, Color innerBackgroundColor) {
Rectangle rect = toMillipointRectangle(startx, starty, width, height);
try {
BorderProps bpsTop = bpsBefore;
@@ -1357,7 +1382,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
bpsLeft = bpsEnd;
bpsRight = bpsStart;
}
- painter.drawBorderRect(rect, bpsTop, bpsBottom, bpsLeft, bpsRight);
+ painter.drawBorderRect(rect, bpsTop, bpsBottom, bpsLeft, bpsRight, innerBackgroundColor);
} catch (IFException ife) {
handleIFException(ife);
}
diff --git a/src/java/org/apache/fop/render/intermediate/IFSerializer.java b/src/java/org/apache/fop/render/intermediate/IFSerializer.java
index 7114f51e3..4c6781706 100644
--- a/src/java/org/apache/fop/render/intermediate/IFSerializer.java
+++ b/src/java/org/apache/fop/render/intermediate/IFSerializer.java
@@ -514,6 +514,37 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
}
/** {@inheritDoc} */
+ public void clipBackground(Rectangle rect, BorderProps bpsBefore, BorderProps bpsAfter,
+ BorderProps bpsStart, BorderProps bpsEnd) throws IFException {
+ try {
+ AttributesImpl atts = new AttributesImpl();
+ addAttribute(atts, "x", Integer.toString(rect.x));
+ addAttribute(atts, "y", Integer.toString(rect.y));
+ addAttribute(atts, "width", Integer.toString(rect.width));
+ addAttribute(atts, "height", Integer.toString(rect.height));
+ if (hasRoundedCorners(bpsBefore, bpsAfter, bpsStart, bpsEnd)) {
+
+ if (bpsBefore != null) {
+ addAttribute(atts, "before", bpsBefore.toString());
+ }
+ if (bpsAfter != null) {
+ addAttribute(atts, "after", bpsAfter.toString());
+ }
+ if (bpsStart != null) {
+ addAttribute(atts, "start", bpsStart.toString());
+ }
+ if (bpsEnd != null) {
+ addAttribute(atts, "end", bpsEnd.toString());
+ }
+ }
+ handler.element(EL_CLIP_RECT, atts);
+ } catch (SAXException e) {
+ throw new IFException("SAX error in clipRect()", e);
+ }
+ }
+
+
+ /** {@inheritDoc} */
public void fillRect(Rectangle rect, Paint fill) throws IFException {
if (fill == null) {
return;
@@ -531,9 +562,38 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
}
}
+ //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 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;
}
@@ -555,6 +615,12 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
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);
@@ -851,4 +917,10 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
throw new IFException("SAX error serializing object", e);
}
}
+
+ /** {@inheritDoc} */
+ public boolean isBackgroundRequired(BorderProps bpsTop, BorderProps bpsBottom,
+ BorderProps bpsLeft, BorderProps bpsRight) {
+ return true;
+ }
}
diff --git a/src/java/org/apache/fop/render/java2d/Java2DBorderPainter.java b/src/java/org/apache/fop/render/java2d/Java2DBorderPainter.java
index b2b29188b..b3ad5ff7a 100644
--- a/src/java/org/apache/fop/render/java2d/Java2DBorderPainter.java
+++ b/src/java/org/apache/fop/render/java2d/Java2DBorderPainter.java
@@ -26,6 +26,7 @@ import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
+import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -315,4 +316,42 @@ public class Java2DBorderPainter extends BorderPainter {
this.currentPath = null;
}
+ /** {@inheritDoc} */
+ protected void arcTo(double startAngle, double endAngle, int cx, int cy, int width, int height)
+ throws IOException {
+ // TODO Auto-generated method stub
+
+ }
+
+ /** {@inheritDoc} */
+ protected void changeCoords(double a, double b, double c, double d, double e, double f) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /** {@inheritDoc} */
+ protected void cubicBezierTo(int p1x, int p1y, int p2x, int p2y, int p3x, int p3y)
+ throws IOException {
+ // TODO Auto-generated method stub
+
+ }
+
+ /** {@inheritDoc} */
+ protected void rotateCoordinates(double angle) throws IOException {
+ // TODO Auto-generated method stub
+
+ }
+
+ /** {@inheritDoc} */
+ protected void scaleCoordinates(float xScale, float yScale) throws IOException {
+ // TODO Auto-generated method stub
+
+ }
+
+ /** {@inheritDoc} */
+ protected void translateCoordinates(int xTranslate, int yTranslate) throws IOException {
+ // TODO Auto-generated method stub
+
+ }
+
}
diff --git a/src/java/org/apache/fop/render/java2d/Java2DPainter.java b/src/java/org/apache/fop/render/java2d/Java2DPainter.java
index 575242d38..7e4d72c14 100644
--- a/src/java/org/apache/fop/render/java2d/Java2DPainter.java
+++ b/src/java/org/apache/fop/render/java2d/Java2DPainter.java
@@ -174,6 +174,13 @@ public class Java2DPainter extends AbstractIFPainter {
}
/** {@inheritDoc} */
+ public void clipBackground(Rectangle rect, BorderProps bpsBefore, BorderProps bpsAfter,
+ BorderProps bpsStart, BorderProps bpsEnd) throws IFException {
+ // TODO Auto-generated method stub
+
+ }
+
+ /** {@inheritDoc} */
public void fillRect(Rectangle rect, Paint fill) throws IFException {
if (fill == null) {
return;
@@ -188,12 +195,7 @@ public class Java2DPainter extends AbstractIFPainter {
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);
}
}
@@ -263,4 +265,6 @@ public class Java2DPainter extends AbstractIFPainter {
g2dState.transform(transform);
}
+
+
}
diff --git a/src/java/org/apache/fop/render/pcl/PCLPainter.java b/src/java/org/apache/fop/render/pcl/PCLPainter.java
index 0d630826c..a057252d6 100644
--- a/src/java/org/apache/fop/render/pcl/PCLPainter.java
+++ b/src/java/org/apache/fop/render/pcl/PCLPainter.java
@@ -100,7 +100,7 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants {
/** @return the target resolution */
protected int getResolution() {
- int resolution = (int)Math.round(getUserAgent().getTargetResolution());
+ int resolution = Math.round(getUserAgent().getTargetResolution());
if (resolution <= 300) {
return 300;
} else {
@@ -183,6 +183,14 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants {
}
/** {@inheritDoc} */
+ public void clipBackground(Rectangle rect, BorderProps bpsBefore, BorderProps bpsAfter,
+ BorderProps bpsStart, BorderProps bpsEnd) throws IFException {
+ //PCL cannot clip (only HP GL/2 can)
+ //If you need clipping support, switch to RenderingMode.BITMAP.
+
+ }
+
+ /** {@inheritDoc} */
public void fillRect(Rectangle rect, Paint fill) throws IFException {
if (fill == null) {
return;
@@ -210,7 +218,7 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants {
final BorderProps top, final BorderProps bottom,
final BorderProps left, final BorderProps right) throws IFException {
if (isSpeedOptimized()) {
- super.drawBorderRect(rect, top, bottom, left, right);
+ super.drawBorderRect(rect, top, bottom, left, right, null);
return;
}
if (top != null || bottom != null || left != null || right != null) {
@@ -532,4 +540,6 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants {
gen.setCursorPos(transPoint.getX(), transPoint.getY());
}
+
+
}
diff --git a/src/java/org/apache/fop/render/pdf/PDFBorderPainter.java b/src/java/org/apache/fop/render/pdf/PDFBorderPainter.java
index f8090fdeb..4bfba9df3 100644
--- a/src/java/org/apache/fop/render/pdf/PDFBorderPainter.java
+++ b/src/java/org/apache/fop/render/pdf/PDFBorderPainter.java
@@ -22,6 +22,7 @@ package org.apache.fop.render.pdf;
import java.awt.Color;
import java.awt.Point;
import java.awt.Rectangle;
+import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -53,6 +54,7 @@ public class PDFBorderPainter extends BorderPainter {
protected void drawBorderLine( // CSOK: ParameterNumber
int x1, int y1, int x2, int y2, boolean horz,
boolean startOrBefore, int style, Color col) {
+ //TODO lose scale?
drawBorderLine(generator, x1 / 1000f, y1 / 1000f, x2 / 1000f, y2 / 1000f,
horz, startOrBefore, style, col);
}
@@ -68,11 +70,12 @@ public class PDFBorderPainter extends BorderPainter {
float colFactor;
float w = x2 - x1;
float h = y2 - y1;
+ /*
if ((w < 0) || (h < 0)) {
LOG.error("Negative extent received (w=" + w + ", h=" + h
+ "). Border won't be painted.");
return;
- }
+ }*/
switch (style) {
case Constants.EN_DASHED:
generator.setColor(col, false);
@@ -291,6 +294,7 @@ public class PDFBorderPainter extends BorderPainter {
}
static final String format(int coordinate) {
+ //TODO lose scale?
return format(coordinate / 1000f);
}
@@ -328,4 +332,38 @@ public class PDFBorderPainter extends BorderPainter {
generator.add("Q\n");
}
+ /** {@inheritDoc} */
+ protected void cubicBezierTo(int p1x, int p1y, int p2x, int p2y, int p3x, int p3y) {
+ generator.add(format(p1x) + " " + format(p1y) + " " + format(p2x) + " " + format(p2y)
+ + " " + format(p3x) + " " + format(p3y) + " c ");
+ }
+
+
+ private void transformCoordinates(int a, int b, int c, int d, int e, int f) {
+ generator.add( "" + format(a) + " " + format(b) + " " + format(c) + " " + format(d)
+ + " " + format(e) + " " + format(f) + " cm ");
+ }
+
+ private void transformCoordinates2(float a, float b, float c, float d, float e, float f) {
+ generator.add( "" + format(a) + " " + format(b) + " " + format(c) + " " + format(d)
+ + " " + format(e) + " " + format(f) + " cm ");
+ }
+
+ /** {@inheritDoc} */
+ protected void rotateCoordinates(double angle) throws IOException {
+ float s = (float)Math.sin(angle);
+ float c = (float)Math.cos(angle);
+ transformCoordinates2(c, s, -s, c, 0, 0);
+ }
+
+ /** {@inheritDoc} */
+ protected void translateCoordinates(int xTranslate, int yTranslate) throws IOException {
+ transformCoordinates(1000, 0, 0, 1000, xTranslate, yTranslate);
+ }
+
+ /** {@inheritDoc} */
+ protected void scaleCoordinates(float xScale, float yScale) throws IOException {
+ transformCoordinates2(xScale, 0, 0, yScale, 0, 0);
+ }
+
}
diff --git a/src/java/org/apache/fop/render/pdf/PDFPainter.java b/src/java/org/apache/fop/render/pdf/PDFPainter.java
index 4928e7251..d7a335dcc 100644
--- a/src/java/org/apache/fop/render/pdf/PDFPainter.java
+++ b/src/java/org/apache/fop/render/pdf/PDFPainter.java
@@ -229,6 +229,20 @@ public class PDFPainter extends AbstractIFPainter {
}
/** {@inheritDoc} */
+ public void clipBackground(Rectangle rect,
+ BorderProps bpsBefore, BorderProps bpsAfter,
+ BorderProps bpsStart, BorderProps bpsEnd) throws IFException {
+
+ try {
+ borderPainter.clipBackground(rect,
+ bpsBefore, bpsAfter, bpsStart, bpsEnd);
+ } catch (IOException ioe) {
+ throw new IFException("I/O error while clipping background", ioe);
+ }
+
+ }
+
+ /** {@inheritDoc} */
public void fillRect(Rectangle rect, Paint fill) throws IFException {
if (fill == null) {
return;
@@ -262,17 +276,16 @@ public class PDFPainter extends AbstractIFPainter {
/** {@inheritDoc} */
@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, 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)
diff --git a/src/java/org/apache/fop/render/ps/PSBorderPainter.java b/src/java/org/apache/fop/render/ps/PSBorderPainter.java
index a52974d36..476e14c99 100644
--- a/src/java/org/apache/fop/render/ps/PSBorderPainter.java
+++ b/src/java/org/apache/fop/render/ps/PSBorderPainter.java
@@ -330,4 +330,58 @@ public class PSBorderPainter extends BorderPainter {
generator.restoreGraphicsState();
}
+
+
+
+ /** {@inheritDoc} */
+ protected void cubicBezierTo(int p1x, int p1y, int p2x, int p2y, int p3x, int p3y)
+ throws IOException {
+ StringBuffer sb = new StringBuffer();
+ sb.append(generator.formatDouble(toPoints(p1x)));
+ sb.append(" ");
+ sb.append(generator.formatDouble(toPoints(p1y)));
+ sb.append(" ");
+ sb.append(generator.formatDouble(toPoints(p2x)));
+ sb.append(" ");
+ sb.append(generator.formatDouble(toPoints(p2y)));
+ sb.append(" ");
+ sb.append(generator.formatDouble(toPoints(p3x)));
+ sb.append(" ");
+ sb.append(generator.formatDouble(toPoints(p3y)));
+ sb.append(" curveto ");
+ generator.writeln(sb.toString());
+
+ }
+
+ /** {@inheritDoc} */
+ protected void rotateCoordinates(double angle) throws IOException {
+ StringBuffer sb = new StringBuffer();
+ sb.append(generator.formatDouble(angle * 180d / Math.PI));
+ sb.append(" ");
+ sb.append(" rotate ");
+ generator.writeln(sb.toString());
+ }
+
+ /** {@inheritDoc} */
+ protected void translateCoordinates(int xTranslate, int yTranslate) throws IOException {
+ StringBuffer sb = new StringBuffer();
+ sb.append(generator.formatDouble(toPoints(xTranslate)));
+ sb.append(" ");
+ sb.append(generator.formatDouble(toPoints(yTranslate)));
+ sb.append(" ");
+ sb.append(" translate ");
+ generator.writeln(sb.toString());
+ }
+
+ /** {@inheritDoc} */
+ protected void scaleCoordinates(float xScale, float yScale) throws IOException {
+ StringBuffer sb = new StringBuffer();
+ sb.append(generator.formatDouble(xScale));
+ sb.append(" ");
+ sb.append(generator.formatDouble(yScale));
+ sb.append(" ");
+ sb.append(" scale ");
+ generator.writeln(sb.toString());
+ }
+
}
diff --git a/src/java/org/apache/fop/render/ps/PSPainter.java b/src/java/org/apache/fop/render/ps/PSPainter.java
index c2288019a..9d16cb428 100644
--- a/src/java/org/apache/fop/render/ps/PSPainter.java
+++ b/src/java/org/apache/fop/render/ps/PSPainter.java
@@ -216,6 +216,20 @@ public class PSPainter extends AbstractIFPainter {
}
/** {@inheritDoc} */
+ public void clipBackground(Rectangle rect,
+ BorderProps bpsBefore, BorderProps bpsAfter,
+ BorderProps bpsStart, BorderProps bpsEnd) throws IFException {
+
+ try {
+ borderPainter.clipBackground(rect,
+ bpsBefore, bpsAfter, bpsStart, bpsEnd);
+ } catch (IOException ioe) {
+ throw new IFException("I/O error while clipping background", ioe);
+ }
+
+ }
+
+ /** {@inheritDoc} */
public void fillRect(Rectangle rect, Paint fill) throws IFException {
if (fill == null) {
return;
@@ -242,15 +256,15 @@ public class PSPainter extends AbstractIFPainter {
/** {@inheritDoc} */
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();
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);
diff --git a/src/java/org/apache/fop/traits/BorderProps.java b/src/java/org/apache/fop/traits/BorderProps.java
index ae7a9a434..051041c1d 100644
--- a/src/java/org/apache/fop/traits/BorderProps.java
+++ b/src/java/org/apache/fop/traits/BorderProps.java
@@ -49,6 +49,12 @@ public class BorderProps implements Serializable {
public Color color; // CSOK: VisibilityModifier
/** Border width */
public int width; // CSOK: VisibilityModifier
+
+ private int radiusStart = 0;
+ private int radiusEnd = 0;
+
+
+
/** Border mode (one of SEPARATE, COLLAPSE_INNER and COLLAPSE_OUTER) */
public int mode; // CSOK: VisibilityModifier
@@ -78,6 +84,37 @@ public class BorderProps implements Serializable {
}
/**
+ *
+ * @return the radius of the corner adjacent to the before or start border
+ */
+ public int getRadiusStart() {
+ return radiusStart;
+ }
+
+ /**
+ *
+ * @param radiusStart the radius of the corner adjacent to the before or start border
+ */
+ public void setRadiusStart(int radiusStart) {
+ this.radiusStart = radiusStart;
+ }
+
+ /**
+ * @return the radius of the corner adjacent to the after or end border
+ */
+ public int getRadiusEnd() {
+ return radiusEnd;
+ }
+
+ /**
+ *
+ * @param radiusEnd the radius of the corner adjacent to the after or end border
+ */
+ public void setRadiusEnd(int radiusEnd) {
+ this.radiusEnd = radiusEnd;
+ }
+
+ /**
* @param bp the border properties or null
* @return the effective width of the clipped part of the border
*/
@@ -117,7 +154,9 @@ public class BorderProps implements Serializable {
&& 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;
@@ -159,7 +198,18 @@ public class BorderProps implements Serializable {
throw new IllegalArgumentException(e.getMessage());
}
- return new BorderProps(style, width, c, mode);
+ BorderProps bp = new BorderProps(style, width, c, mode);
+
+ found = m.find();
+ if (found) {
+ int startRadius = Integer.parseInt(m.group());
+ m.find();
+ int endRadius = Integer.parseInt(m.group());
+ bp.setRadiusStart(startRadius);
+ bp.setRadiusEnd(endRadius);
+ }
+
+ return bp;
} else {
throw new IllegalArgumentException("BorderProps must be surrounded by parentheses");
}
@@ -176,12 +226,24 @@ public class BorderProps implements Serializable {
sbuf.append(',');
sbuf.append(width);
if (mode != SEPARATE) {
- sbuf.append(',');
if (mode == COLLAPSE_INNER) {
- sbuf.append("collapse-inner");
+ sbuf.append(",collapse-inner");
} else {
- sbuf.append("collapse-outer");
+ sbuf.append(",collapse-outer");
+ }
+ }
+
+ if (radiusStart != 0 || radiusEnd != 0) {
+ if (mode == SEPARATE) {
+ // Because of the corner radii properties the mode must be set
+ // so that the parameter index is consistent
+ sbuf.append(",separate");
}
+ sbuf.append(',');
+ sbuf.append(radiusStart);
+
+ sbuf.append(',');
+ sbuf.append(radiusEnd);
}
sbuf.append(')');
return sbuf.toString();
diff --git a/src/sandbox/org/apache/fop/render/svg/SVGPainter.java b/src/sandbox/org/apache/fop/render/svg/SVGPainter.java
index 3eba51097..147536ccb 100644
--- a/src/sandbox/org/apache/fop/render/svg/SVGPainter.java
+++ b/src/sandbox/org/apache/fop/render/svg/SVGPainter.java
@@ -30,7 +30,6 @@ import java.io.IOException;
import java.util.Map;
import org.w3c.dom.Document;
-
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
@@ -269,6 +268,13 @@ public class SVGPainter extends AbstractIFPainter implements SVGConstants {
}
/** {@inheritDoc} */
+ public void clipBackground(Rectangle rect, BorderProps bpsBefore, BorderProps bpsAfter,
+ BorderProps bpsStart, BorderProps bpsEnd) throws IFException {
+ //TODO Implement me!!!
+
+ }
+
+ /** {@inheritDoc} */
public void fillRect(Rectangle rect, Paint fill) throws IFException {
if (fill == null) {
return;
@@ -408,4 +414,13 @@ public class SVGPainter extends AbstractIFPainter implements SVGConstants {
}
}
+ /** {@inheritDoc} */
+ public void fillBackground(Rectangle rect, Paint fill, BorderProps bpsBefore,
+ BorderProps bpsAfter, BorderProps bpsStart, BorderProps bpsEnd) throws IFException {
+ // Not supported in SVG
+
+ }
+
+
+
}