<xs:complexType>
<xs:attributeGroup ref="mf:rectAtts"/>
<xs:attributeGroup ref="mf:fillAtts"/>
+ <xs:attributeGroup ref="mf:borderAtts"/>
</xs:complexType>
</xs:element>
<xs:element name="line">
<xs:element name="border-rect">
<xs:complexType>
<xs:attributeGroup ref="mf:rectAtts"/>
- <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:attribute name="inner-background-color" type="mf:colorType"/>
+ <xs:attributeGroup ref="mf:borderAtts"/>
</xs:complexType>
</xs:element>
<xs:element name="image">
<xs:attributeGroup name="rectAtts">
<xs:attributeGroup ref="mf:posAtts"/>
<xs:attributeGroup ref="mf:sizeAtts"/>
+ </xs:attributeGroup>
+ <xs:attributeGroup name="borderAtts">
+ <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="fillAtts">
<xs:attribute name="fill" type="xs:string" default="none"/>
AFPResourceInfo resourceInfo = dataObjectInfo.getResourceInfo();
updateResourceInfoUri(resourceInfo);
- if (includeCachedObject(resourceInfo, null)) {
+ if (includeCachedObject(resourceInfo, dataObjectInfo.getObjectAreaInfo())) {
return;
}
(Trait.Background) backgroundArea.getTrait(Trait.BACKGROUND),
bpsBefore, bpsAfter, bpsStart, bpsEnd);
- Color bg = null;
- if (backgroundTrait != null) {
+ // TODO what is the default bg color? Should we serialize it?
+ Color bg = Color.white;
+ if (backgroundTrait != null && backgroundTrait.getColor() != null) {
bg = backgroundTrait.getColor();
}
updateColor(back.getColor(), true);
fillRect(sx, sy, paddRectWidth, paddRectHeight);
}
+
if (back.getImageInfo() != null) {
ImageSize imageSize = back.getImageInfo().getSize();
-
int horzCount = (int)((paddRectWidth
* 1000 / imageSize.getWidthMpt()) + 1.0f);
int vertCount = (int)((paddRectHeight
}
/**
+ * TODO represent border related parameters in a class
* Clip the background to the inner border.
* This draws the border traits given the position and the traits.
*
* @param 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
*/
protected void drawBorders( // CSOK: ParameterNumber
float startx, float starty, float width, float height,
* @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 innerBackgroundColor the background color of the block
*/
protected void drawBorders( // CSOK: MethodLength
Rectangle2D.Float borderRect,
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,
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,
afterCut.lineTo(startRadius, 0);
beforeCut.lineTo(0, beforeRadius);
} else {
- afterCut.lineTo(startRadius, (float)(borderWidthRatio * startRadius));
+ afterCut.lineTo(startRadius, (borderWidthRatio * startRadius));
beforeCut.lineTo(1f / borderWidthRatio * beforeRadius, beforeRadius);
afterCut.lineTo(startRadius, 0);
bpsStart, bpsEnd);
}
+ /** {@inheritDoc} */
+ public void fillBackground(Rectangle rect, Paint fill, BorderProps bpsBefore,
+ BorderProps bpsAfter, BorderProps bpsStart, BorderProps bpsEnd) throws IFException {
+ // not supported in AFP
+ }
}
*/
public abstract class BorderPainter {
+ /** TODO remove before integration*/
public static final String ROUNDED_CORNERS = "fop.round-corners";
+ /** TODO Use a class to model border instead of an array
+ * convention index of before, end, after and start borders */
protected static final int BEFORE = 0, END = 1, AFTER = 2, START = 3;
+ /** TODO Use a class to model border corners 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;
* @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 innerBackgroundColor the inner background color
* @throws IFException if an error occurs while drawing the borders
*/
public void drawBorders(Rectangle borderRect, // CSOK: MethodLength
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
+ * @throws IOException
+ */
protected void drawRectangularBorders(Rectangle borderRect,
BorderProps bpsBefore, BorderProps bpsAfter,
BorderProps bpsStart, BorderProps bpsEnd) throws IOException {
}
}
+ /** 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 {
}
}
+ /** 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,
}
}
- if (ellipseBERadiusX != 0) {
+ if (ellipseBERadiusX != 0 && ellipseBERadiusY != 0) {
final double[] outerJoinMetrics = getCornerBorderJoinMetrics(
ellipseBERadiusX, ellipseBERadiusY, (double)innery / (ex1 - ex2));
/**
* Clip the background to the inner border
- * @param rect
- * @param bpsBefore
- * @param bpsAfter
- * @param bpsStart
- * @param bpsEnd
+ * @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,
lineTo(startx + ellipseSE, starty + height);
- if (ellipseSE > 0 && ellipseSE > 0) {
+ if (ellipseSE > 0 && ellipseAS > 0) {
arcTo( Math.PI / 2, Math.PI, startx + ellipseSE,
starty + height - ellipseAS, ellipseSE, ellipseAS);
}
}
- /*
- * If the ellipse radii exceed the border edge length, the ellipses are rescaled.
+ /**
+ * 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,
double esf = 1d;
if (bpsBefore != null) {
- if (bpsStart != null && bpsEnd != null
- && bpsStart.getRadiusStart() + bpsEnd.getRadiusStart() > 0) {
+ double ellipseExtent = (bpsStart == null ? 0 : bpsStart.getRadiusStart())
+ + (bpsEnd == null ? 0 : bpsEnd.getRadiusStart());
- double f = (double)width / (bpsStart.getRadiusStart() + bpsEnd.getRadiusStart());
+ if (ellipseExtent > 0) {
+ double f = width / ellipseExtent;
if (f < esf) {
esf = f;
}
}
}
+
if (bpsStart != null) {
- if (bpsAfter != null && bpsBefore != null
- && bpsAfter.getRadiusStart() + bpsBefore.getRadiusStart() > 0) {
- double f = (double)height / (bpsAfter.getRadiusStart()
- + bpsBefore.getRadiusStart());
+ 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) {
- if (bpsStart != null && bpsEnd != null
- && bpsStart.getRadiusEnd() + bpsEnd.getRadiusEnd() > 0) {
- double f = (double)width / (bpsStart.getRadiusEnd() + bpsEnd.getRadiusEnd());
+ 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) {
- if (bpsAfter != null && bpsBefore != null
- && bpsAfter.getRadiusEnd() + bpsBefore.getRadiusEnd() > 0) {
- double f = (double)height / (bpsAfter.getRadiusEnd() + bpsBefore.getRadiusEnd());
+ double ellipseExtent = (bpsAfter == null ? 0 : bpsAfter.getRadiusEnd())
+ + (bpsBefore == null ? 0 : bpsBefore.getRadiusEnd());
+
+ if (ellipseExtent > 0) {
+ double f = height / ellipseExtent;
if (f < esf) {
esf = f;
}
*/
protected abstract void restoreGraphicsState() throws IOException;
+ /**
+ * TODO remove the System.props when rounded corners code is stable
+ * @return true iff in rounded corners mode
+ */
public static boolean isRoundedCornersSupported() {
return "true".equalsIgnoreCase(System.getProperty(ROUNDED_CORNERS, "true"));
}
/**
- *
- * @param bpsBefore
- * @param bpsAfter
- * @param bpsStart
- * @param bpsEnd
- * @return true if the background needs to be painted
- */
- boolean isBackgroundRequired( BorderProps bpsBefore, BorderProps bpsAfter,
+ * TODO Painter-specific rounded borders logic required background drawing to be
+ * made optional. A future refactoring of the rounded borders code should aim to make
+ * the need for this abstraction obsolete
+ * @param bpsBefore the before border
+ * @param bpsAfter the after border
+ * @param bpsStart the start border
+ * @param bpsEnd the end border
+ * @return true if and only if background drawing is required
+ */
+ boolean isBackgroundRequired(BorderProps bpsBefore, BorderProps bpsAfter,
BorderProps bpsStart, BorderProps bpsEnd);
/**
int y = Integer.parseInt(attributes.getValue("y"));
int width = Integer.parseInt(attributes.getValue("width"));
int height = Integer.parseInt(attributes.getValue("height"));
+ BorderProps[] borders = new BorderProps[4];
+ for (int i = 0; i < 4; i++) {
+ String b = attributes.getValue(SIDES[i]);
+ if (b != null) {
+ borders[i] = BorderProps.valueOf(userAgent, b);
+ }
+ }
+
+ if (!(borders[0] == null && borders[1] == null
+ && borders[2] == null && borders[3] == null)) {
+ painter.clipBackground(new Rectangle(x, y, width, height),
+ borders[0], borders[1], borders[2], borders[3]);
+ }
painter.clipRect(new Rectangle(x, y, width, height));
}
} catch (PropertyException pe) {
throw new IFException("Error parsing the fill attribute", pe);
}
- painter.fillRect(new Rectangle(x, y, width, height), fillColor);
+
+ Rectangle rectangularArea = new Rectangle(x, y, width, height);
+
+ //TODO should rect be overloaded to include rounded corners
+ // or should we introduce a new IF element?
+ BorderProps[] borders = new BorderProps[4];
+ for (int i = 0; i < 4; i++) {
+ String b = attributes.getValue(SIDES[i]);
+ if (b != null) {
+ borders[i] = BorderProps.valueOf(userAgent, b);
+ }
+ }
+
+ if (!(borders[0] == null && borders[1] == null
+ && borders[2] == null && borders[3] == null)) {
+ painter.clipBackground(rectangularArea,
+ borders[0], borders[1], borders[2], borders[3]);
+ }
+
+ painter.fillRect(rectangularArea , fillColor);
}
}
/** {@inheritDoc} */
public void clipBackground(Rectangle rect, BorderProps bpsBefore, BorderProps bpsAfter,
BorderProps bpsStart, BorderProps bpsEnd) throws IFException {
- // TODO Auto-generated method stub
+ try {
+ AttributesImpl atts = new AttributesImpl();
+ addAttribute(atts, "x", Integer.toString(rect.x));
+ addAttribute(atts, "y", Integer.toString(rect.y));
+ addAttribute(atts, "width", Integer.toString(rect.width));
+ addAttribute(atts, "height", Integer.toString(rect.height));
+ if (hasRoundedCorners(bpsBefore, bpsAfter, bpsStart, bpsEnd)) {
+ if (bpsBefore != null) {
+ addAttribute(atts, "before", bpsBefore.toString());
+ }
+ if (bpsAfter != null) {
+ addAttribute(atts, "after", bpsAfter.toString());
+ }
+ if (bpsStart != null) {
+ addAttribute(atts, "start", bpsStart.toString());
+ }
+ if (bpsEnd != null) {
+ addAttribute(atts, "end", bpsEnd.toString());
+ }
+ }
+ handler.element(EL_CLIP_RECT, atts);
+ } catch (SAXException e) {
+ throw new IFException("SAX error in clipRect()", e);
+ }
}
}
}
+ //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 {
}
}
+ /** {@inheritDoc} */
+ public void fillBackground(Rectangle rect, Paint fill, BorderProps bpsBefore,
+ BorderProps bpsAfter, BorderProps bpsStart, BorderProps bpsEnd) throws IFException {
+ // Not supported in SVG
+
+ }
+
}