Skip to content

Commit cf5430a

Browse files
committed
Support different border-radiuses. Some changes in border's abstraction concept.
DEVSIX-1569
1 parent a09e27f commit cf5430a

19 files changed

+836
-360
lines changed

io/src/main/java/com/itextpdf/io/LogMessageConstant.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ public final class LogMessageConstant {
8989
public static final String INVALID_KEY_VALUE_KEY_0_HAS_NULL_VALUE = "Invalid key value: key {0} has null value.";
9090
public static final String LAST_ROW_IS_NOT_COMPLETE = "Last row is not completed. Table bottom border may collapse as you do not expect it";
9191
public static final String MAKE_COPY_OF_CATALOG_DICTIONARY_IS_FORBIDDEN = "Make copy of Catalog dictionary is forbidden.";
92+
public static final String METHOD_IS_NOT_IMPLEMENTED_BY_DEFAULT_OTHER_METHOD_WILL_BE_USED = "Method {0} is not implemented by default: please, override and implement it. {1} will be used instead.";
9293
public static final String NAME_ALREADY_EXISTS_IN_THE_NAME_TREE = "Name \"{0}\" already exists in the name tree; old value will be replaced by the new one.";
9394
public static final String NOT_TAGGED_PAGES_IN_TAGGED_DOCUMENT = "Not tagged pages are copied to the tagged document. Destination document now may contain not tagged content.";
9495
public static final String NO_FIELDS_IN_ACROFORM = "Required AcroForm entry /Fields does not exist in the document. Empty array /Fields will be created.";

layout/src/main/java/com/itextpdf/layout/ElementPropertyContainer.java

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ This file is part of the iText (R) project.
5252
import com.itextpdf.layout.layout.LayoutPosition;
5353
import com.itextpdf.layout.property.Background;
5454
import com.itextpdf.layout.property.BaseDirection;
55+
import com.itextpdf.layout.property.BorderRadius;
5556
import com.itextpdf.layout.property.FontKerning;
5657
import com.itextpdf.layout.property.HorizontalAlignment;
5758
import com.itextpdf.layout.property.Property;
@@ -534,6 +535,61 @@ public T setBorderLeft(Border border) {
534535
return (T) (Object) this;
535536
}
536537

538+
/**
539+
* Sets a border radius for all four edges of this Element.
540+
*
541+
* @param borderRadius a customized {@link BorderRadius}
542+
* @return this Element.
543+
*/
544+
public T setBorderRadius(BorderRadius borderRadius) {
545+
setProperty(Property.BORDER_RADIUS, borderRadius);
546+
return (T) (Object) this;
547+
}
548+
549+
/**
550+
* Sets a border radius for the bottom left corner of this Element.
551+
*
552+
* @param borderRadius a customized {@link BorderRadius}
553+
* @return this Element.
554+
*/
555+
public T setBorderBottomLeftRadius(BorderRadius borderRadius) {
556+
setProperty(Property.BORDER_BOTTOM_LEFT_RADIUS, borderRadius);
557+
return (T) (Object) this;
558+
}
559+
560+
/**
561+
* Sets a border radius for the bottom right corner of this Element.
562+
*
563+
* @param borderRadius a customized {@link BorderRadius}
564+
* @return this Element.
565+
*/
566+
public T setBorderBottomRightRadius(BorderRadius borderRadius) {
567+
setProperty(Property.BORDER_BOTTOM_RIGHT_RADIUS, borderRadius);
568+
return (T) (Object) this;
569+
}
570+
571+
/**
572+
* Sets a border radius for the top left corner of this Element.
573+
*
574+
* @param borderRadius a customized {@link BorderRadius}
575+
* @return this Element.
576+
*/
577+
public T setBorderTopLeftRadius(BorderRadius borderRadius) {
578+
setProperty(Property.BORDER_TOP_LEFT_RADIUS, borderRadius);
579+
return (T) (Object) this;
580+
}
581+
582+
/**
583+
* Sets a border radius for the top right corner of this Element.
584+
*
585+
* @param borderRadius a customized {@link BorderRadius}
586+
* @return this Element.
587+
*/
588+
public T setBorderTopRightRadius(BorderRadius borderRadius) {
589+
setProperty(Property.BORDER_TOP_RIGHT_RADIUS, borderRadius);
590+
return (T) (Object) this;
591+
}
592+
537593
/**
538594
* Sets a rule for splitting strings when they don't fit into one line.
539595
* The default implementation is {@link com.itextpdf.layout.splitting.DefaultSplitCharacters}

layout/src/main/java/com/itextpdf/layout/border/Border.java

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,13 @@ This file is part of the iText (R) project.
4545

4646
import com.itextpdf.kernel.color.Color;
4747
import com.itextpdf.kernel.color.ColorConstants;
48+
import com.itextpdf.io.LogMessageConstant;
49+
import com.itextpdf.io.util.MessageFormatUtil;
4850
import com.itextpdf.kernel.geom.Point;
4951
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
5052
import com.itextpdf.layout.property.TransparentColor;
53+
import org.slf4j.Logger;
54+
import org.slf4j.LoggerFactory;
5155

5256
/**
5357
* Represents a border.
@@ -260,18 +264,65 @@ public void draw(PdfCanvas canvas, float x1, float y1, float x2, float y2, Side
260264
* <code>borderWidthAfter</code> - width of the left border. Those width are used to handle areas
261265
* of border joins.
262266
* </p>
267+
* <p>
268+
* <code>borderRadius</code> is used to draw rounded borders.
269+
* </p>
263270
*
264271
* @param canvas PdfCanvas to be written to
265272
* @param x1 x coordinate of the beginning point of the element side, that should be bordered
266273
* @param y1 y coordinate of the beginning point of the element side, that should be bordered
267274
* @param x2 x coordinate of the ending point of the element side, that should be bordered
268275
* @param y2 y coordinate of the ending point of the element side, that should be bordered
269-
* @param borderRadius border radius
270-
* @param side the {@link Border.Side}, that represents element side, that should be bordered
276+
* @param borderRadius defines the radius of the element's corners
277+
* @param defaultSide the {@link Border.Side}, that we will fallback to, if it cannot be determined by border coordinates
271278
* @param borderWidthBefore defines width of the border that is before the current one
272279
* @param borderWidthAfter defines width of the border that is after the current one
273280
*/
274-
public abstract void draw(PdfCanvas canvas, float x1, float y1, float x2, float y2, float borderRadius, Side side, float borderWidthBefore, float borderWidthAfter);
281+
public void draw(PdfCanvas canvas, float x1, float y1, float x2, float y2, float borderRadius, Side defaultSide, float borderWidthBefore, float borderWidthAfter) {
282+
draw(canvas, x1, y1, x2, y2, borderRadius, borderRadius, borderRadius, borderRadius, defaultSide, borderWidthBefore, borderWidthAfter);
283+
}
284+
285+
/**
286+
* <p>
287+
* All borders are supposed to be drawn in such way, that inner content of the element is on the right from the
288+
* drawing direction. Borders are drawn in this order: top, right, bottom, left.
289+
* </p>
290+
* <p>
291+
* Given points specify the line which lies on the border of the content area,
292+
* therefore the border itself should be drawn to the left from the drawing direction.
293+
* </p>
294+
* <p>
295+
* <code>borderWidthBefore</code> and <code>borderWidthAfter</code> parameters are used to
296+
* define the widths of the borders that are before and after the current border, e.g. for
297+
* the bottom border, <code>borderWidthBefore</code> specifies width of the right border and
298+
* <code>borderWidthAfter</code> - width of the left border. Those width are used to handle areas
299+
* of border joins.
300+
* </p>
301+
* <p>
302+
* <code>horizontalRadius1</code>, <code>verticalRadius1</code>, <code>horizontalRadius2</code>
303+
* and <code>verticalRadius2</code> are used to draw rounded borders.
304+
* </p>
305+
*
306+
* @param canvas PdfCanvas to be written to
307+
* @param x1 x coordinate of the beginning point of the element side, that should be bordered
308+
* @param y1 y coordinate of the beginning point of the element side, that should be bordered
309+
* @param x2 x coordinate of the ending point of the element side, that should be bordered
310+
* @param y2 y coordinate of the ending point of the element side, that should be bordered
311+
* @param horizontalRadius1 defines the horizontal radius of the border's first corner
312+
* @param verticalRadius1 defines the vertical radius of the border's first corner
313+
* @param horizontalRadius2 defines the horizontal radius of the border's second corner
314+
* @param verticalRadius2 defines the vertical radius of the border's second corner
315+
* @param defaultSide the {@link Border.Side}, that we will fallback to, if it cannot be determined by border coordinates
316+
* @param borderWidthBefore defines width of the border that is before the current one
317+
* @param borderWidthAfter defines width of the border that is after the current one
318+
*/
319+
public void draw(PdfCanvas canvas, float x1, float y1, float x2, float y2, float horizontalRadius1, float verticalRadius1, float horizontalRadius2, float verticalRadius2, Side defaultSide, float borderWidthBefore, float borderWidthAfter) {
320+
Logger logger = LoggerFactory.getLogger(Border.class);
321+
logger.warn(MessageFormatUtil.format(LogMessageConstant.METHOD_IS_NOT_IMPLEMENTED_BY_DEFAULT_OTHER_METHOD_WILL_BE_USED,
322+
"Border#draw(PdfCanvas, float, float, float, float, float, float, float, float, Side, float, float",
323+
"Border#draw(PdfCanvas, float, float, float, float, Side, float, float)"));
324+
draw(canvas, x1, y1, x2, y2, defaultSide, borderWidthBefore, borderWidthAfter);
325+
}
275326

276327
/**
277328
* Draws the border of a cell.
@@ -320,6 +371,7 @@ public float getWidth() {
320371

321372
/**
322373
* Sets the {@link Color color} of the {@link Border border}
374+
*
323375
* @param color The color
324376
*/
325377
public void setColor(Color color) {
@@ -329,6 +381,7 @@ public void setColor(Color color) {
329381

330382
/**
331383
* Sets the width of the {@link Border border}
384+
*
332385
* @param width The width
333386
*/
334387
public void setWidth(float width) {

layout/src/main/java/com/itextpdf/layout/border/Border3D.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -206,11 +206,6 @@ public void draw(PdfCanvas canvas, float x1, float y1, float x2, float y2, float
206206
canvas.restoreState();
207207
}
208208

209-
@Override
210-
public void draw(PdfCanvas canvas, float x1, float y1, float x2, float y2, float borderRadius, Side side, float borderWidthBefore, float borderWidthAfter) {
211-
draw(canvas, x1, y1, x2, y2, borderWidthBefore, borderWidthAfter);
212-
}
213-
214209
/**
215210
* {@inheritDoc}
216211
*/

layout/src/main/java/com/itextpdf/layout/border/DashedBorder.java

Lines changed: 47 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ public void drawCellBorder(PdfCanvas canvas, float x1, float y1, float x2, float
179179
}
180180

181181
@Override
182-
public void draw(PdfCanvas canvas, float x1, float y1, float x2, float y2, float outerRadius, Side side, float borderWidthBefore, float borderWidthAfter) {
182+
public void draw(PdfCanvas canvas, float x1, float y1, float x2, float y2, float horizontalRadius1, float verticalRadius1, float horizontalRadius2, float verticalRadius2, Side defaultSide, float borderWidthBefore, float borderWidthAfter) {
183183
float curv = 0.447f;
184184
float initialGap = width * GAP_MODIFIER;
185185
float dash = width * DASH_MODIFIER;
@@ -194,10 +194,10 @@ public void draw(PdfCanvas canvas, float x1, float y1, float x2, float y2, float
194194
// Points (x0, y0) and (x3, y3) are used to produce Bezier curve
195195
float x0 = x1, y0 = y1,
196196
x3 = x2, y3 = y2;
197-
198-
float innerRadiusBefore = Math.max(0, outerRadius - borderWidthBefore),
199-
innerRadius = Math.max(0, outerRadius - width),
200-
innerRadiusAfter = Math.max(0, outerRadius - borderWidthAfter);
197+
float innerRadiusBefore,
198+
innerRadiusFirst,
199+
innerRadiusSecond,
200+
innerRadiusAfter;
201201

202202
float widthHalf = width / 2;
203203

@@ -209,14 +209,21 @@ public void draw(PdfCanvas canvas, float x1, float y1, float x2, float y2, float
209209
canvas.setLineDash(dash, adjustedGap, dash + adjustedGap / 2);
210210

211211
Point clipPoint1, clipPoint2, clipPoint;
212-
Border.Side borderSide = getBorderSide(x1, y1, x2, y2, side);
212+
Border.Side borderSide = getBorderSide(x1, y1, x2, y2, defaultSide);
213213
switch (borderSide) {
214214
case TOP:
215+
216+
innerRadiusBefore = Math.max(0, horizontalRadius1 - borderWidthBefore);
217+
innerRadiusFirst = Math.max(0, verticalRadius1 - width);
218+
innerRadiusSecond = Math.max(0, verticalRadius2 - width);
219+
innerRadiusAfter = Math.max(0, horizontalRadius2 - borderWidthAfter);
220+
221+
215222
x0 -= borderWidthBefore / 2;
216-
y0 -= innerRadius;
223+
y0 -= innerRadiusFirst;
217224

218225
x3 += borderWidthAfter / 2;
219-
y3 -= innerRadius;
226+
y3 -= innerRadiusSecond;
220227

221228
clipPoint1 = getIntersectionPoint(new Point(x1 - borderWidthBefore, y1 + width), new Point(x1, y1), new Point(x0, y0), new Point(x0 + 10, y0));
222229
clipPoint2 = getIntersectionPoint(new Point(x2 + borderWidthAfter, y2 + width), new Point(x2, y2), new Point(x3, y3), new Point(x3 - 10, y3));
@@ -235,15 +242,20 @@ public void draw(PdfCanvas canvas, float x1, float y1, float x2, float y2, float
235242
y2 += widthHalf;
236243

237244
canvas
238-
.moveTo(x0, y0).curveTo(x0, y0 + innerRadius * curv, x1 - innerRadiusBefore * curv, y1, x1, y1)
245+
.moveTo(x0, y0).curveTo(x0, y0 + innerRadiusFirst * curv, x1 - innerRadiusBefore * curv, y1, x1, y1)
239246
.lineTo(x2, y2)
240-
.curveTo(x2 + innerRadiusAfter * curv, y2, x3, y3 + innerRadius * curv, x3, y3);
247+
.curveTo(x2 + innerRadiusAfter * curv, y2, x3, y3 + innerRadiusSecond * curv, x3, y3);
241248
break;
242249
case RIGHT:
243-
x0 -= innerRadius;
250+
innerRadiusBefore = Math.max(0, verticalRadius1 - borderWidthBefore);
251+
innerRadiusFirst = Math.max(0, horizontalRadius1 - width);
252+
innerRadiusSecond = Math.max(0, horizontalRadius2 - width);
253+
innerRadiusAfter = Math.max(0, verticalRadius2 - borderWidthAfter);
254+
255+
x0 -= innerRadiusFirst;
244256
y0 += borderWidthBefore / 2;
245257

246-
x3 -= innerRadius;
258+
x3 -= innerRadiusSecond;
247259
y3 -= borderWidthAfter;
248260

249261
clipPoint1 = getIntersectionPoint(new Point(x1 + width, y1 + borderWidthBefore), new Point(x1, y1), new Point(x0, y0), new Point(x0, y0 - 10));
@@ -263,17 +275,22 @@ public void draw(PdfCanvas canvas, float x1, float y1, float x2, float y2, float
263275
y2 += innerRadiusAfter;
264276

265277
canvas
266-
.moveTo(x0, y0).curveTo(x0 + innerRadius * curv, y0, x1, y1 + innerRadiusBefore * curv, x1, y1)
278+
.moveTo(x0, y0).curveTo(x0 + innerRadiusFirst * curv, y0, x1, y1 + innerRadiusBefore * curv, x1, y1)
267279
.lineTo(x2, y2)
268-
.curveTo(x2, y2 - innerRadiusAfter * curv, x3 + innerRadius * curv, y3, x3, y3);
280+
.curveTo(x2, y2 - innerRadiusAfter * curv, x3 + innerRadiusSecond * curv, y3, x3, y3);
269281

270282
break;
271283
case BOTTOM:
284+
innerRadiusBefore = Math.max(0, horizontalRadius1 - borderWidthBefore);
285+
innerRadiusFirst = Math.max(0, verticalRadius1 - width);
286+
innerRadiusSecond = Math.max(0, verticalRadius2 - width);
287+
innerRadiusAfter = Math.max(0, horizontalRadius2 - borderWidthAfter);
288+
272289
x0 += borderWidthBefore / 2;
273-
y0 += innerRadius;
290+
y0 += innerRadiusFirst;
274291

275292
x3 -= borderWidthAfter / 2;
276-
y3 += innerRadius;
293+
y3 += innerRadiusSecond;
277294

278295
clipPoint1 = getIntersectionPoint(new Point(x1 + borderWidthBefore, y1 - width), new Point(x1, y1), new Point(x0, y0), new Point(x0 - 10, y0));
279296
clipPoint2 = getIntersectionPoint(new Point(x2 - borderWidthAfter, y2 - width), new Point(x2, y2), new Point(x3, y3), new Point(x3 + 10, y3));
@@ -292,16 +309,21 @@ public void draw(PdfCanvas canvas, float x1, float y1, float x2, float y2, float
292309
y2 -= widthHalf;
293310

294311
canvas
295-
.moveTo(x0, y0).curveTo(x0, y0 - innerRadius * curv, x1 + innerRadiusBefore * curv, y1, x1, y1)
312+
.moveTo(x0, y0).curveTo(x0, y0 - innerRadiusFirst * curv, x1 + innerRadiusBefore * curv, y1, x1, y1)
296313
.lineTo(x2, y2)
297-
.curveTo(x2 - innerRadiusAfter * curv, y2, x3, y3 - innerRadius * curv, x3, y3);
314+
.curveTo(x2 - innerRadiusAfter * curv, y2, x3, y3 - innerRadiusSecond * curv, x3, y3);
298315

299316
break;
300317
case LEFT:
301-
x0 += innerRadius;
318+
innerRadiusBefore = Math.max(0, verticalRadius1 - borderWidthBefore);
319+
innerRadiusFirst = Math.max(0, horizontalRadius1 - width);
320+
innerRadiusSecond = Math.max(0, horizontalRadius2 - width);
321+
innerRadiusAfter = Math.max(0, verticalRadius2 - borderWidthAfter);
322+
323+
x0 += innerRadiusFirst;
302324
y0 -= borderWidthBefore / 2;
303325

304-
x3 += innerRadius;
326+
x3 += innerRadiusSecond;
305327
y3 += borderWidthAfter;
306328

307329
clipPoint1 = getIntersectionPoint(new Point(x1 - width, y1 - borderWidthBefore), new Point(x1, y1), new Point(x0, y0), new Point(x0, y0 + 10));
@@ -321,15 +343,16 @@ public void draw(PdfCanvas canvas, float x1, float y1, float x2, float y2, float
321343
y2 -= innerRadiusAfter;
322344

323345
canvas
324-
.moveTo(x0, y0).curveTo(x0 - innerRadius * curv, y0, x1, y1 - innerRadiusBefore * curv, x1, y1)
346+
.moveTo(x0, y0).curveTo(x0 - innerRadiusFirst * curv, y0, x1, y1 - innerRadiusBefore * curv, x1, y1)
325347
.lineTo(x2, y2)
326-
.curveTo(x2, y2 + innerRadiusAfter * curv, x3 - innerRadius * curv, y3, x3, y3);
348+
.curveTo(x2, y2 + innerRadiusAfter * curv, x3 - innerRadiusSecond * curv, y3, x3, y3);
327349
break;
328350
}
329351
canvas
330352
.stroke()
331-
.restoreState();
332-
}
353+
.restoreState(); }
354+
355+
/**
333356
334357
/**
335358
* Adjusts the size of the gap between dots

0 commit comments

Comments
 (0)