From 09a6084a3915ca1786610bb524105c711fac0a5d Mon Sep 17 00:00:00 2001 From: Glen Mazza Date: Sat, 14 Aug 2004 18:36:21 +0000 Subject: [PATCH] 1.) fo:Instream-Foreign-Object initialization logic moved from AddLMVisitor to flow.InstreamForiegnObject.java, and the layout logic itself moved to a new layoutmgr.InstreamForeignObjectLM.java. (Broke with usual nomenclature of adding ~LayoutManager to end, given that newer 1.1 and post-1.1 FO names are getting even larger.) 2.) validateChildNode() added for fo:inline. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@197871 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/fo/FObjMixed.java | 1 + src/java/org/apache/fop/fo/flow/Inline.java | 86 +++++--- .../fop/fo/flow/InstreamForeignObject.java | 20 +- .../apache/fop/layoutmgr/AddLMVisitor.java | 169 ---------------- .../layoutmgr/InstreamForeignObjectLM.java | 190 ++++++++++++++++++ 5 files changed, 256 insertions(+), 210 deletions(-) create mode 100644 src/java/org/apache/fop/layoutmgr/InstreamForeignObjectLM.java diff --git a/src/java/org/apache/fop/fo/FObjMixed.java b/src/java/org/apache/fop/fo/FObjMixed.java index d5d272f6e..902bd3457 100644 --- a/src/java/org/apache/fop/fo/FObjMixed.java +++ b/src/java/org/apache/fop/fo/FObjMixed.java @@ -26,6 +26,7 @@ import org.apache.fop.layoutmgr.InlineStackingLayoutManager; /** * 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 */ diff --git a/src/java/org/apache/fop/fo/flow/Inline.java b/src/java/org/apache/fop/fo/flow/Inline.java index 4e97670dc..5df8b7573 100644 --- a/src/java/org/apache/fop/fo/flow/Inline.java +++ b/src/java/org/apache/fop/fo/flow/Inline.java @@ -20,34 +20,23 @@ package org.apache.fop.fo.flow; // 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 @@ -62,28 +51,56 @@ public class Inline extends FObjMixed { 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 */ @@ -98,6 +115,9 @@ public class Inline extends FObjMixed { return new InlineCharIterator(this, propMgr.getBorderAndPadding()); } + /** + * @see org.apache.fop.fo.FObj#getName() + */ public String getName() { return "fo:inline"; } diff --git a/src/java/org/apache/fop/fo/flow/InstreamForeignObject.java b/src/java/org/apache/fop/fo/flow/InstreamForeignObject.java index f11a7ece3..5c7264aa4 100644 --- a/src/java/org/apache/fop/fo/flow/InstreamForeignObject.java +++ b/src/java/org/apache/fop/fo/flow/InstreamForeignObject.java @@ -18,6 +18,9 @@ package org.apache.fop.fo.flow; +// Java +import java.util.List; + // XML import org.xml.sax.Attributes; import org.xml.sax.Locator; @@ -25,8 +28,7 @@ import org.xml.sax.SAXParseException; // 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; /** @@ -34,7 +36,7 @@ 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; @@ -121,14 +123,16 @@ public class InstreamForeignObject extends FObj implements LMVisited { } /** - * 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"; } diff --git a/src/java/org/apache/fop/layoutmgr/AddLMVisitor.java b/src/java/org/apache/fop/layoutmgr/AddLMVisitor.java index 0373fd170..fd2d684fa 100644 --- a/src/java/org/apache/fop/layoutmgr/AddLMVisitor.java +++ b/src/java/org/apache/fop/layoutmgr/AddLMVisitor.java @@ -16,29 +16,20 @@ /* $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; @@ -209,164 +200,4 @@ public class AddLMVisitor { } 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; - } } diff --git a/src/java/org/apache/fop/layoutmgr/InstreamForeignObjectLM.java b/src/java/org/apache/fop/layoutmgr/InstreamForeignObjectLM.java new file mode 100644 index 000000000..eb582e313 --- /dev/null +++ b/src/java/org/apache/fop/layoutmgr/InstreamForeignObjectLM.java @@ -0,0 +1,190 @@ +/* + * 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; + } +} + -- 2.39.5