| /* |
| * 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 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 |
| */ |
| public void drawBorders(Rectangle borderRect, // CSOK: MethodLength |
| BorderProps bpsTop, BorderProps bpsBottom, |
| BorderProps bpsLeft, BorderProps bpsRight) throws IOException { |
| int startx = borderRect.x; |
| int starty = borderRect.y; |
| int width = borderRect.width; |
| int height = borderRect.height; |
| boolean[] b = new boolean[] { |
| (bpsTop != null), (bpsRight != null), |
| (bpsBottom != null), (bpsLeft != null)}; |
| if (!b[0] && !b[1] && !b[2] && !b[3]) { |
| return; |
| } |
| int[] bw = new int[] { |
| (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(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[3] && b[0]), (b[0] && b[1]), (b[1] && b[2]), (b[2] && b[3])}; |
| if (bpsTop != null) { |
| int sx1 = startx; |
| int sx2 = (slant[0] ? sx1 + bw[3] - clipw[3] : sx1); |
| int 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 (bpsTop.mode == BorderProps.COLLAPSE_OUTER) { |
| if (bpsLeft != null && bpsLeft.mode == BorderProps.COLLAPSE_OUTER) { |
| sx1a -= clipw[3]; |
| } |
| if (bpsRight != null && bpsRight.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, |
| bpsTop.style, bpsTop.color); |
| restoreGraphicsState(); |
| } |
| if (bpsRight != 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 (bpsRight.mode == BorderProps.COLLAPSE_OUTER) { |
| if (bpsTop != null && bpsTop.mode == BorderProps.COLLAPSE_OUTER) { |
| sy1a -= clipw[0]; |
| } |
| if (bpsBottom != null && bpsBottom.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, |
| bpsRight.style, bpsRight.color); |
| restoreGraphicsState(); |
| } |
| if (bpsBottom != 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 (bpsBottom.mode == BorderProps.COLLAPSE_OUTER) { |
| if (bpsLeft != null && bpsLeft.mode == BorderProps.COLLAPSE_OUTER) { |
| sx1a -= clipw[3]; |
| } |
| if (bpsRight != null && bpsRight.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, |
| bpsBottom.style, bpsBottom.color); |
| restoreGraphicsState(); |
| } |
| if (bpsLeft != 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 (bpsLeft.mode == BorderProps.COLLAPSE_OUTER) { |
| if (bpsTop != null && bpsTop.mode == BorderProps.COLLAPSE_OUTER) { |
| sy1a -= clipw[0]; |
| } |
| if (bpsBottom != null && bpsBottom.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, bpsLeft.style, bpsLeft.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; |
| |
| } |