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: AbstractGraphicsLayoutManager.java 495371 2007-01-11 21:03:07Z adelmelle $ */
019:
020: package org.apache.fop.layoutmgr.inline;
021:
022: import java.awt.geom.Rectangle2D;
023: import java.util.LinkedList;
024:
025: import org.apache.fop.area.Area;
026: import org.apache.fop.area.inline.Viewport;
027: import org.apache.fop.datatypes.Length;
028: import org.apache.fop.datatypes.LengthBase;
029: import org.apache.fop.fo.FObj;
030: import org.apache.fop.fo.flow.AbstractGraphics;
031: import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
032: import org.apache.fop.layoutmgr.LayoutContext;
033: import org.apache.fop.layoutmgr.TraitSetter;
034:
035: /**
036: * LayoutManager handling the common tasks for the fo:instream-foreign-object
037: * and fo:external-graphics formatting objects
038: */
039: public abstract class AbstractGraphicsLayoutManager extends
040: LeafNodeLayoutManager {
041:
042: /** The graphics object this LM deals with */
043: protected AbstractGraphics fobj;
044:
045: /**
046: * Constructor
047: * @param node the formatting object that creates this area
048: */
049: public AbstractGraphicsLayoutManager(AbstractGraphics node) {
050: super (node);
051: fobj = node;
052: }
053:
054: /**
055: * Get the inline area created by this element.
056: *
057: * @return the viewport inline area
058: */
059: private Viewport getInlineArea() {
060:
061: // viewport size is determined by block-progression-dimension
062: // and inline-progression-dimension
063:
064: // if replaced then use height then ignore block-progression-dimension
065: //int h = this.propertyList.get("height").getLength().mvalue();
066:
067: // use specified line-height then ignore dimension in height direction
068: boolean hasLH = false; //propertyList.get("line-height").getSpecifiedValue() != null;
069:
070: Length len;
071:
072: int bpd = -1;
073: int ipd = -1;
074: if (hasLH) {
075: bpd = fobj.getLineHeight().getOptimum(this ).getLength()
076: .getValue(this );
077: } else {
078: // this property does not apply when the line-height applies
079: // isn't the block-progression-dimension always in the same
080: // direction as the line height?
081: len = fobj.getBlockProgressionDimension().getOptimum(this )
082: .getLength();
083: if (len.getEnum() != EN_AUTO) {
084: bpd = len.getValue(this );
085: } else {
086: len = fobj.getHeight();
087: if (len.getEnum() != EN_AUTO) {
088: bpd = len.getValue(this );
089: }
090: }
091: }
092:
093: len = fobj.getInlineProgressionDimension().getOptimum(this )
094: .getLength();
095: if (len.getEnum() != EN_AUTO) {
096: ipd = len.getValue(this );
097: } else {
098: len = fobj.getWidth();
099: if (len.getEnum() != EN_AUTO) {
100: ipd = len.getValue(this );
101: }
102: }
103:
104: // if auto then use the intrinsic size of the content scaled
105: // to the content-height and content-width
106: int cwidth = -1;
107: int cheight = -1;
108: len = fobj.getContentWidth();
109: if (len.getEnum() != EN_AUTO) {
110: if (len.getEnum() == EN_SCALE_TO_FIT) {
111: if (ipd != -1) {
112: cwidth = ipd;
113: }
114: } else {
115: cwidth = len.getValue(this );
116: }
117: }
118: len = fobj.getContentHeight();
119: if (len.getEnum() != EN_AUTO) {
120: if (len.getEnum() == EN_SCALE_TO_FIT) {
121: if (bpd != -1) {
122: cheight = bpd;
123: }
124: } else {
125: cheight = len.getValue(this );
126: }
127: }
128:
129: int scaling = fobj.getScaling();
130: if ((scaling == EN_UNIFORM) || (cwidth == -1) || cheight == -1) {
131: if (cwidth == -1 && cheight == -1) {
132: cwidth = fobj.getIntrinsicWidth();
133: cheight = fobj.getIntrinsicHeight();
134: } else if (cwidth == -1) {
135: if (fobj.getIntrinsicHeight() == 0) {
136: cwidth = 0;
137: } else {
138: cwidth = (int) (fobj.getIntrinsicWidth()
139: * (double) cheight / fobj
140: .getIntrinsicHeight());
141: }
142: } else if (cheight == -1) {
143: if (fobj.getIntrinsicWidth() == 0) {
144: cheight = 0;
145: } else {
146: cheight = (int) (fobj.getIntrinsicHeight()
147: * (double) cwidth / fobj
148: .getIntrinsicWidth());
149: }
150: } else {
151: // adjust the larger
152: if (fobj.getIntrinsicWidth() == 0
153: || fobj.getIntrinsicHeight() == 0) {
154: cwidth = 0;
155: cheight = 0;
156: } else {
157: double rat1 = (double) cwidth
158: / fobj.getIntrinsicWidth();
159: double rat2 = (double) cheight
160: / fobj.getIntrinsicHeight();
161: if (rat1 < rat2) {
162: // reduce cheight
163: cheight = (int) (rat1 * fobj
164: .getIntrinsicHeight());
165: } else if (rat1 > rat2) {
166: cwidth = (int) (rat2 * fobj.getIntrinsicWidth());
167: }
168: }
169: }
170: }
171:
172: if (ipd == -1) {
173: ipd = cwidth;
174: }
175: if (bpd == -1) {
176: bpd = cheight;
177: }
178:
179: boolean clip = false;
180: if (cwidth > ipd || cheight > bpd) {
181: int overflow = fobj.getOverflow();
182: if (overflow == EN_HIDDEN) {
183: clip = true;
184: } else if (overflow == EN_ERROR_IF_OVERFLOW) {
185: log.error("Object overflows the viewport: clipping");
186: clip = true;
187: }
188: }
189:
190: int xoffset = fobj.computeXOffset(ipd, cwidth);
191: int yoffset = fobj.computeYOffset(bpd, cheight);
192:
193: CommonBorderPaddingBackground borderProps = fobj
194: .getCommonBorderPaddingBackground();
195:
196: //Determine extra BPD from borders etc.
197: int beforeBPD = borderProps.getPadding(
198: CommonBorderPaddingBackground.BEFORE, false, this );
199: beforeBPD += borderProps.getBorderWidth(
200: CommonBorderPaddingBackground.BEFORE, false);
201: int afterBPD = borderProps.getPadding(
202: CommonBorderPaddingBackground.AFTER, false, this );
203: afterBPD += borderProps.getBorderWidth(
204: CommonBorderPaddingBackground.AFTER, false);
205:
206: yoffset += beforeBPD;
207: //bpd += beforeBPD;
208: //bpd += afterBPD;
209:
210: //Determine extra IPD from borders etc.
211: int startIPD = borderProps.getPadding(
212: CommonBorderPaddingBackground.START, false, this );
213: startIPD += borderProps.getBorderWidth(
214: CommonBorderPaddingBackground.START, false);
215: int endIPD = borderProps.getPadding(
216: CommonBorderPaddingBackground.END, false, this );
217: endIPD += borderProps.getBorderWidth(
218: CommonBorderPaddingBackground.END, false);
219:
220: xoffset += startIPD;
221: //ipd += startIPD;
222: //ipd += endIPD;
223:
224: Rectangle2D placement = new Rectangle2D.Float(xoffset, yoffset,
225: cwidth, cheight);
226:
227: Area viewportArea = getChildArea();
228: TraitSetter.setProducerID(viewportArea, fobj.getId());
229: transferForeignAttributes(viewportArea);
230:
231: Viewport vp = new Viewport(viewportArea);
232: TraitSetter.setProducerID(vp, fobj.getId());
233: vp.setIPD(ipd);
234: vp.setBPD(bpd);
235: vp.setContentPosition(placement);
236: vp.setClip(clip);
237: vp.setOffset(0);
238:
239: // Common Border, Padding, and Background Properties
240: TraitSetter.addBorders(vp, fobj
241: .getCommonBorderPaddingBackground(), false, false,
242: false, false, this );
243: TraitSetter.addPadding(vp, fobj
244: .getCommonBorderPaddingBackground(), false, false,
245: false, false, this );
246: TraitSetter.addBackground(vp, fobj
247: .getCommonBorderPaddingBackground(), this );
248:
249: return vp;
250: }
251:
252: /**
253: * @see org.apache.fop.layoutmgr.LayoutManager#getNextKnuthElements(LayoutContext, int)
254: */
255: public LinkedList getNextKnuthElements(LayoutContext context,
256: int alignment) {
257: Viewport areaCurrent = getInlineArea();
258: setCurrentArea(areaCurrent);
259: return super .getNextKnuthElements(context, alignment);
260: }
261:
262: /**
263: * @see LeafNodeLayoutManager#makeAlignmentContext(LayoutContext)
264: */
265: protected AlignmentContext makeAlignmentContext(
266: LayoutContext context) {
267: return new AlignmentContext(get(context).getAllocBPD(), fobj
268: .getAlignmentAdjust(), fobj.getAlignmentBaseline(),
269: fobj.getBaselineShift(), fobj.getDominantBaseline(),
270: context.getAlignmentContext());
271: }
272:
273: /**
274: * @see org.apache.fop.layoutmgr.inline.LeafNodeLayoutManager#addId()
275: */
276: protected void addId() {
277: getPSLM().addIDToPage(fobj.getId());
278: }
279:
280: /**
281: * Returns the image of foreign object area to be put into
282: * the viewport.
283: * @return the appropriate area
284: */
285: abstract Area getChildArea();
286:
287: // --------- Property Resolution related functions --------- //
288:
289: /**
290: * @see org.apache.fop.datatypes.PercentBaseContext#getBaseLength(int, FObj)
291: */
292: public int getBaseLength(int lengthBase, FObj fobj) {
293: switch (lengthBase) {
294: case LengthBase.IMAGE_INTRINSIC_WIDTH:
295: return getIntrinsicWidth();
296: case LengthBase.IMAGE_INTRINSIC_HEIGHT:
297: return getIntrinsicHeight();
298: case LengthBase.ALIGNMENT_ADJUST:
299: return get(null).getBPD();
300: default: // Delegate to super class
301: return super .getBaseLength(lengthBase, fobj);
302: }
303: }
304:
305: /**
306: * Returns the intrinsic width of the e-g.
307: * @return the width of the element
308: */
309: protected int getIntrinsicWidth() {
310: return fobj.getIntrinsicWidth();
311: }
312:
313: /**
314: * Returns the intrinsic height of the e-g.
315: * @return the height of the element
316: */
317: protected int getIntrinsicHeight() {
318: return fobj.getIntrinsicHeight();
319: }
320:
321: }
|