1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 /* $Id: AFPBorderPainter.java 1802793 2017-07-24 11:49:40Z ssteiner $ */
19 
20 package org.apache.fop.afp;
21 
22 import java.awt.geom.AffineTransform;
23 
24 import org.apache.fop.fo.Constants;
25 import org.apache.fop.render.intermediate.BorderPainter;
26 import org.apache.fop.util.ColorUtil;
27 
28 /**
29  * Handles the drawing of borders/lines in AFP
30  */
31 public class AFPBorderPainter extends AbstractAFPPainter {
32 
33     /**
34      * Main constructor
35      *
36      * @param paintingState the AFP painting state converter
37      * @param dataStream the AFP datastream
38      */
AFPBorderPainter(AFPPaintingState paintingState, DataStream dataStream)39     public AFPBorderPainter(AFPPaintingState paintingState, DataStream dataStream) {
40         super(paintingState, dataStream);
41     }
42 
43     /** {@inheritDoc} */
paint(PaintingInfo paintInfo)44     public void paint(PaintingInfo paintInfo) {
45         Integer bytesAvailable = dataStream.getCurrentPage().getPresentationTextObject().getBytesAvailable();
46         if (bytesAvailable != null && bytesAvailable < 1024) {
47             dataStream.getCurrentPage().endPresentationObject();
48         }
49 
50         BorderPaintingInfo borderPaintInfo = (BorderPaintingInfo)paintInfo;
51         float w = borderPaintInfo.getX2() - borderPaintInfo.getX1();
52         float h = borderPaintInfo.getY2() - borderPaintInfo.getY1();
53         if ((w < 0) || (h < 0)) {
54             log.error("Negative extent received. Border won't be painted.");
55             return;
56         }
57 
58         int pageWidth = dataStream.getCurrentPage().getWidth();
59         int pageHeight = dataStream.getCurrentPage().getHeight();
60         AFPUnitConverter unitConv = paintingState.getUnitConverter();
61         AffineTransform at = paintingState.getData().getTransform();
62 
63         float x1 = unitConv.pt2units(borderPaintInfo.getX1());
64         float y1 = unitConv.pt2units(borderPaintInfo.getY1());
65         float x2 = unitConv.pt2units(borderPaintInfo.getX2());
66         float y2 = unitConv.pt2units(borderPaintInfo.getY2());
67 
68         switch (paintingState.getRotation()) {
69         case 90:
70             x1 += at.getTranslateY();
71             y1 += (float) (pageWidth - at.getTranslateX());
72             x2 += at.getTranslateY();
73             y2 += (float) (pageWidth - at.getTranslateX());
74             break;
75         case 180:
76             x1 += (float) (pageWidth - at.getTranslateX());
77             y1 += (float) (pageHeight - at.getTranslateY());
78             x2 += (float) (pageWidth - at.getTranslateX());
79             y2 += (float) (pageHeight - at.getTranslateY());
80             break;
81         case 270:
82             x1 = (float) (pageHeight - at.getTranslateY());
83             y1 += (float) at.getTranslateX();
84             x2 += x1;
85             y2 += (float) at.getTranslateX();
86             break;
87         case 0:
88         default:
89             x1 += at.getTranslateX();
90             y1 += at.getTranslateY();
91             x2 += at.getTranslateX();
92             y2 += at.getTranslateY();
93             break;
94         }
95 
96         AFPLineDataInfo lineDataInfo = new AFPLineDataInfo();
97         lineDataInfo.setColor(borderPaintInfo.getColor());
98         lineDataInfo.setRotation(paintingState.getRotation());
99         lineDataInfo.setX1(Math.round(x1));
100         lineDataInfo.setY1(Math.round(y1));
101         float thickness;
102         if (borderPaintInfo.isHorizontal()) {
103             thickness = y2 - y1;
104         } else {
105             thickness = x2 - x1;
106         }
107         lineDataInfo.setThickness(Math.round(thickness));
108 
109         // handle border-*-style
110         switch (borderPaintInfo.getStyle()) {
111         case Constants.EN_DOUBLE:
112             int thickness3 = (int)Math.floor(thickness / 3f);
113             lineDataInfo.setThickness(thickness3);
114             if (borderPaintInfo.isHorizontal()) {
115                 lineDataInfo.setX2(Math.round(x2));
116                 lineDataInfo.setY2(lineDataInfo.getY1());
117                 dataStream.createLine(lineDataInfo);
118                 int distance = thickness3 * 2;
119                 lineDataInfo = new AFPLineDataInfo(lineDataInfo);
120                 lineDataInfo.setY1(lineDataInfo.getY1() + distance);
121                 lineDataInfo.setY2(lineDataInfo.getY2() + distance);
122                 dataStream.createLine(lineDataInfo);
123             } else {
124                 lineDataInfo.setX2(lineDataInfo.getX1());
125                 lineDataInfo.setY2(Math.round(y2));
126                 dataStream.createLine(lineDataInfo);
127                 int distance = thickness3 * 2;
128                 lineDataInfo = new AFPLineDataInfo(lineDataInfo);
129                 lineDataInfo.setX1(lineDataInfo.getX1() + distance);
130                 lineDataInfo.setX2(lineDataInfo.getX2() + distance);
131                 dataStream.createLine(lineDataInfo);
132             }
133             break;
134         case Constants.EN_DASHED:
135             if (borderPaintInfo.isHorizontal()) {
136                 int dashWidth = (int) unitConv.pt2units(BorderPainter.dashWidthCalculator(w, h));
137                 lineDataInfo.setX2(lineDataInfo.getX1() + dashWidth);
138                 lineDataInfo.setY2(lineDataInfo.getY1());
139                 int ex2 = Math.round(x2);
140                 int spaceWidth = (int) (BorderPainter.DASHED_BORDER_SPACE_RATIO * dashWidth);
141                 while (lineDataInfo.getX2() <= ex2 && dashWidth > 0) {
142                     dataStream.createLine(lineDataInfo);
143                     lineDataInfo.setX1(lineDataInfo.getX2() + spaceWidth);
144                     lineDataInfo.setX2(lineDataInfo.getX1() + dashWidth);
145                 }
146             } else {
147                 int dashWidth = (int) unitConv.pt2units(BorderPainter.dashWidthCalculator(h, w));
148                 lineDataInfo.setX2(lineDataInfo.getX1());
149                 lineDataInfo.setY2(lineDataInfo.getY1() + dashWidth);
150                 int ey2 = Math.round(y2);
151                 int spaceWidth = (int) (BorderPainter.DASHED_BORDER_SPACE_RATIO * dashWidth);
152                 while (lineDataInfo.getY2() <= ey2 && dashWidth > 0) {
153                     dataStream.createLine(lineDataInfo);
154                     lineDataInfo.setY1(lineDataInfo.getY2() + spaceWidth);
155                     lineDataInfo.setY2(lineDataInfo.getY1() + dashWidth);
156                 }
157             }
158             break;
159         case Constants.EN_DOTTED:
160             if (borderPaintInfo.isHorizontal()) {
161                 lineDataInfo.setX2(lineDataInfo.getX1() + lineDataInfo.getThickness());
162                 lineDataInfo.setY2(lineDataInfo.getY1());
163                 int ex2 = Math.round(x2);
164                 while (lineDataInfo.getX1() + lineDataInfo.getThickness() < ex2) {
165                     dataStream.createLine(lineDataInfo);
166                     lineDataInfo.setX1(lineDataInfo.getX1() + 3 * lineDataInfo.getThickness());
167                     lineDataInfo.setX2(lineDataInfo.getX1() + lineDataInfo.getThickness());
168                 }
169             } else {
170                 lineDataInfo.setX2(lineDataInfo.getX1());
171                 lineDataInfo.setY2(lineDataInfo.getY1() + lineDataInfo.getThickness());
172                 int ey2 = Math.round(y2);
173                 while (lineDataInfo.getY1() + lineDataInfo.getThickness() < ey2) {
174                     dataStream.createLine(lineDataInfo);
175                     lineDataInfo.setY1(lineDataInfo.getY1() + 3 * lineDataInfo.getThickness());
176                     lineDataInfo.setY2(lineDataInfo.getY1() + lineDataInfo.getThickness());
177                 }
178             }
179             break;
180         case Constants.EN_GROOVE:
181         case Constants.EN_RIDGE:
182             //TODO
183             int yNew;
184             lineDataInfo.setX2(Math.round(x2));
185             float colFactor = (borderPaintInfo.getStyle() == Constants.EN_GROOVE ? 0.4f : -0.4f);
186             float h3 = (y2 - y1) / 3;
187             lineDataInfo.setColor(
188                 ColorUtil.lightenColor(borderPaintInfo.getColor(), -colFactor));
189             lineDataInfo.setThickness(Math.round(h3));
190             yNew = Math.round(y1);
191             lineDataInfo.setY1(yNew);
192             lineDataInfo.setY2(yNew);
193             dataStream.createLine(lineDataInfo);
194             lineDataInfo.setColor(borderPaintInfo.getColor());
195             yNew = Math.round(y1 + h3);
196             lineDataInfo.setY1(yNew);
197             lineDataInfo.setY2(yNew);
198             dataStream.createLine(lineDataInfo);
199             lineDataInfo.setColor(ColorUtil.lightenColor(borderPaintInfo.getColor(), colFactor));
200             yNew = Math.round(y1 + h3 + h3);
201             lineDataInfo.setY1(yNew);
202             lineDataInfo.setY2(yNew);
203             dataStream.createLine(lineDataInfo);
204             break;
205         case Constants.EN_HIDDEN:
206             break;
207         case Constants.EN_INSET:
208         case Constants.EN_OUTSET:
209         case Constants.EN_SOLID:
210         default:
211             if (borderPaintInfo.isHorizontal()) {
212                 lineDataInfo.setX2(Math.round(x2));
213                 lineDataInfo.setY2(lineDataInfo.getY1());
214             } else {
215                 lineDataInfo.setX2(lineDataInfo.getX1());
216                 lineDataInfo.setY2(Math.round(y2));
217             }
218             dataStream.createLine(lineDataInfo);
219         }
220     }
221 
222 }
223