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