aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert Meyer <rmeyer@apache.org>2013-10-22 10:06:12 +0000
committerRobert Meyer <rmeyer@apache.org>2013-10-22 10:06:12 +0000
commit6c5966390eb0fdeb8c4b7cc5231e6244cdd53512 (patch)
treedd9f9ef2b960968cc28a8b3979e202b8719f7738
parent480edcfb80906fbad780060093c7e943b91f8430 (diff)
downloadxmlgraphics-fop-6c5966390eb0fdeb8c4b7cc5231e6244cdd53512.tar.gz
xmlgraphics-fop-6c5966390eb0fdeb8c4b7cc5231e6244cdd53512.zip
FOP-2104: RTF renderer barfs when fo:table-row is missing inside fo-table-header
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1534582 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--src/java/org/apache/fop/render/rtf/RTFHandler.java42
-rw-r--r--src/java/org/apache/fop/render/rtf/RTFPlaceHolderHelper.java72
-rw-r--r--src/java/org/apache/fop/render/rtf/rtflib/tools/BuilderContext.java71
3 files changed, 166 insertions, 19 deletions
diff --git a/src/java/org/apache/fop/render/rtf/RTFHandler.java b/src/java/org/apache/fop/render/rtf/RTFHandler.java
index dfeff65f1..73fa3504c 100644
--- a/src/java/org/apache/fop/render/rtf/RTFHandler.java
+++ b/src/java/org/apache/fop/render/rtf/RTFHandler.java
@@ -157,6 +157,7 @@ public class RTFHandler extends FOEventHandler {
private PercentContext percentManager = new PercentContext();
+
/**
* Creates a new RTF structure handler.
* @param userAgent the FOUserAgent for this process
@@ -270,7 +271,7 @@ public class RTFHandler extends FOEventHandler {
return;
} else {
- builderContext.popContainer();
+ builderContext.popContainer(RtfSection.class, this);
this.pagemaster = null;
}
}
@@ -377,10 +378,10 @@ public class RTFHandler extends FOEventHandler {
//just do nothing
} else if (regionBefore != null
&& fl.getFlowName().equals(regionBefore.getRegionName())) {
- builderContext.popContainer();
+ builderContext.popContainer(RtfBefore.class, this);
} else if (regionAfter != null
&& fl.getFlowName().equals(regionAfter.getRegionName())) {
- builderContext.popContainer();
+ builderContext.popContainer(RtfAfter.class, this);
}
} catch (Exception e) {
log.error("endFlow: " + e.getMessage());
@@ -571,7 +572,7 @@ public class RTFHandler extends FOEventHandler {
nestedTableDepth--;
builderContext.popTableContext();
- builderContext.popContainer();
+ builderContext.popContainer(RtfTable.class, this);
}
/** {@inheritDoc} */
@@ -605,21 +606,25 @@ public class RTFHandler extends FOEventHandler {
/** {@inheritDoc} */
public void startHeader(TableHeader header) {
+ builderContext.pushPart(header);
startPart(header);
}
/** {@inheritDoc} */
public void endHeader(TableHeader header) {
+ builderContext.popPart(header.getClass(), this);
endPart(header);
}
/** {@inheritDoc} */
public void startFooter(TableFooter footer) {
+ builderContext.pushPart(footer);
startPart(footer);
}
/** {@inheritDoc} */
public void endFooter(TableFooter footer) {
+ builderContext.popPart(footer.getClass(), this);
endPart(footer);
}
@@ -711,11 +716,13 @@ public class RTFHandler extends FOEventHandler {
* {@inheritDoc}
*/
public void startBody(TableBody body) {
+ builderContext.pushPart(body);
startPart(body);
}
/** {@inheritDoc} */
public void endBody(TableBody body) {
+ builderContext.popPart(TableBody.class, this);
endPart(body);
}
@@ -784,7 +791,7 @@ public class RTFHandler extends FOEventHandler {
}
- builderContext.popContainer();
+ builderContext.popContainer(RtfTableRow.class, this);
builderContext.getTableContext().decreaseRowSpannings();
}
@@ -893,7 +900,7 @@ public class RTFHandler extends FOEventHandler {
throw new RuntimeException(e.getMessage());
}
- builderContext.popContainer();
+ builderContext.popContainer(RtfTableCell.class, this);
builderContext.getTableContext().selectNextColumn();
}
@@ -929,7 +936,7 @@ public class RTFHandler extends FOEventHandler {
return;
}
- builderContext.popContainer();
+ builderContext.popContainer(RtfList.class, this);
}
/** {@inheritDoc} */
@@ -976,7 +983,7 @@ public class RTFHandler extends FOEventHandler {
return;
}
- builderContext.popContainer();
+ builderContext.popContainer(RtfListItem.class, this);
}
/** {@inheritDoc} */
@@ -1005,7 +1012,7 @@ public class RTFHandler extends FOEventHandler {
return;
}
- builderContext.popContainer();
+ builderContext.popContainer(RtfListItemLabel.class, this);
}
/** {@inheritDoc} */
@@ -1070,7 +1077,7 @@ public class RTFHandler extends FOEventHandler {
return;
}
- builderContext.popContainer();
+ builderContext.popContainer(RtfHyperLink.class, this);
}
/** {@inheritDoc} */
@@ -1306,7 +1313,7 @@ public class RTFHandler extends FOEventHandler {
return;
}
- builderContext.popContainer();
+ builderContext.popContainer(RtfFootnote.class, this);
}
/** {@inheritDoc} */
@@ -1688,6 +1695,19 @@ public class RTFHandler extends FOEventHandler {
}
/**
+ * Closes any mismatched tags that are detected in the RTF structure.
+ * @param containerClass The class representing the tag to close.
+ * @return Determines whether the tag mismatch has been handled.
+ */
+ public boolean endContainer(Class containerClass) {
+ if (containerClass == RtfTableRow.class) {
+ endRow(null);
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Calls the event handlers for the passed FONode and all its elements.
*
* @param foNode FONode object which shall be recursed
diff --git a/src/java/org/apache/fop/render/rtf/RTFPlaceHolderHelper.java b/src/java/org/apache/fop/render/rtf/RTFPlaceHolderHelper.java
new file mode 100644
index 000000000..c31c68db1
--- /dev/null
+++ b/src/java/org/apache/fop/render/rtf/RTFPlaceHolderHelper.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.render.rtf;
+
+import org.apache.fop.render.rtf.rtflib.exceptions.RtfException;
+import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfAttributes;
+import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfContainer;
+import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfTable;
+import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfTableRow;
+import org.apache.fop.render.rtf.rtflib.tools.BuilderContext;
+
+/**
+ * This class creates objects which are missing from the XSL:FO but are required
+ * by the RTF format.
+ */
+public class RTFPlaceHolderHelper {
+ /** The context object for building the RTF */
+ private BuilderContext builderContext;
+
+ /**
+ * Creates a new instance for the RTF place holder which attempts to resolve
+ * mismatches in structure between XSL:FO and RTF.
+ * @param builderContext The builder context
+ */
+ public RTFPlaceHolderHelper(BuilderContext builderContext) {
+ this.builderContext = builderContext;
+ }
+
+ /**
+ * A method to create an object which is missing and required from the
+ * RTF structure.
+ * @param containerClass The class which is missing
+ * @throws Exception
+ */
+ public void createRTFPlaceholder(Class containerClass) throws RtfException {
+ if (containerClass == RtfTableRow.class) {
+ createRtfTableRow();
+ }
+ }
+
+ private void createRtfTableRow() throws RtfException {
+ try {
+ RtfContainer element = builderContext.getContainer(RtfTable.class, true, null);
+ if (element != null && element instanceof RtfTable) {
+ RtfTable table = (RtfTable)element;
+ RtfAttributes attribs = new RtfAttributes();
+ RtfTableRow newRow = table.newTableRow(attribs);
+ builderContext.pushContainer(newRow);
+ builderContext.getTableContext().selectFirstColumn();
+ }
+ } catch (Exception ex) {
+ throw new RtfException(ex.getMessage());
+ }
+ }
+}
diff --git a/src/java/org/apache/fop/render/rtf/rtflib/tools/BuilderContext.java b/src/java/org/apache/fop/render/rtf/rtflib/tools/BuilderContext.java
index f0a29a0ab..6dcae5412 100644
--- a/src/java/org/apache/fop/render/rtf/rtflib/tools/BuilderContext.java
+++ b/src/java/org/apache/fop/render/rtf/rtflib/tools/BuilderContext.java
@@ -21,6 +21,12 @@ package org.apache.fop.render.rtf.rtflib.tools;
import java.util.Stack;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.fop.fo.FObj;
+import org.apache.fop.render.rtf.RTFHandler;
+import org.apache.fop.render.rtf.RTFPlaceHolderHelper;
import org.apache.fop.render.rtf.rtflib.exceptions.RtfException;
import org.apache.fop.render.rtf.rtflib.rtfdoc.IRtfOptions;
import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfContainer;
@@ -38,6 +44,10 @@ import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfContainer;
*/
public class BuilderContext {
+
+ /** Static logging instance */
+ protected static final Log LOG = LogFactory.getLog(BuilderContext.class.getName());
+
/** stack of RtfContainers */
private final Stack containers = new Stack();
@@ -96,17 +106,22 @@ public class BuilderContext {
* @throws RtfException if not caught
*/
public RtfContainer getContainer(Class containerClass, boolean required,
- Object /*IBuilder*/ forWhichBuilder) throws RtfException {
+ Object forWhichBuilder) throws RtfException {
// TODO what to do if the desired container is not at the top of the stack?
// close top-of-stack container?
- final RtfContainer result = (RtfContainer)getObjectFromStack(containers,
+ RtfContainer result = (RtfContainer)getObjectFromStack(containers,
containerClass);
if (result == null && required) {
- throw new RtfException(
- "No RtfContainer of class '" + containerClass.getName()
- + "' available for '" + forWhichBuilder.getClass().getName() + "' builder"
- );
+ RTFPlaceHolderHelper placeHolderHelper = new RTFPlaceHolderHelper(this);
+ placeHolderHelper.createRTFPlaceholder(containerClass);
+ result = getContainer(containerClass, required, forWhichBuilder);
+ if (result == null) {
+ throw new RtfException(
+ "No RtfContainer of class '" + containerClass.getName()
+ + "' available for '" + forWhichBuilder.getClass().getName() + "' builder"
+ );
+ }
}
return result;
@@ -121,6 +136,14 @@ public class BuilderContext {
}
/**
+ * Push a Class representing a non-writeable section of the FO tree
+ * @param part the part
+ */
+ public void pushPart(FObj part) {
+ containers.push(part);
+ }
+
+ /**
* In some cases an RtfContainer must be replaced by another one on the
* stack. This happens when handling nested fo:blocks for example: after
* handling a nested block the enclosing block must switch to a new
@@ -142,8 +165,40 @@ public class BuilderContext {
}
/** pop the topmost RtfContainer from our stack */
- public void popContainer() {
- containers.pop();
+ public void popContainer(Class containerClass, RTFHandler handler) {
+ handlePop(containerClass, handler);
+ }
+
+ /** pop the topmost part class from our stack */
+ public void popPart(Class part, RTFHandler handler) {
+ handlePop(part, handler);
+ }
+
+ /**
+ * This method checks for any tag mismatches between what is being closed
+ * and what exists on the stack. If a mismatch is found, then it will push
+ * the object back onto the stack and attempt to close the given section
+ * before retrying with the current pop task.
+ * @param aClass The class to be popped from the stack
+ * @param handler The RTF handler class to fix any mismatches
+ */
+ private void handlePop(Class aClass, RTFHandler handler) {
+ Object object = containers.pop();
+ if (object.getClass() != aClass) {
+ pushAndClose(aClass, object, handler);
+ }
+ }
+
+ private void pushAndClose(Class aClass, Object object, RTFHandler handler) {
+ containers.push(object);
+ if (handler.endContainer(object.getClass())) {
+ popContainer(aClass, handler);
+ } else {
+ /* This should never happen unless a placeholder is not catered for
+ * in the RTFHandler.endContainer method. */
+ LOG.warn("Unhandled RTF structure tag mismatch detected between " +
+ aClass.getSimpleName() + " and "+object.getClass().getSimpleName());
+ }
}
/* push an IBuilder to our stack /