001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: /* $Id: TraitSetter.java 530445 2007-04-19 15:12:50Z vhennebert $ */
019:
020: package org.apache.fop.layoutmgr;
021:
022: import org.apache.commons.logging.Log;
023: import org.apache.commons.logging.LogFactory;
024: import org.apache.fop.traits.BorderProps;
025: import org.apache.fop.traits.MinOptMax;
026: import org.apache.fop.area.Area;
027: import org.apache.fop.area.Trait;
028: import org.apache.fop.datatypes.LengthBase;
029: import org.apache.fop.datatypes.PercentBaseContext;
030: import org.apache.fop.datatypes.SimplePercentBaseContext;
031: import org.apache.fop.fo.Constants;
032: import org.apache.fop.fo.properties.CommonMarginBlock;
033: import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
034: import org.apache.fop.fo.properties.CommonTextDecoration;
035: import org.apache.fop.fonts.Font;
036: import org.apache.fop.fonts.FontInfo;
037: import org.apache.fop.fonts.FontTriplet;
038:
039: /**
040: * This is a helper class used for setting common traits on areas.
041: */
042: public class TraitSetter {
043:
044: /** logger */
045: protected static Log log = LogFactory.getLog(TraitSetter.class);
046:
047: /**
048: * Sets border and padding traits on areas.
049: * @param area area to set the traits on
050: * @param bpProps border and padding properties
051: * @param bNotFirst True if the area is not the first area
052: * @param bNotLast True if the area is not the last area
053: * @param context Property evaluation context
054: */
055: public static void setBorderPaddingTraits(Area area,
056: CommonBorderPaddingBackground bpProps, boolean bNotFirst,
057: boolean bNotLast, PercentBaseContext context) {
058: int iBP;
059: iBP = bpProps.getPadding(CommonBorderPaddingBackground.START,
060: bNotFirst, context);
061: if (iBP > 0) {
062: area.addTrait(Trait.PADDING_START, new Integer(iBP));
063: }
064: iBP = bpProps.getPadding(CommonBorderPaddingBackground.END,
065: bNotLast, context);
066: if (iBP > 0) {
067: area.addTrait(Trait.PADDING_END, new Integer(iBP));
068: }
069: iBP = bpProps.getPadding(CommonBorderPaddingBackground.BEFORE,
070: false, context);
071: if (iBP > 0) {
072: area.addTrait(Trait.PADDING_BEFORE, new Integer(iBP));
073: }
074: iBP = bpProps.getPadding(CommonBorderPaddingBackground.AFTER,
075: false, context);
076: if (iBP > 0) {
077: area.addTrait(Trait.PADDING_AFTER, new Integer(iBP));
078: }
079:
080: addBorderTrait(area, bpProps, bNotFirst,
081: CommonBorderPaddingBackground.START,
082: BorderProps.SEPARATE, Trait.BORDER_START);
083:
084: addBorderTrait(area, bpProps, bNotLast,
085: CommonBorderPaddingBackground.END,
086: BorderProps.SEPARATE, Trait.BORDER_END);
087:
088: addBorderTrait(area, bpProps, false,
089: CommonBorderPaddingBackground.BEFORE,
090: BorderProps.SEPARATE, Trait.BORDER_BEFORE);
091:
092: addBorderTrait(area, bpProps, false,
093: CommonBorderPaddingBackground.AFTER,
094: BorderProps.SEPARATE, Trait.BORDER_AFTER);
095: }
096:
097: /**
098: * Sets border traits on an area.
099: * @param area area to set the traits on
100: * @param bpProps border and padding properties
101: * @param mode the border paint mode (see BorderProps)
102: */
103: private static void addBorderTrait(Area area,
104: CommonBorderPaddingBackground bpProps, boolean bDiscard,
105: int iSide, int mode, Object oTrait) {
106: int iBP = bpProps.getBorderWidth(iSide, bDiscard);
107: if (iBP > 0) {
108: area.addTrait(oTrait, new BorderProps(bpProps
109: .getBorderStyle(iSide), iBP, bpProps
110: .getBorderColor(iSide), mode));
111: }
112: }
113:
114: /**
115: * Add borders to an area. Note: this method also adds unconditional padding. Don't use!
116: * Layout managers that create areas with borders can use this to
117: * add the borders to the area.
118: * @param area the area to set the traits on.
119: * @param bordProps border properties
120: * @param context Property evaluation context
121: * @deprecated Call the other addBorders() method and addPadding separately.
122: */
123: public static void addBorders(Area area,
124: CommonBorderPaddingBackground bordProps,
125: PercentBaseContext context) {
126: BorderProps bps = getBorderProps(bordProps,
127: CommonBorderPaddingBackground.BEFORE);
128: if (bps != null) {
129: area.addTrait(Trait.BORDER_BEFORE, bps);
130: }
131: bps = getBorderProps(bordProps,
132: CommonBorderPaddingBackground.AFTER);
133: if (bps != null) {
134: area.addTrait(Trait.BORDER_AFTER, bps);
135: }
136: bps = getBorderProps(bordProps,
137: CommonBorderPaddingBackground.START);
138: if (bps != null) {
139: area.addTrait(Trait.BORDER_START, bps);
140: }
141: bps = getBorderProps(bordProps,
142: CommonBorderPaddingBackground.END);
143: if (bps != null) {
144: area.addTrait(Trait.BORDER_END, bps);
145: }
146:
147: addPadding(area, bordProps, context);
148: }
149:
150: /**
151: * Add borders to an area.
152: * Layout managers that create areas with borders can use this to
153: * add the borders to the area.
154: * @param area the area to set the traits on.
155: * @param bordProps border properties
156: * @param discardBefore true if the before border should be discarded
157: * @param discardAfter true if the after border should be discarded
158: * @param discardStart true if the start border should be discarded
159: * @param discardEnd true if the end border should be discarded
160: * @param context Property evaluation context
161: */
162: public static void addBorders(Area area,
163: CommonBorderPaddingBackground bordProps,
164: boolean discardBefore, boolean discardAfter,
165: boolean discardStart, boolean discardEnd,
166: PercentBaseContext context) {
167: BorderProps bps = getBorderProps(bordProps,
168: CommonBorderPaddingBackground.BEFORE);
169: if (bps != null && !discardBefore) {
170: area.addTrait(Trait.BORDER_BEFORE, bps);
171: }
172: bps = getBorderProps(bordProps,
173: CommonBorderPaddingBackground.AFTER);
174: if (bps != null && !discardAfter) {
175: area.addTrait(Trait.BORDER_AFTER, bps);
176: }
177: bps = getBorderProps(bordProps,
178: CommonBorderPaddingBackground.START);
179: if (bps != null && !discardStart) {
180: area.addTrait(Trait.BORDER_START, bps);
181: }
182: bps = getBorderProps(bordProps,
183: CommonBorderPaddingBackground.END);
184: if (bps != null && !discardEnd) {
185: area.addTrait(Trait.BORDER_END, bps);
186: }
187: }
188:
189: /**
190: * Add borders to an area for the collapsing border model in tables.
191: * Layout managers that create areas with borders can use this to
192: * add the borders to the area.
193: * @param area the area to set the traits on.
194: * @param bordProps border properties
195: * @param outer 4 boolean values indicating if the side represents the
196: * table's outer border. Order: before, after, start, end
197: * @param context Property evaluation context
198: */
199: public static void addCollapsingBorders(Area area,
200: CommonBorderPaddingBackground bordProps, boolean[] outer,
201: PercentBaseContext context) {
202: BorderProps bps = getCollapsingBorderProps(bordProps,
203: CommonBorderPaddingBackground.BEFORE, outer[0]);
204: if (bps != null) {
205: area.addTrait(Trait.BORDER_BEFORE, bps);
206: }
207: bps = getCollapsingBorderProps(bordProps,
208: CommonBorderPaddingBackground.AFTER, outer[1]);
209: if (bps != null) {
210: area.addTrait(Trait.BORDER_AFTER, bps);
211: }
212: bps = getCollapsingBorderProps(bordProps,
213: CommonBorderPaddingBackground.START, outer[2]);
214: if (bps != null) {
215: area.addTrait(Trait.BORDER_START, bps);
216: }
217: bps = getCollapsingBorderProps(bordProps,
218: CommonBorderPaddingBackground.END, outer[3]);
219: if (bps != null) {
220: area.addTrait(Trait.BORDER_END, bps);
221: }
222: }
223:
224: private static void addPadding(Area area,
225: CommonBorderPaddingBackground bordProps,
226: PercentBaseContext context) {
227: addPadding(area, bordProps, false, false, false, false, context);
228: }
229:
230: /**
231: * Add padding to an area.
232: * Layout managers that create areas with padding can use this to
233: * add the borders to the area.
234: * @param area the area to set the traits on.
235: * @param bordProps border and padding properties
236: * @param discardBefore true if the before padding should be discarded
237: * @param discardAfter true if the after padding should be discarded
238: * @param discardStart true if the start padding should be discarded
239: * @param discardEnd true if the end padding should be discarded
240: * @param context Property evaluation context
241: */
242: public static void addPadding(Area area,
243: CommonBorderPaddingBackground bordProps,
244: boolean discardBefore, boolean discardAfter,
245: boolean discardStart, boolean discardEnd,
246: PercentBaseContext context) {
247: int padding = bordProps.getPadding(
248: CommonBorderPaddingBackground.BEFORE, discardBefore,
249: context);
250: if (padding != 0) {
251: area.addTrait(Trait.PADDING_BEFORE, new java.lang.Integer(
252: padding));
253: }
254:
255: padding = bordProps.getPadding(
256: CommonBorderPaddingBackground.AFTER, discardAfter,
257: context);
258: if (padding != 0) {
259: area.addTrait(Trait.PADDING_AFTER, new java.lang.Integer(
260: padding));
261: }
262:
263: padding = bordProps.getPadding(
264: CommonBorderPaddingBackground.START, discardStart,
265: context);
266: if (padding != 0) {
267: area.addTrait(Trait.PADDING_START, new java.lang.Integer(
268: padding));
269: }
270:
271: padding = bordProps.getPadding(
272: CommonBorderPaddingBackground.END, discardEnd, context);
273: if (padding != 0) {
274: area.addTrait(Trait.PADDING_END, new java.lang.Integer(
275: padding));
276: }
277:
278: }
279:
280: private static BorderProps getBorderProps(
281: CommonBorderPaddingBackground bordProps, int side) {
282: int width = bordProps.getBorderWidth(side, false);
283: if (width != 0) {
284: BorderProps bps;
285: bps = new BorderProps(bordProps.getBorderStyle(side),
286: width, bordProps.getBorderColor(side),
287: BorderProps.SEPARATE);
288: return bps;
289: } else {
290: return null;
291: }
292: }
293:
294: private static BorderProps getCollapsingBorderProps(
295: CommonBorderPaddingBackground bordProps, int side,
296: boolean outer) {
297: int width = bordProps.getBorderWidth(side, false);
298: if (width != 0) {
299: BorderProps bps;
300: bps = new BorderProps(bordProps.getBorderStyle(side),
301: width, bordProps.getBorderColor(side),
302: (outer ? BorderProps.COLLAPSE_OUTER
303: : BorderProps.COLLAPSE_INNER));
304: return bps;
305: } else {
306: return null;
307: }
308: }
309:
310: /**
311: * Add background to an area.
312: * Layout managers that create areas with a background can use this to
313: * add the background to the area.
314: * Note: The area's IPD and BPD must be set before calling this method.
315: * @param area the area to set the traits on
316: * @param backProps the background properties
317: * @param context Property evaluation context
318: */
319: public static void addBackground(Area area,
320: CommonBorderPaddingBackground backProps,
321: PercentBaseContext context) {
322: if (!backProps.hasBackground()) {
323: return;
324: }
325: Trait.Background back = new Trait.Background();
326: back.setColor(backProps.backgroundColor);
327:
328: if (backProps.getFopImage() != null) {
329: back.setURL(backProps.backgroundImage);
330: back.setFopImage(backProps.getFopImage());
331: back.setRepeat(backProps.backgroundRepeat);
332: if (backProps.backgroundPositionHorizontal != null) {
333: if (back.getRepeat() == Constants.EN_NOREPEAT
334: || back.getRepeat() == Constants.EN_REPEATY) {
335: if (area.getIPD() > 0) {
336: int width = area.getIPD();
337: width += backProps.getPaddingStart(false,
338: context);
339: width += backProps
340: .getPaddingEnd(false, context);
341: back
342: .setHoriz(backProps.backgroundPositionHorizontal
343: .getValue(new SimplePercentBaseContext(
344: context,
345: LengthBase.IMAGE_BACKGROUND_POSITION_HORIZONTAL,
346: (width - back
347: .getFopImage()
348: .getIntrinsicWidth()))));
349: } else {
350: //TODO Area IPD has to be set for this to work
351: log
352: .warn("Horizontal background image positioning ignored"
353: + " because the IPD was not set on the area."
354: + " (Yes, it's a bug in FOP)");
355: }
356: }
357: }
358: if (backProps.backgroundPositionVertical != null) {
359: if (back.getRepeat() == Constants.EN_NOREPEAT
360: || back.getRepeat() == Constants.EN_REPEATX) {
361: if (area.getBPD() > 0) {
362: int height = area.getBPD();
363: height += backProps.getPaddingBefore(false,
364: context);
365: height += backProps.getPaddingAfter(false,
366: context);
367: back
368: .setVertical(backProps.backgroundPositionVertical
369: .getValue(new SimplePercentBaseContext(
370: context,
371: LengthBase.IMAGE_BACKGROUND_POSITION_VERTICAL,
372: (height - back
373: .getFopImage()
374: .getIntrinsicHeight()))));
375: } else {
376: //TODO Area BPD has to be set for this to work
377: log
378: .warn("Vertical background image positioning ignored"
379: + " because the BPD was not set on the area."
380: + " (Yes, it's a bug in FOP)");
381: }
382: }
383: }
384: }
385:
386: area.addTrait(Trait.BACKGROUND, back);
387: }
388:
389: /**
390: * Add space to a block area.
391: * Layout managers that create block areas can use this to add space
392: * outside of the border rectangle to the area.
393: * @param area the area to set the traits on.
394: * @param bpProps the border, padding and background properties
395: * @param startIndent the effective start-indent value
396: * @param endIndent the effective end-indent value
397: * @param context the context for evaluation of percentages
398: */
399: public static void addMargins(Area area,
400: CommonBorderPaddingBackground bpProps, int startIndent,
401: int endIndent, PercentBaseContext context) {
402: if (startIndent != 0) {
403: area.addTrait(Trait.START_INDENT, new Integer(startIndent));
404: }
405:
406: int spaceStart = startIndent
407: - bpProps.getBorderStartWidth(false)
408: - bpProps.getPaddingStart(false, context);
409: if (spaceStart != 0) {
410: area.addTrait(Trait.SPACE_START, new Integer(spaceStart));
411: }
412:
413: if (endIndent != 0) {
414: area.addTrait(Trait.END_INDENT, new Integer(endIndent));
415: }
416: int spaceEnd = endIndent - bpProps.getBorderEndWidth(false)
417: - bpProps.getPaddingEnd(false, context);
418: if (spaceEnd != 0) {
419: area.addTrait(Trait.SPACE_END, new Integer(spaceEnd));
420: }
421: }
422:
423: /**
424: * Add space to a block area.
425: * Layout managers that create block areas can use this to add space
426: * outside of the border rectangle to the area.
427: * @param area the area to set the traits on.
428: * @param bpProps the border, padding and background properties
429: * @param marginProps the margin properties.
430: * @param context the context for evaluation of percentages
431: */
432: public static void addMargins(Area area,
433: CommonBorderPaddingBackground bpProps,
434: CommonMarginBlock marginProps, PercentBaseContext context) {
435: int startIndent = marginProps.startIndent.getValue(context);
436: int endIndent = marginProps.endIndent.getValue(context);
437: addMargins(area, bpProps, startIndent, endIndent, context);
438: }
439:
440: /**
441: * Returns the effective space length of a resolved space specifier based on the adjustment
442: * value.
443: * @param adjust the adjustment value
444: * @param space the space specifier
445: * @return the effective space length
446: */
447: public static int getEffectiveSpace(double adjust, MinOptMax space) {
448: if (space == null) {
449: return 0;
450: }
451: int sp = space.opt;
452: if (adjust > 0) {
453: sp = sp + (int) (adjust * (space.max - space.opt));
454: } else {
455: sp = sp + (int) (adjust * (space.opt - space.min));
456: }
457: return sp;
458: }
459:
460: /**
461: * Adds traits for space-before and space-after to an area.
462: * @param area the target area
463: * @param adjust the adjustment value
464: * @param spaceBefore the space-before space specifier
465: * @param spaceAfter the space-after space specifier
466: */
467: public static void addSpaceBeforeAfter(Area area, double adjust,
468: MinOptMax spaceBefore, MinOptMax spaceAfter) {
469: int space;
470: space = getEffectiveSpace(adjust, spaceBefore);
471: if (space != 0) {
472: area.addTrait(Trait.SPACE_BEFORE, new Integer(space));
473: }
474: space = getEffectiveSpace(adjust, spaceAfter);
475: if (space != 0) {
476: area.addTrait(Trait.SPACE_AFTER, new Integer(space));
477: }
478: }
479:
480: /**
481: * Sets the traits for breaks on an area.
482: * @param area the area to set the traits on.
483: * @param breakBefore the value for break-before
484: * @param breakAfter the value for break-after
485: */
486: public static void addBreaks(Area area, int breakBefore,
487: int breakAfter) {
488: /* Currently disabled as these traits are never used by the renderers
489: area.addTrait(Trait.BREAK_AFTER, new Integer(breakAfter));
490: area.addTrait(Trait.BREAK_BEFORE, new Integer(breakBefore));
491: */
492: }
493:
494: /**
495: * Adds font traits to an area
496: * @param area the target are
497: * @param font the font to use
498: */
499: public static void addFontTraits(Area area, Font font) {
500: area.addTrait(Trait.FONT, font.getFontTriplet());
501: area.addTrait(Trait.FONT_SIZE, new Integer(font.getFontSize()));
502: }
503:
504: /**
505: * Adds the text-decoration traits to the area.
506: * @param area the area to set the traits on
507: * @param deco the text decorations
508: */
509: public static void addTextDecoration(Area area,
510: CommonTextDecoration deco) {
511: //TODO Finish text-decoration
512: if (deco != null) {
513: if (deco.hasUnderline()) {
514: area.addTrait(Trait.UNDERLINE, Boolean.TRUE);
515: area.addTrait(Trait.UNDERLINE_COLOR, deco
516: .getUnderlineColor());
517: }
518: if (deco.hasOverline()) {
519: area.addTrait(Trait.OVERLINE, Boolean.TRUE);
520: area.addTrait(Trait.OVERLINE_COLOR, deco
521: .getOverlineColor());
522: }
523: if (deco.hasLineThrough()) {
524: area.addTrait(Trait.LINETHROUGH, Boolean.TRUE);
525: area.addTrait(Trait.LINETHROUGH_COLOR, deco
526: .getLineThroughColor());
527: }
528: if (deco.isBlinking()) {
529: area.addTrait(Trait.BLINK, Boolean.TRUE);
530: }
531: }
532: }
533:
534: /**
535: * Sets the producer's ID as a trait on the area. This can be used to track back the
536: * generating FO node.
537: * @param area the area to set the traits on
538: * @param id the ID to set
539: */
540: public static void setProducerID(Area area, String id) {
541: if (id != null && id.length() > 0) {
542: area.addTrait(Trait.PROD_ID, id);
543: }
544: }
545: }
|