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: TraitSetter.java 1790795 2017-04-10 10:03:35Z cbowditch $ */
19 
20 package org.apache.fop.layoutmgr;
21 
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24 
25 import org.apache.fop.accessibility.StructureTreeElement;
26 import org.apache.fop.area.Area;
27 import org.apache.fop.area.Trait;
28 import org.apache.fop.datatypes.LengthBase;
29 import org.apache.fop.datatypes.PercentBaseContext;
30 import org.apache.fop.datatypes.SimplePercentBaseContext;
31 import org.apache.fop.fo.Constants;
32 import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
33 import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
34 import org.apache.fop.fo.properties.CommonMarginBlock;
35 import org.apache.fop.fo.properties.CommonTextDecoration;
36 import org.apache.fop.fonts.Font;
37 import org.apache.fop.traits.BorderProps;
38 import org.apache.fop.traits.MinOptMax;
39 import org.apache.fop.traits.Visibility;
40 
41 /**
42  * This is a helper class used for setting common traits on areas.
43  */
44 public final class TraitSetter {
45 
TraitSetter()46     private TraitSetter() {
47     }
48 
49     /** logger */
50     private static final Log LOG = LogFactory.getLog(TraitSetter.class);
51 
52     /**
53      * Sets border and padding traits on areas.
54      *
55      * @param area      area to set the traits on
56      * @param bpProps   border and padding properties
57      * @param isNotFirst True if the area is not the first area
58      * @param isNotLast  True if the area is not the last area
59      * @param context   Property evaluation context
60      */
setBorderPaddingTraits(Area area, CommonBorderPaddingBackground bpProps, boolean isNotFirst, boolean isNotLast, PercentBaseContext context)61     public static void setBorderPaddingTraits(Area area,
62             CommonBorderPaddingBackground bpProps, boolean isNotFirst, boolean isNotLast,
63             PercentBaseContext context) {
64         int padding;
65         padding = bpProps.getPadding(CommonBorderPaddingBackground.START, isNotFirst, context);
66         if (padding > 0) {
67             area.addTrait(Trait.PADDING_START, padding);
68         }
69         padding = bpProps.getPadding(CommonBorderPaddingBackground.END, isNotLast, context);
70         if (padding > 0) {
71             area.addTrait(Trait.PADDING_END, padding);
72         }
73         padding = bpProps.getPadding(CommonBorderPaddingBackground.BEFORE, false, context);
74         if (padding > 0) {
75             area.addTrait(Trait.PADDING_BEFORE, padding);
76         }
77         padding = bpProps.getPadding(CommonBorderPaddingBackground.AFTER, false, context);
78         if (padding > 0) {
79             area.addTrait(Trait.PADDING_AFTER, padding);
80         }
81 
82         addBorderTrait(area, bpProps, isNotFirst,
83                 CommonBorderPaddingBackground.START,
84                 BorderProps.Mode.SEPARATE, Trait.BORDER_START, context);
85 
86         addBorderTrait(area, bpProps, isNotLast,
87                 CommonBorderPaddingBackground.END,
88                 BorderProps.Mode.SEPARATE, Trait.BORDER_END, context);
89 
90         addBorderTrait(area, bpProps, false,
91                 CommonBorderPaddingBackground.BEFORE,
92                 BorderProps.Mode.SEPARATE, Trait.BORDER_BEFORE, context);
93 
94         addBorderTrait(area, bpProps, false,
95                 CommonBorderPaddingBackground.AFTER,
96                 BorderProps.Mode.SEPARATE, Trait.BORDER_AFTER, context);
97     }
98 
99     /*
100      * Sets border traits on an area.
101      *
102      * @param area    area to set the traits on
103      * @param bpProps border and padding properties
104      * @param mode    the border paint mode (see BorderProps)
105      */
addBorderTrait(Area area, CommonBorderPaddingBackground bpProps, boolean discard, int side, BorderProps.Mode mode, Integer traitCode, PercentBaseContext context)106     private static void addBorderTrait(Area area,
107                                        CommonBorderPaddingBackground bpProps,
108 
109                                        boolean discard, int side, BorderProps.Mode mode,
110                                        Integer traitCode, PercentBaseContext context) {
111         int width = bpProps.getBorderWidth(side, discard);
112         int radiusStart = bpProps.getBorderRadiusStart(side, discard, context);
113         int radiusEnd = bpProps.getBorderRadiusEnd(side, discard, context);
114         if (width > 0 || radiusStart > 0 || radiusEnd > 0) {
115             area.addTrait(traitCode, new BorderProps(bpProps.getBorderStyle(side), width, radiusStart,
116                     radiusEnd, bpProps.getBorderColor(side), mode));
117         }
118     }
119 
120     /**
121      * Add borders to an area. Note: this method also adds unconditional padding. Don't use!
122      * Layout managers that create areas with borders can use this to
123      * add the borders to the area.
124      * @param area the area to set the traits on.
125      * @param borderProps border properties
126      * @param context Property evaluation context
127      * @deprecated Call the other addBorders() method and addPadding separately.
128      */
addBorders(Area area, CommonBorderPaddingBackground borderProps, PercentBaseContext context)129     public static void addBorders(Area area, CommonBorderPaddingBackground borderProps,
130                                   PercentBaseContext context) {
131         BorderProps bps = getBorderProps(borderProps, CommonBorderPaddingBackground.BEFORE, context);
132         if (bps != null) {
133             area.addTrait(Trait.BORDER_BEFORE, bps);
134         }
135         bps = getBorderProps(borderProps, CommonBorderPaddingBackground.AFTER, context);
136         if (bps != null) {
137             area.addTrait(Trait.BORDER_AFTER, bps);
138         }
139         bps = getBorderProps(borderProps, CommonBorderPaddingBackground.START, context);
140         if (bps != null) {
141             area.addTrait(Trait.BORDER_START, bps);
142         }
143         bps = getBorderProps(borderProps, CommonBorderPaddingBackground.END, context);
144         if (bps != null) {
145             area.addTrait(Trait.BORDER_END, bps);
146         }
147 
148         addPadding(area, borderProps, context);
149     }
150 
151     /**
152      * Add borders to an area.
153      * Layout managers that create areas with borders can use this to
154      * add the borders to the area.
155      * @param area the area to set the traits on.
156      * @param borderProps border properties
157      * @param discardBefore true if the before border should be discarded
158      * @param discardAfter true if the after border should be discarded
159      * @param discardStart true if the start border should be discarded
160      * @param discardEnd true if the end border should be discarded
161      * @param context Property evaluation context
162      */
163     //TODO: remove evaluation context; unused, since border-widths are always absolute lengths
addBorders(Area area, CommonBorderPaddingBackground borderProps, boolean discardBefore, boolean discardAfter, boolean discardStart, boolean discardEnd, PercentBaseContext context)164     public static void addBorders(Area area, CommonBorderPaddingBackground borderProps,
165                 boolean discardBefore, boolean discardAfter,
166                 boolean discardStart, boolean discardEnd,
167                 PercentBaseContext context) {
168         BorderProps bps = getBorderProps(borderProps, CommonBorderPaddingBackground.BEFORE, context);
169         if (bps != null && !discardBefore) {
170             area.addTrait(Trait.BORDER_BEFORE, bps);
171         }
172         bps = getBorderProps(borderProps, CommonBorderPaddingBackground.AFTER, context);
173         if (bps != null && !discardAfter) {
174             area.addTrait(Trait.BORDER_AFTER, bps);
175         }
176         bps = getBorderProps(borderProps, CommonBorderPaddingBackground.START, context);
177         if (bps != null && !discardStart) {
178             area.addTrait(Trait.BORDER_START, bps);
179         }
180         bps = getBorderProps(borderProps, CommonBorderPaddingBackground.END, context);
181         if (bps != null && !discardEnd) {
182             area.addTrait(Trait.BORDER_END, bps);
183         }
184 
185     }
186 
187     /**
188      * Add borders to an area for the collapsing border model in tables.
189      * Layout managers that create areas with borders can use this to
190      * add the borders to the area.
191      * @param area the area to set the traits on.
192      * @param borderBefore the resolved before border
193      * @param borderAfter the resolved after border
194      * @param borderStart the resolved start border
195      * @param borderEnd the resolved end border
196      * @param outer 4 boolean values indicating if the side represents the
197      *     table's outer border. Order: before, after, start, end
198      */
addCollapsingBorders(Area area, BorderInfo borderBefore, BorderInfo borderAfter, BorderInfo borderStart, BorderInfo borderEnd, boolean[] outer)199     public static void addCollapsingBorders(Area area,
200             BorderInfo borderBefore, BorderInfo borderAfter,
201             BorderInfo borderStart, BorderInfo borderEnd,
202             boolean[] outer) {
203         BorderProps bps = getCollapsingBorderProps(borderBefore, outer[0]);
204         if (bps != null) {
205             area.addTrait(Trait.BORDER_BEFORE, bps);
206         }
207         bps = getCollapsingBorderProps(borderAfter, outer[1]);
208         if (bps != null) {
209             area.addTrait(Trait.BORDER_AFTER, bps);
210         }
211         bps = getCollapsingBorderProps(borderStart, outer[2]);
212         if (bps != null) {
213             area.addTrait(Trait.BORDER_START, bps);
214         }
215         bps = getCollapsingBorderProps(borderEnd, outer[3]);
216         if (bps != null) {
217             area.addTrait(Trait.BORDER_END, bps);
218         }
219     }
220 
addPadding(Area area, CommonBorderPaddingBackground bordProps, PercentBaseContext context)221     private static void addPadding(Area area, CommonBorderPaddingBackground bordProps,
222                                 PercentBaseContext context) {
223         addPadding(area, bordProps, false, false, false, false, context);
224     }
225 
226     /**
227      * Add padding to an area.
228      * Layout managers that create areas with padding can use this to
229      * add the borders to the area.
230      * @param area the area to set the traits on.
231      * @param bordProps border and padding properties
232      * @param discardBefore true if the before padding should be discarded
233      * @param discardAfter true if the after padding should be discarded
234      * @param discardStart true if the start padding should be discarded
235      * @param discardEnd true if the end padding should be discarded
236      * @param context Property evaluation context
237      */
addPadding(Area area, CommonBorderPaddingBackground bordProps, boolean discardBefore, boolean discardAfter, boolean discardStart, boolean discardEnd, PercentBaseContext context)238     public static void addPadding(Area area, CommonBorderPaddingBackground bordProps,
239                 boolean discardBefore, boolean discardAfter,
240                 boolean discardStart, boolean discardEnd,
241                 PercentBaseContext context) {
242         int padding = bordProps.getPadding(CommonBorderPaddingBackground.BEFORE,
243                 discardBefore, context);
244         if (padding != 0) {
245             area.addTrait(Trait.PADDING_BEFORE, padding);
246         }
247 
248         padding = bordProps.getPadding(CommonBorderPaddingBackground.AFTER,
249                 discardAfter, context);
250         if (padding != 0) {
251             area.addTrait(Trait.PADDING_AFTER, padding);
252         }
253 
254         padding = bordProps.getPadding(CommonBorderPaddingBackground.START,
255                 discardStart, context);
256         if (padding != 0) {
257             area.addTrait(Trait.PADDING_START, padding);
258         }
259 
260         padding = bordProps.getPadding(CommonBorderPaddingBackground.END,
261                 discardEnd, context);
262         if (padding != 0) {
263             area.addTrait(Trait.PADDING_END, padding);
264         }
265 
266     }
267 
getBorderProps(CommonBorderPaddingBackground bordProps, int side, PercentBaseContext context)268     private static BorderProps getBorderProps(CommonBorderPaddingBackground bordProps,
269             int side, PercentBaseContext context) {
270         int width = bordProps.getBorderWidth(side, false);
271         int radiusStart = bordProps.getBorderRadiusStart(side, false, context);
272         int radiusEnd = bordProps.getBorderRadiusEnd(side, false, context);
273         if (width != 0 || radiusStart != 0 || radiusEnd != 0) {
274             return new BorderProps(bordProps.getBorderStyle(side), width, radiusStart, radiusEnd,
275                                   bordProps.getBorderColor(side), BorderProps.Mode.SEPARATE);
276         } else {
277             return null;
278         }
279     }
280 
getCollapsingBorderProps(BorderInfo borderInfo, boolean outer)281     private static BorderProps getCollapsingBorderProps(BorderInfo borderInfo, boolean outer) {
282         assert borderInfo != null;
283         int width = borderInfo.getRetainedWidth();
284         if (width != 0) {
285             return  BorderProps.makeRectangular(borderInfo.getStyle(), width, borderInfo.getColor(),
286                     (outer ? BorderProps.Mode.COLLAPSE_OUTER : BorderProps.Mode.COLLAPSE_INNER));
287         } else {
288             return null;
289         }
290     }
291 
292 
293     /**
294      * Add background to an area. This method is mainly used by table-related layout
295      * managers to add background for column, body or row. Since the area corresponding to
296      * border-separation must be filled with the table's background, for every cell an
297      * additional area with the same dimensions is created to hold the background for the
298      * corresponding column/body/row. An additional shift must then be added to
299      * background-position-horizontal/vertical to ensure the background images are
300      * correctly placed. Indeed the placement of images must be made WRT the
301      * column/body/row and not the cell.
302      *
303      * <p>Note: The area's IPD and BPD must be set before calling this method.</p>
304      *
305      * <p>TODO the regular
306      * {@link #addBackground(Area, CommonBorderPaddingBackground, PercentBaseContext)}
307      * method should be used instead, and a means to retrieve the original area's
308      * dimensions must be found.</p>
309      *
310      * <p>TODO the placement of images in the x- or y-direction will be incorrect if
311      * background-repeat is set for that direction.</p>
312      *
313      * @param area the area to set the traits on
314      * @param backProps the background properties
315      * @param context Property evaluation context
316      * @param ipdShift horizontal shift to affect to the background, in addition to the
317      * value of the background-position-horizontal property
318      * @param bpdShift vertical shift to affect to the background, in addition to the
319      * value of the background-position-vertical property
320      * @param referenceIPD value to use as a reference for percentage calculation
321      * @param referenceBPD value to use as a reference for percentage calculation
322      */
addBackground(Area area, CommonBorderPaddingBackground backProps, PercentBaseContext context, int ipdShift, int bpdShift, int referenceIPD, int referenceBPD)323     public static void addBackground(Area area,
324             CommonBorderPaddingBackground backProps,
325             PercentBaseContext context,
326             int ipdShift, int bpdShift, int referenceIPD, int referenceBPD) {
327         if (!backProps.hasBackground()) {
328             return;
329         }
330         Trait.Background back = new Trait.Background();
331         back.setColor(backProps.backgroundColor);
332 
333         if (backProps.getImageInfo() != null) {
334             back.setURL(backProps.backgroundImage);
335             back.setImageInfo(backProps.getImageInfo());
336             back.setRepeat(backProps.backgroundRepeat);
337             if (backProps.backgroundPositionHorizontal != null) {
338                 if (back.getRepeat() == Constants.EN_NOREPEAT
339                         || back.getRepeat() == Constants.EN_REPEATY) {
340                     if (area.getIPD() > 0) {
341                         PercentBaseContext refContext = new SimplePercentBaseContext(context,
342                                 LengthBase.IMAGE_BACKGROUND_POSITION_HORIZONTAL,
343                                 (referenceIPD - back.getImageInfo().getSize().getWidthMpt()));
344 
345                         back.setHoriz(ipdShift
346                                 + backProps.backgroundPositionHorizontal.getValue(refContext));
347                     } else {
348                         // TODO Area IPD has to be set for this to work
349                         LOG.warn("Horizontal background image positioning ignored"
350                                 + " because the IPD was not set on the area."
351                                 + " (Yes, it's a bug in FOP)");
352                     }
353                 }
354             }
355             if (backProps.backgroundPositionVertical != null) {
356                 if (back.getRepeat() == Constants.EN_NOREPEAT
357                         || back.getRepeat() == Constants.EN_REPEATX) {
358                     if (area.getBPD() > 0) {
359                         PercentBaseContext refContext = new SimplePercentBaseContext(context,
360                                 LengthBase.IMAGE_BACKGROUND_POSITION_VERTICAL,
361                                 (referenceBPD - back.getImageInfo().getSize().getHeightMpt()));
362                         back.setVertical(bpdShift
363                                 + backProps.backgroundPositionVertical.getValue(refContext));
364                     } else {
365                         // TODO Area BPD has to be set for this to work
366                         LOG.warn("Vertical background image positioning ignored"
367                                 + " because the BPD was not set on the area."
368                                 + " (Yes, it's a bug in FOP)");
369                     }
370                 }
371             }
372         }
373 
374         area.addTrait(Trait.BACKGROUND, back);
375     }
376 
377     /**
378      * Add background to an area.
379      * Layout managers that create areas with a background can use this to
380      * add the background to the area.
381      * Note: The area's IPD and BPD must be set before calling this method.
382      * @param area the area to set the traits on
383      * @param backProps the background properties
384      * @param context Property evaluation context
385      */
addBackground(Area area, CommonBorderPaddingBackground backProps, PercentBaseContext context)386     public static void addBackground(Area area,
387                                      CommonBorderPaddingBackground backProps,
388                                      PercentBaseContext context) {
389         if (!backProps.hasBackground()) {
390             return;
391         }
392         Trait.Background back = new Trait.Background();
393         back.setColor(backProps.backgroundColor);
394 
395         if (backProps.getImageInfo() != null) {
396             back.setURL(backProps.backgroundImage);
397             back.setImageInfo(backProps.getImageInfo());
398             back.setRepeat(backProps.backgroundRepeat);
399             if (backProps.backgroundPositionHorizontal != null) {
400                 if (back.getRepeat() == Constants.EN_NOREPEAT
401                         || back.getRepeat() == Constants.EN_REPEATY) {
402                     if (area.getIPD() > 0) {
403                         int width = area.getIPD();
404                         width += backProps.getPaddingStart(false, context);
405                         width += backProps.getPaddingEnd(false, context);
406                         int imageWidthMpt = back.getImageInfo().getSize().getWidthMpt();
407                         int lengthBaseValue = width - imageWidthMpt;
408                         SimplePercentBaseContext simplePercentBaseContext
409                                 = new SimplePercentBaseContext(context,
410                                 LengthBase.IMAGE_BACKGROUND_POSITION_HORIZONTAL,
411                                 lengthBaseValue);
412                         int horizontal = backProps.backgroundPositionHorizontal.getValue(
413                                 simplePercentBaseContext);
414                         back.setHoriz(horizontal);
415                     } else {
416                         //TODO Area IPD has to be set for this to work
417                         LOG.warn("Horizontal background image positioning ignored"
418                                 + " because the IPD was not set on the area."
419                                 + " (Yes, it's a bug in FOP)");
420                     }
421                 }
422             }
423             if (backProps.backgroundPositionVertical != null) {
424                 if (back.getRepeat() == Constants.EN_NOREPEAT
425                         || back.getRepeat() == Constants.EN_REPEATX) {
426                     if (area.getBPD() > 0) {
427                         int height = area.getBPD();
428                         height += backProps.getPaddingBefore(false, context);
429                         height += backProps.getPaddingAfter(false, context);
430                         int imageHeightMpt = back.getImageInfo().getSize().getHeightMpt();
431                         int lengthBaseValue = height - imageHeightMpt;
432                         SimplePercentBaseContext simplePercentBaseContext
433                                 = new SimplePercentBaseContext(context,
434                                 LengthBase.IMAGE_BACKGROUND_POSITION_VERTICAL,
435                                 lengthBaseValue);
436                         int vertical = backProps.backgroundPositionVertical.getValue(
437                                 simplePercentBaseContext);
438                         back.setVertical(vertical);
439                     } else {
440                         //TODO Area BPD has to be set for this to work
441                         LOG.warn("Vertical background image positioning ignored"
442                                 + " because the BPD was not set on the area."
443                                 + " (Yes, it's a bug in FOP)");
444                     }
445                 }
446             }
447             if (backProps.backgroungImageTargetWidth.getValue() != 0) {
448                 back.setImageTargetWidth(backProps.backgroungImageTargetWidth.getValue());
449             }
450             if (backProps.backgroungImageTargetHeight.getValue() != 0) {
451                 back.setImageTargetHeight(backProps.backgroungImageTargetHeight.getValue());
452             }
453         }
454 
455         area.addTrait(Trait.BACKGROUND, back);
456     }
457 
458     /**
459      * Add space to a block area.
460      * Layout managers that create block areas can use this to add space
461      * outside of the border rectangle to the area.
462      * @param area the area to set the traits on.
463      * @param bpProps the border, padding and background properties
464      * @param startIndent the effective start-indent value
465      * @param endIndent the effective end-indent value
466      * @param context the context for evaluation of percentages
467      */
addMargins(Area area, CommonBorderPaddingBackground bpProps, int startIndent, int endIndent, PercentBaseContext context)468     public static void addMargins(Area area,
469                                   CommonBorderPaddingBackground bpProps,
470                                   int startIndent, int endIndent,
471                                   PercentBaseContext context) {
472         if (startIndent != 0) {
473             area.addTrait(Trait.START_INDENT, startIndent);
474         }
475 
476         int spaceStart = startIndent
477                 - bpProps.getBorderStartWidth(false)
478                 - bpProps.getPaddingStart(false, context);
479         if (spaceStart != 0) {
480             area.addTrait(Trait.SPACE_START, spaceStart);
481         }
482 
483         if (endIndent != 0) {
484             area.addTrait(Trait.END_INDENT, endIndent);
485         }
486         int spaceEnd = endIndent
487                 - bpProps.getBorderEndWidth(false)
488                 - bpProps.getPaddingEnd(false, context);
489         if (spaceEnd != 0) {
490             area.addTrait(Trait.SPACE_END, spaceEnd);
491         }
492     }
493 
494     /**
495      * Add space to a block area.
496      * Layout managers that create block areas can use this to add space
497      * outside of the border rectangle to the area.
498      * @param area the area to set the traits on.
499      * @param bpProps the border, padding and background properties
500      * @param marginProps the margin properties.
501      * @param context the context for evaluation of percentages
502      */
addMargins(Area area, CommonBorderPaddingBackground bpProps, CommonMarginBlock marginProps, PercentBaseContext context)503     public static void addMargins(Area area,
504                                   CommonBorderPaddingBackground bpProps,
505                                   CommonMarginBlock marginProps,
506                                   PercentBaseContext context) {
507         int startIndent = marginProps.startIndent.getValue(context);
508         int endIndent = marginProps.endIndent.getValue(context);
509         addMargins(area, bpProps, startIndent, endIndent, context);
510     }
511 
512     /**
513      * Returns the effective space length of a resolved space specifier based on the adjustment
514      * value.
515      * @param adjust the adjustment value
516      * @param space the space specifier
517      * @return the effective space length
518      */
getEffectiveSpace(double adjust, MinOptMax space)519     public static int getEffectiveSpace(double adjust, MinOptMax space) {
520         if (space == null) {
521             return 0;
522         } else {
523             int spaceOpt = space.getOpt();
524             if (adjust > 0) {
525                 spaceOpt += (int) (adjust * space.getStretch());
526             } else {
527                 spaceOpt += (int) (adjust * space.getShrink());
528             }
529             return spaceOpt;
530         }
531     }
532 
533     /**
534      * Adds traits for space-before and space-after to an area.
535      * @param area the target area
536      * @param adjust the adjustment value
537      * @param spaceBefore the space-before space specifier
538      * @param spaceAfter the space-after space specifier
539      */
addSpaceBeforeAfter(Area area, double adjust, MinOptMax spaceBefore, MinOptMax spaceAfter)540     public static void addSpaceBeforeAfter(Area area, double adjust, MinOptMax spaceBefore,
541                                            MinOptMax spaceAfter) {
542         addSpaceTrait(area, Trait.SPACE_BEFORE, spaceBefore, adjust);
543         addSpaceTrait(area, Trait.SPACE_AFTER, spaceAfter, adjust);
544     }
545 
addSpaceTrait(Area area, Integer spaceTrait, MinOptMax space, double adjust)546     private static void addSpaceTrait(Area area, Integer spaceTrait,
547             MinOptMax space, double adjust) {
548         int effectiveSpace = getEffectiveSpace(adjust, space);
549         if (effectiveSpace != 0) {
550             area.addTrait(spaceTrait, effectiveSpace);
551         }
552     }
553 
554     /**
555      * Sets the traits for breaks on an area.
556      * @param area the area to set the traits on.
557      * @param breakBefore the value for break-before
558      * @param breakAfter the value for break-after
559      */
addBreaks(Area area, int breakBefore, int breakAfter)560     public static void addBreaks(Area area, int breakBefore, int breakAfter) {
561         /* Currently disabled as these traits are never used by the renderers
562         area.addTrait(Trait.BREAK_AFTER, Integer.valueOf(breakAfter));
563         area.addTrait(Trait.BREAK_BEFORE, Integer.valueOf(breakBefore));
564         */
565     }
566 
567     /**
568      * Adds font traits to an area
569      * @param area the target are
570      * @param font the font to use
571      */
addFontTraits(Area area, Font font)572     public static void addFontTraits(Area area, Font font) {
573         area.addTrait(Trait.FONT, font.getFontTriplet());
574         area.addTrait(Trait.FONT_SIZE, font.getFontSize());
575     }
576 
577     /**
578      * Adds the text-decoration traits to the area.
579      * @param area the area to set the traits on
580      * @param deco the text decorations
581      */
addTextDecoration(Area area, CommonTextDecoration deco)582     public static void addTextDecoration(Area area, CommonTextDecoration deco) {
583         //TODO Finish text-decoration
584         if (deco != null) {
585             if (deco.hasUnderline()) {
586                 area.addTrait(Trait.UNDERLINE, Boolean.TRUE);
587                 area.addTrait(Trait.UNDERLINE_COLOR, deco.getUnderlineColor());
588             }
589             if (deco.hasOverline()) {
590                 area.addTrait(Trait.OVERLINE, Boolean.TRUE);
591                 area.addTrait(Trait.OVERLINE_COLOR, deco.getOverlineColor());
592             }
593             if (deco.hasLineThrough()) {
594                 area.addTrait(Trait.LINETHROUGH, Boolean.TRUE);
595                 area.addTrait(Trait.LINETHROUGH_COLOR, deco.getLineThroughColor());
596             }
597             if (deco.isBlinking()) {
598                 area.addTrait(Trait.BLINK, Boolean.TRUE);
599             }
600         }
601     }
602 
setVisibility(Area area, int visibility)603     public static void setVisibility(Area area, int visibility) {
604         Visibility v;
605         switch (visibility) {
606             case Constants.EN_COLLAPSE:
607                 v = Visibility.COLLAPSE;
608                 break;
609             case Constants.EN_HIDDEN:
610                 v = Visibility.HIDDEN;
611                 break;
612             default:
613                 v = Visibility.VISIBLE;
614         }
615         area.addTrait(Trait.VISIBILITY, v);
616     }
617 
618     /**
619      * Sets the structure tree element associated to the given area.
620      *
621      * @param area the area to set the traits on
622      * @param structureTreeElement the element the area is associated to in the document structure
623      */
addStructureTreeElement(Area area, StructureTreeElement structureTreeElement)624     public static void addStructureTreeElement(Area area,
625             StructureTreeElement structureTreeElement) {
626         if (structureTreeElement != null) {
627             area.addTrait(Trait.STRUCTURE_TREE_ELEMENT, structureTreeElement);
628         }
629     }
630 
631     /**
632      * Sets the producer's ID as a trait on the area. This can be used to track back the
633      * generating FO node.
634      * @param area the area to set the traits on
635      * @param id the ID to set
636      */
setProducerID(Area area, String id)637     public static void setProducerID(Area area, String id) {
638         if (id != null && id.length() > 0) {
639             area.addTrait(Trait.PROD_ID, id);
640         }
641     }
642 
643     /**
644      * Sets the optional content group layer as a trait on the area.
645      * @param area the area to set the traits on
646      * @param layer the layer ID to set
647      */
setLayer(Area area, String layer)648     public static void setLayer(Area area, String layer) {
649         if (layer != null && layer.length() > 0) {
650             area.addTrait(Trait.LAYER, layer);
651         }
652     }
653 }
654