blob: 20402369ad3e974a1ca4fa4b97f00e6676cbe18c [file] [log] [blame]
/*
* 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.intermediate;
import java.awt.Color;
import java.awt.Point;
import java.awt.Rectangle;
import java.io.IOException;
import org.apache.fop.traits.BorderProps;
import org.apache.fop.traits.RuleStyle;
/**
* This is an abstract base class for handling border painting.
*/
public abstract class BorderPainter {
/**
* 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
* @throws IOException if an I/O error occurs while creating the borders
*/
public void drawBorders(Rectangle borderRect, // CSOK: MethodLength
BorderProps bpsBefore, BorderProps bpsAfter,
BorderProps bpsStart, BorderProps bpsEnd) throws IOException {
int startx = borderRect.x;
int starty = borderRect.y;
int width = borderRect.width;
int height = borderRect.height;
boolean[] b = new boolean[] {
(bpsBefore != null), (bpsEnd != null),
(bpsAfter != null), (bpsStart != null)};
if (!b[0] && !b[1] && !b[2] && !b[3]) {
return;
}
int[] bw = new int[] {
(b[0] ? bpsBefore.width : 0),
(b[1] ? bpsEnd.width : 0),
(b[2] ? bpsAfter.width : 0),
(b[3] ? bpsStart.width : 0)};
int[] clipw = new int[] {
BorderProps.getClippedWidth(bpsBefore),
BorderProps.getClippedWidth(bpsEnd),
BorderProps.getClippedWidth(bpsAfter),
BorderProps.getClippedWidth(bpsStart)};
starty += clipw[0];
height -= clipw[0];
height -= clipw[2];
startx += clipw[3];
width -= clipw[3];
width -= clipw[1];
boolean[] slant = new boolean[] {
(b[3] && b[0]), (b[0] && b[1]), (b[1] && b[2]), (b[2] && b[3])};
if (bpsBefore != null) {
int sx1 = startx;
int sx2 = (slant[0] ? sx1 + bw[3] - clipw[3] : sx1);
int ex1 = startx + width;
int ex2 = (slant[1] ? ex1 - bw[1] + clipw[1] : ex1);
int outery = starty - clipw[0];
int clipy = outery + clipw[0];
int innery = outery + bw[0];
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[3];
}
if (bpsEnd != null && bpsEnd.mode == BorderProps.COLLAPSE_OUTER) {
ex1a += clipw[1];
}
lineTo(sx1a, outery);
lineTo(ex1a, outery);
}
lineTo(ex1, clipy);
lineTo(ex2, innery);
lineTo(sx2, innery);
closePath();
clip();
drawBorderLine(sx1a, outery, ex1a, innery, true, true,
bpsBefore.style, bpsBefore.color);
restoreGraphicsState();
}
if (bpsEnd != null) {
int sy1 = starty;
int sy2 = (slant[1] ? sy1 + bw[0] - clipw[0] : sy1);
int ey1 = starty + height;
int ey2 = (slant[2] ? ey1 - bw[2] + clipw[2] : ey1);
int outerx = startx + width + clipw[1];
int clipx = outerx - clipw[1];
int innerx = outerx - bw[1];
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[0];
}
if (bpsAfter != null && bpsAfter.mode == BorderProps.COLLAPSE_OUTER) {
ey1a += clipw[2];
}
lineTo(outerx, sy1a);
lineTo(outerx, ey1a);
}
lineTo(clipx, ey1);
lineTo(innerx, ey2);
lineTo(innerx, sy2);
closePath();
clip();
drawBorderLine(innerx, sy1a, outerx, ey1a, false, false, bpsEnd.style, bpsEnd.color);
restoreGraphicsState();
}
if (bpsAfter != null) {
int sx1 = startx;
int sx2 = (slant[3] ? sx1 + bw[3] - clipw[3] : sx1);
int ex1 = startx + width;
int ex2 = (slant[2] ? ex1 - bw[1] + clipw[1] : ex1);
int outery = starty + height + clipw[2];
int clipy = outery - clipw[2];
int innery = outery - bw[2];
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[3];
}
if (bpsEnd != null && bpsEnd.mode == BorderProps.COLLAPSE_OUTER) {
ex1a += clipw[1];
}
lineTo(ex1a, outery);
lineTo(sx1a, outery);
}
lineTo(sx1, clipy);
lineTo(sx2, innery);
lineTo(ex2, innery);
closePath();
clip();
drawBorderLine(sx1a, innery, ex1a, outery, true, false, bpsAfter.style, bpsAfter.color);
restoreGraphicsState();
}
if (bpsStart != null) {
int sy1 = starty;
int sy2 = (slant[0] ? sy1 + bw[0] - clipw[0] : sy1);
int ey1 = sy1 + height;
int ey2 = (slant[3] ? ey1 - bw[2] + clipw[2] : ey1);
int outerx = startx - clipw[3];
int clipx = outerx + clipw[3];
int innerx = outerx + bw[3];
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[0];
}
if (bpsAfter != null && bpsAfter.mode == BorderProps.COLLAPSE_OUTER) {
ey1a += clipw[2];
}
lineTo(outerx, ey1a);
lineTo(outerx, sy1a);
}
lineTo(clipx, sy1);
lineTo(innerx, sy2);
lineTo(innerx, ey2);
closePath();
clip();
drawBorderLine(outerx, sy1a, innerx, ey1a, false, true, bpsStart.style, bpsStart.color);
restoreGraphicsState();
}
}
/**
* Draws a border line.
* @param x1 X coordinate of the upper left corner
* of the line's bounding rectangle (in millipoints)
* @param y1 start Y coordinate of the upper left corner
* of the line's bounding rectangle (in millipoints)
* @param x2 end X coordinate of the lower right corner
* of the line's bounding rectangle (in millipoints)
* @param y2 end y coordinate of the lower right corner
* of the line's bounding rectangle (in millipoints)
* @param horz true if it is a horizontal line
* @param startOrBefore true if the line is the start or end edge of a border box
* @param style the border style
* @param color the border color
* @throws IOException if an I/O error occurs
*/
protected abstract void drawBorderLine( // CSOK: ParameterNumber
int x1, int y1, int x2, int y2,
boolean horz, boolean startOrBefore, int style, Color color) throws IOException;
/**
* Draws a line/rule.
* @param start start point (coordinates in millipoints)
* @param end end point (coordinates in millipoints)
* @param width width of the line
* @param color the line color
* @param style the rule style
* @throws IOException if an I/O error occurs
*/
public abstract void drawLine(Point start, Point end,
int width, Color color, RuleStyle style) throws IOException;
/**
* Moves the cursor to the given coordinate.
* @param x the X coordinate (in millipoints)
* @param y the Y coordinate (in millipoints)
* @throws IOException if an I/O error occurs
*/
protected abstract void moveTo(int x, int y) throws IOException;
/**
* Draws a line from the current cursor position to the given coordinates.
* @param x the X coordinate (in millipoints)
* @param y the Y coordinate (in millipoints)
* @throws IOException if an I/O error occurs
*/
protected abstract void lineTo(int x, int y) throws IOException;
/**
* Closes the current path.
* @throws IOException if an I/O error occurs
*/
protected abstract void closePath() throws IOException;
/**
* Reduces the current clipping region to the current path.
* @throws IOException if an I/O error occurs
*/
protected abstract void clip() throws IOException;
/**
* Save the graphics state on the stack.
* @throws IOException if an I/O error occurs
*/
protected abstract void saveGraphicsState() throws IOException;
/**
* Restore the last graphics state from the stack.
* @throws IOException if an I/O error occurs
*/
protected abstract void restoreGraphicsState() throws IOException;
}