/**
* Base class for representation of mixed content formatting objects
* and their processing
+ * @todo define what a "mixed content formatting object" is
*/
public class FObjMixed extends FObj {
/** TextInfo for this object */
// XML
import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
import org.xml.sax.SAXParseException;
// FOP
-import org.apache.fop.apps.FOPException;
import org.apache.fop.fo.CharIterator;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.FObjMixed;
import org.apache.fop.fo.InlineCharIterator;
-import org.apache.fop.layoutmgr.AddLMVisitor;
-import org.apache.fop.fo.properties.CommonAccessibility;
-import org.apache.fop.fo.properties.CommonAural;
-import org.apache.fop.fo.properties.CommonBackground;
-import org.apache.fop.fo.properties.CommonBorderAndPadding;
-import org.apache.fop.fo.properties.CommonMarginInline;
-import org.apache.fop.fo.properties.CommonRelativePosition;
/**
- * Class modelling the fo:inline object. See Sec. 6.6.7 of the XSL-FO Standard.
+ * Class modelling the fo:inline formatting object.
*/
public class Inline extends FObjMixed {
- // Textdecoration
- /** is this text underlined? */
- protected boolean underlined = false;
- /** is this text overlined? */
- protected boolean overlined = false;
- /** is this text lined through? */
- protected boolean lineThrough = false;
+ // used for FO validation
+ private boolean blockOrInlineItemFound = false;
+ private boolean canHaveBlockLevelChildren = true;
/**
* @param parent FONode that is the parent of this object
protected void addProperties(Attributes attlist) throws SAXParseException {
super.addProperties(attlist);
- if (parent.getName().equals("fo:flow")) {
- throw new SAXParseException("inline formatting objects cannot"
- + " be directly under flow", locator);
- }
-
- int textDecoration = this.propertyList.get(PR_TEXT_DECORATION).getEnum();
-
- if (textDecoration == TextDecoration.UNDERLINE) {
- this.underlined = true;
- }
+ /* Check to see if this node can have block-level children.
+ * See validateChildNode() below.
+ */
+ int lvlLeader = findAncestor("fo:leader");
+ int lvlFootnote = findAncestor("fo:footnote");
+ int lvlInCntr = findAncestor("fo:inline-container");
+
+ if (lvlLeader > 0) {
+ if (lvlInCntr < 0 ||
+ (lvlInCntr > 0 && lvlInCntr > lvlLeader)) {
+ canHaveBlockLevelChildren = false;
+ }
+ } else if (lvlFootnote > 0) {
+ if (lvlInCntr < 0 || lvlInCntr > lvlFootnote) {
+ canHaveBlockLevelChildren = false;
+ }
+ }
- if (textDecoration == TextDecoration.OVERLINE) {
- this.overlined = true;
- }
+ getFOInputHandler().startInline(this);
+ }
- if (textDecoration == TextDecoration.LINE_THROUGH) {
- this.lineThrough = true;
+ /**
+ * @see org.apache.fop.fo.FONode#validateChildNode(Locator, String, String)
+ * XSL Content Model: marker* (#PCDATA|%inline;|%block;)*
+ * Additionally: " An fo:inline that is a descendant of an fo:leader
+ * or fo:footnote may not have block-level children, unless it has a
+ * nearer ancestor that is an fo:inline-container." (paraphrased)
+ */
+ protected void validateChildNode(Locator loc, String nsURI, String localName)
+ throws SAXParseException {
+ if (nsURI == FO_URI && localName.equals("marker")) {
+ if (blockOrInlineItemFound) {
+ nodesOutOfOrderError(loc, "fo:marker",
+ "(#PCDATA|%inline;|%block;)");
+ }
+ } else if (!isBlockOrInlineItem(nsURI, localName)) {
+ invalidChildError(loc, nsURI, localName);
+ } else if (!canHaveBlockLevelChildren && isBlockItem(nsURI, localName)) {
+ String ruleViolated =
+ " An fo:inline that is a descendant of an fo:leader" +
+ " or fo:footnote may not have block-level children," +
+ " unless it has a nearer ancestor that is an" +
+ " fo:inline-container.";
+ invalidChildError(loc, nsURI, localName, ruleViolated);
+ } else {
+ blockOrInlineItemFound = true;
}
-
- getFOInputHandler().startInline(this);
}
+
/**
* @see org.apache.fop.fo.FONode#end
*/
return new InlineCharIterator(this, propMgr.getBorderAndPadding());
}
+ /**
+ * @see org.apache.fop.fo.FObj#getName()
+ */
public String getName() {
return "fo:inline";
}
package org.apache.fop.fo.flow;
+// Java
+import java.util.List;
+
// XML
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
// FOP
import org.apache.fop.fo.FONode;
-import org.apache.fop.fo.LMVisited;
-import org.apache.fop.layoutmgr.AddLMVisitor;
+import org.apache.fop.layoutmgr.InstreamForeignObjectLM;
import org.apache.fop.fo.FObj;
/**
* This is an atomic inline object that contains
* xml data.
*/
-public class InstreamForeignObject extends FObj implements LMVisited {
+public class InstreamForeignObject extends FObj {
boolean hasNonXSLNamespaceElement = false;
}
/**
- * This is a hook for the AddLMVisitor class to be able to access
- * this object.
- * @param aLMV the AddLMVisitor object that can access this object.
+ * @see org.apache.fop.fo.FObj#addLayoutManager(List)
*/
- public void acceptVisitor(AddLMVisitor aLMV) {
- aLMV.serveInstreamForeignObject(this);
+ public void addLayoutManager(List list) {
+ InstreamForeignObjectLM lm = new InstreamForeignObjectLM(this);
+ list.add(lm);
}
+ /**
+ * @see org.apache.fop.fo.FObj#getName()
+ */
public String getName() {
return "fo:instream-foreign-object";
}
/* $Id$ */
-
package org.apache.fop.layoutmgr;
-import java.awt.geom.Point2D;
-import java.awt.geom.Rectangle2D;
import java.util.List;
import java.util.ListIterator;
import org.apache.fop.area.Trait;
import org.apache.fop.area.inline.FilledArea;
-import org.apache.fop.area.inline.ForeignObject;
import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.area.inline.Space;
-import org.apache.fop.area.inline.Viewport;
import org.apache.fop.area.inline.TextArea;
import org.apache.fop.datatypes.Length;
import org.apache.fop.fo.Constants;
-import org.apache.fop.fo.FONode;
import org.apache.fop.fo.FObj;
-import org.apache.fop.fo.XMLObj;
-import org.apache.fop.fo.flow.Block;
import org.apache.fop.fo.flow.Inline;
-import org.apache.fop.fo.flow.InstreamForeignObject;
import org.apache.fop.fo.flow.Leader;
import org.apache.fop.fo.flow.Wrapper;
import org.apache.fop.traits.MinOptMax;
}
return leaderArea;
}
-
- public void serveInstreamForeignObject(InstreamForeignObject node) {
- Viewport areaCurrent = getInstreamForeignObjectInlineArea(node);
- if (areaCurrent != null) {
- LeafNodeLayoutManager lm = new LeafNodeLayoutManager(node);
- lm.setCurrentArea(areaCurrent);
- lm.setAlignment(node.getProperty(Constants.PR_VERTICAL_ALIGN).getEnum());
- lm.setLead(areaCurrent.getHeight());
- currentLMList.add(lm);
- }
- }
- /**
- * Get the inline area created by this element.
- *
- * @return the viewport inline area
- */
- public Viewport getInstreamForeignObjectInlineArea(InstreamForeignObject node) {
- if (node.getChildNodes() == null) {
- return null;
- }
-
- if (node.childNodes.size() != 1) {
- // error
- return null;
- }
- FONode fo = (FONode) node.childNodes.get(0);
- if (!(fo instanceof XMLObj)) {
- // error
- return null;
- }
- XMLObj child = (XMLObj)fo;
-
- // viewport size is determined by block-progression-dimension
- // and inline-progression-dimension
-
- // if replaced then use height then ignore block-progression-dimension
- //int h = this.propertyList.get("height").getLength().mvalue();
-
- // use specified line-height then ignore dimension in height direction
- boolean hasLH = false;//propertyList.get("line-height").getSpecifiedValue() != null;
-
- Length len;
-
- int bpd = -1;
- int ipd = -1;
- boolean bpdauto = false;
- if (hasLH) {
- bpd = node.getProperty(Constants.PR_LINE_HEIGHT).getLength().getValue();
- } else {
- // this property does not apply when the line-height applies
- // isn't the block-progression-dimension always in the same
- // direction as the line height?
- len = node.getProperty(Constants.PR_BLOCK_PROGRESSION_DIMENSION | Constants.CP_OPTIMUM).getLength();
- if (!len.isAuto()) {
- bpd = len.getValue();
- } else {
- len = node.getProperty(Constants.PR_HEIGHT).getLength();
- if (!len.isAuto()) {
- bpd = len.getValue();
- }
- }
- }
-
- len = node.getProperty(Constants.PR_INLINE_PROGRESSION_DIMENSION | Constants.CP_OPTIMUM).getLength();
- if (!len.isAuto()) {
- ipd = len.getValue();
- } else {
- len = node.getProperty(Constants.PR_WIDTH).getLength();
- if (!len.isAuto()) {
- ipd = len.getValue();
- }
- }
-
- // if auto then use the intrinsic size of the content scaled
- // to the content-height and content-width
- int cwidth = -1;
- int cheight = -1;
- len = node.getProperty(Constants.PR_CONTENT_WIDTH).getLength();
- if (!len.isAuto()) {
- /*if(len.scaleToFit()) {
- if(ipd != -1) {
- cwidth = ipd;
- }
- } else {*/
- cwidth = len.getValue();
- }
- len = node.getProperty(Constants.PR_CONTENT_HEIGHT).getLength();
- if (!len.isAuto()) {
- /*if(len.scaleToFit()) {
- if(bpd != -1) {
- cwidth = bpd;
- }
- } else {*/
- cheight = len.getValue();
- }
-
- Point2D csize = new Point2D.Float(cwidth == -1 ? -1 : cwidth / 1000f,
- cheight == -1 ? -1 : cheight / 1000f);
- Point2D size = child.getDimension(csize);
- if (size == null) {
- // error
- return null;
- }
- if (cwidth == -1) {
- cwidth = (int)size.getX() * 1000;
- }
- if (cheight == -1) {
- cheight = (int)size.getY() * 1000;
- }
- int scaling = node.getProperty(Constants.PR_SCALING).getEnum();
- if (scaling == Constants.Scaling.UNIFORM) {
- // adjust the larger
- double rat1 = cwidth / (size.getX() * 1000f);
- double rat2 = cheight / (size.getY() * 1000f);
- if (rat1 < rat2) {
- // reduce cheight
- cheight = (int)(rat1 * size.getY() * 1000);
- } else {
- cwidth = (int)(rat2 * size.getX() * 1000);
- }
- }
-
- if (ipd == -1) {
- ipd = cwidth;
- }
- if (bpd == -1) {
- bpd = cheight;
- }
-
- boolean clip = false;
- if (cwidth > ipd || cheight > bpd) {
- int overflow = node.getProperty(Constants.PR_OVERFLOW).getEnum();
- if (overflow == Constants.Overflow.HIDDEN) {
- clip = true;
- } else if (overflow == Constants.Overflow.ERROR_IF_OVERFLOW) {
- node.getLogger().error("Instream foreign object overflows the viewport: clipping");
- clip = true;
- }
- }
-
- int xoffset = node.computeXOffset(ipd, cwidth);
- int yoffset = node.computeYOffset(bpd, cheight);
-
- Rectangle2D placement = new Rectangle2D.Float(xoffset, yoffset, cwidth, cheight);
-
- org.w3c.dom.Document doc = child.getDOMDocument();
- String ns = child.getDocumentNamespace();
-
- node.childNodes = null;
- ForeignObject foreign = new ForeignObject(doc, ns);
-
- Viewport areaCurrent = new Viewport(foreign);
- areaCurrent.setWidth(ipd);
- areaCurrent.setHeight(bpd);
- areaCurrent.setContentPosition(placement);
- areaCurrent.setClip(clip);
- areaCurrent.setOffset(0);
-
- return areaCurrent;
- }
}
--- /dev/null
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.layoutmgr;
+
+// Java
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+// FOP
+import org.apache.fop.datatypes.Length;
+import org.apache.fop.fo.XMLObj;
+import org.apache.fop.fo.flow.InstreamForeignObject;
+import org.apache.fop.area.inline.ForeignObject;
+import org.apache.fop.area.inline.InlineArea;
+import org.apache.fop.area.inline.Viewport;
+
+/**
+ * LayoutManager for the fo:basic-link formatting object
+ */
+public class InstreamForeignObjectLM extends LeafNodeLayoutManager {
+
+ InstreamForeignObject ifoNode;
+
+ /**
+ * Constructor
+ * @param node the formatting object that creates this area
+ */
+ public InstreamForeignObjectLM(InstreamForeignObject node) {
+ super(node);
+ ifoNode = node;
+ Viewport areaCurrent = getInlineArea();
+ setCurrentArea(areaCurrent);
+ setAlignment(node.getProperty(PR_VERTICAL_ALIGN).getEnum());
+ setLead(areaCurrent.getHeight());
+ }
+
+ /**
+ * Get the inline area created by this element.
+ *
+ * @return the viewport inline area
+ */
+ private Viewport getInlineArea() {
+ XMLObj child = (XMLObj) ifoNode.childNodes.get(0);
+
+ // viewport size is determined by block-progression-dimension
+ // and inline-progression-dimension
+
+ // if replaced then use height then ignore block-progression-dimension
+ //int h = this.propertyList.get("height").getLength().mvalue();
+
+ // use specified line-height then ignore dimension in height direction
+ boolean hasLH = false;//propertyList.get("line-height").getSpecifiedValue() != null;
+
+ Length len;
+
+ int bpd = -1;
+ int ipd = -1;
+ boolean bpdauto = false;
+ if (hasLH) {
+ bpd = ifoNode.getProperty(PR_LINE_HEIGHT).getLength().getValue();
+ } else {
+ // this property does not apply when the line-height applies
+ // isn't the block-progression-dimension always in the same
+ // direction as the line height?
+ len = ifoNode.getProperty(PR_BLOCK_PROGRESSION_DIMENSION | CP_OPTIMUM).getLength();
+ if (!len.isAuto()) {
+ bpd = len.getValue();
+ } else {
+ len = ifoNode.getProperty(PR_HEIGHT).getLength();
+ if (!len.isAuto()) {
+ bpd = len.getValue();
+ }
+ }
+ }
+
+ len = ifoNode.getProperty(PR_INLINE_PROGRESSION_DIMENSION | CP_OPTIMUM).getLength();
+ if (!len.isAuto()) {
+ ipd = len.getValue();
+ } else {
+ len = ifoNode.getProperty(PR_WIDTH).getLength();
+ if (!len.isAuto()) {
+ ipd = len.getValue();
+ }
+ }
+
+ // if auto then use the intrinsic size of the content scaled
+ // to the content-height and content-width
+ int cwidth = -1;
+ int cheight = -1;
+ len = ifoNode.getProperty(PR_CONTENT_WIDTH).getLength();
+ if (!len.isAuto()) {
+ /*if(len.scaleToFit()) {
+ if(ipd != -1) {
+ cwidth = ipd;
+ }
+ } else {*/
+ cwidth = len.getValue();
+ }
+ len = ifoNode.getProperty(PR_CONTENT_HEIGHT).getLength();
+ if (!len.isAuto()) {
+ /*if(len.scaleToFit()) {
+ if(bpd != -1) {
+ cwidth = bpd;
+ }
+ } else {*/
+ cheight = len.getValue();
+ }
+
+ Point2D csize = new Point2D.Float(cwidth == -1 ? -1 : cwidth / 1000f,
+ cheight == -1 ? -1 : cheight / 1000f);
+ Point2D size = child.getDimension(csize);
+ if (size == null) {
+ // error
+ return null;
+ }
+ if (cwidth == -1) {
+ cwidth = (int)size.getX() * 1000;
+ }
+ if (cheight == -1) {
+ cheight = (int)size.getY() * 1000;
+ }
+ int scaling = ifoNode.getProperty(PR_SCALING).getEnum();
+ if (scaling == Scaling.UNIFORM) {
+ // adjust the larger
+ double rat1 = cwidth / (size.getX() * 1000f);
+ double rat2 = cheight / (size.getY() * 1000f);
+ if (rat1 < rat2) {
+ // reduce cheight
+ cheight = (int)(rat1 * size.getY() * 1000);
+ } else {
+ cwidth = (int)(rat2 * size.getX() * 1000);
+ }
+ }
+
+ if (ipd == -1) {
+ ipd = cwidth;
+ }
+ if (bpd == -1) {
+ bpd = cheight;
+ }
+
+ boolean clip = false;
+ if (cwidth > ipd || cheight > bpd) {
+ int overflow = ifoNode.getProperty(PR_OVERFLOW).getEnum();
+ if (overflow == Overflow.HIDDEN) {
+ clip = true;
+ } else if (overflow == Overflow.ERROR_IF_OVERFLOW) {
+ ifoNode.getLogger().error("Instream foreign object overflows the viewport: clipping");
+ clip = true;
+ }
+ }
+
+ int xoffset = ifoNode.computeXOffset(ipd, cwidth);
+ int yoffset = ifoNode.computeYOffset(bpd, cheight);
+
+ Rectangle2D placement = new Rectangle2D.Float(xoffset, yoffset, cwidth, cheight);
+
+ org.w3c.dom.Document doc = child.getDOMDocument();
+ String ns = child.getDocumentNamespace();
+
+ ifoNode.childNodes = null;
+ ForeignObject foreign = new ForeignObject(doc, ns);
+
+ Viewport areaCurrent = new Viewport(foreign);
+ areaCurrent.setWidth(ipd);
+ areaCurrent.setHeight(bpd);
+ areaCurrent.setContentPosition(placement);
+ areaCurrent.setClip(clip);
+ areaCurrent.setOffset(0);
+
+ return areaCurrent;
+ }
+}
+