From 6b31590493e688b62aadb7a3fdcae7f454109d31 Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Sun, 6 Jul 2008 16:40:08 +0000 Subject: [PATCH] Bugzilla #43825: leader supports fixed percent values for leader-length, most other properties use-content, leader-pattern-width not implemented Submitted by: Maximilan Aster Changes to the patch by Jeremias: - Adjustments for FOP code conventions git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/fop-0_95@674314 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/fop/render/rtf/RTFHandler.java | 24 ++ .../render/rtf/TextAttributesConverter.java | 176 ++++++++++++-- .../render/rtf/rtflib/rtfdoc/RtfLeader.java | 219 ++++++++++++++++++ .../render/rtf/rtflib/rtfdoc/RtfTextrun.java | 9 + status.xml | 4 + 5 files changed, 410 insertions(+), 22 deletions(-) create mode 100644 src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfLeader.java diff --git a/src/java/org/apache/fop/render/rtf/RTFHandler.java b/src/java/org/apache/fop/render/rtf/RTFHandler.java index dd7a9bb3f..d023e1fe4 100644 --- a/src/java/org/apache/fop/render/rtf/RTFHandler.java +++ b/src/java/org/apache/fop/render/rtf/RTFHandler.java @@ -1299,6 +1299,26 @@ public class RTFHandler extends FOEventHandler { /** {@inheritDoc} */ public void leader(Leader l) { + if (bDefer) { + return; + } + + try { + percentManager.setDimension(l); + RtfAttributes rtfAttr = TextAttributesConverter.convertLeaderAttributes( + l, percentManager); + + IRtfTextrunContainer container + = (IRtfTextrunContainer)builderContext.getContainer( + IRtfTextrunContainer.class, true, this); + RtfTextrun textrun = container.getTextrun(); + + textrun.addLeader(rtfAttr); + + } catch (Exception e) { + log.error("startLeader: " + e.getMessage()); + throw new RuntimeException(e.getMessage()); + } } /** @@ -1558,6 +1578,10 @@ public class RTFHandler extends FOEventHandler { } else { endCell( (TableCell) foNode); } + } else if (foNode instanceof Leader) { + if (bStart) { + leader((Leader) foNode); + } } else if (foNode instanceof PageNumberCitation) { if (bStart) { startPageNumberCitation((PageNumberCitation) foNode); diff --git a/src/java/org/apache/fop/render/rtf/TextAttributesConverter.java b/src/java/org/apache/fop/render/rtf/TextAttributesConverter.java index d40c6a826..63c470b5d 100644 --- a/src/java/org/apache/fop/render/rtf/TextAttributesConverter.java +++ b/src/java/org/apache/fop/render/rtf/TextAttributesConverter.java @@ -5,9 +5,9 @@ * 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. @@ -21,25 +21,30 @@ package org.apache.fop.render.rtf; import java.awt.Color; -//FOP +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + import org.apache.fop.apps.FOPException; import org.apache.fop.datatypes.Length; +import org.apache.fop.datatypes.PercentBaseContext; import org.apache.fop.fo.Constants; import org.apache.fop.fo.FONode; import org.apache.fop.fo.FOText; import org.apache.fop.fo.flow.Block; import org.apache.fop.fo.flow.BlockContainer; import org.apache.fop.fo.flow.Inline; +import org.apache.fop.fo.flow.Leader; import org.apache.fop.fo.flow.PageNumber; import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.fo.properties.CommonFont; import org.apache.fop.fo.properties.CommonMarginBlock; import org.apache.fop.fo.properties.CommonTextDecoration; -import org.apache.fop.render.rtf.BorderAttributesConverter; +import org.apache.fop.fo.properties.PercentLength; import org.apache.fop.render.rtf.rtflib.rtfdoc.IBorderAttributes; import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfAttributes; import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfColorTable; import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfFontManager; +import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfLeader; import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfText; /** Converts FO properties to RtfAttributes @@ -52,13 +57,15 @@ import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfText; * @author rmarra */ final class TextAttributesConverter { - + + private static Log log = LogFactory.getLog(TextAttributesConverter.class); + /** * Constructor is private, because it's just a utility class. */ private TextAttributesConverter() { } - + /** * Converts all known text FO properties to RtfAttributes * @param props list of FO properites, which are to be converted @@ -106,7 +113,7 @@ final class TextAttributesConverter { attrBaseLineShift(fobj.getBaseLineShift(), attrib); return attrib; } - + /** * Converts all character related FO properties to RtfAttributes. * @param fobj FObj whose properties are to be converted @@ -137,6 +144,131 @@ final class TextAttributesConverter { return attrib; } + + /** + * Converts FO properties used by RtfLeader to RtfAttributes. + * @param fobj Leader + * @param context PercentBaseContext + * @return RtfAttributes + * @throws FOPException + */ + public static RtfAttributes convertLeaderAttributes(Leader fobj, PercentBaseContext context) + throws FOPException { + boolean tab = false; + FOPRtfAttributes attrib = new FOPRtfAttributes(); + attrib.set(RtfText.ATTR_FONT_FAMILY, + RtfFontManager.getInstance().getFontNumber(fobj.getCommonFont().getFirstFontFamily())); + + if (fobj.getLeaderLength() != null) { + attrib.set(RtfLeader.LEADER_WIDTH, convertMptToTwips(fobj.getLeaderLength().getMaximum( + context).getLength().getValue(context))); + + if (fobj.getLeaderLength().getMaximum(context) instanceof PercentLength) { + if (((PercentLength)fobj.getLeaderLength().getMaximum(context)).getString().equals( + "100.0%")) { + // Use Tab instead of white spaces + attrib.set(RtfLeader.LEADER_USETAB, 1); + tab = true; + } + } + } + + attrFontColor(fobj.getColor(), attrib); + + if (fobj.getLeaderPatternWidth() != null) { + //TODO calculate pattern width not possible for white spaces, because its using + //underlines for tab it would work with LEADER_PATTERN_WIDTH (expndtw) + } + + switch(fobj.getLeaderPattern()) { + case Constants.EN_DOTS: + if (tab) { + attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_TAB_DOTTED); + } else { + attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_DOTTED); + } + break; + case Constants.EN_SPACE: + //nothing has to be set for spaces + break; + case Constants.EN_RULE: + //Things like start-indent, space-after, ... not supported? + //Leader class does not offer these properties + //TODO aggregate them with the leader width or + // create a second - blank leader - before + + if (fobj.getRuleThickness() != null) { + //TODO See inside RtfLeader, better calculation for + //white spaces would be necessary + //attrib.set(RtfLeader.LEADER_RULE_THICKNESS, + // fobj.getRuleThickness().getValue(context)); + log.warn("RTF: fo:leader rule-thickness not supported"); + } + + switch (fobj.getRuleStyle()) { + case Constants.EN_SOLID: + if (tab) { + attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_TAB_THICK); + } else { + attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_THICK); + } + break; + case Constants.EN_DASHED: + if (tab) { + attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_TAB_MIDDLEDOTTED); + } else { + attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_MIDDLEDOTTED); + } + break; + case Constants.EN_DOTTED: + if (tab) { + attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_TAB_DOTTED); + } else { + attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_DOTTED); + } + break; + case Constants.EN_DOUBLE: + if (tab) { + attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_TAB_EQUAL); + } else { + attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_EQUAL); + } + break; + case Constants.EN_GROOVE: + if (tab) { + attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_TAB_HYPHENS); + } else { + attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_HYPHENS); + } + break; + case Constants.EN_RIDGE: + if (tab) { + attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_TAB_UNDERLINE); + } else { + attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_UNDERLINE); + } + break; + default: + break; + } + break; + case Constants.EN_USECONTENT: + log.warn("RTF: fo:leader use-content not supported"); + break; + default: + break; + } + + if (fobj.getLeaderAlignment() == Constants.EN_REFERENCE_AREA) { + log.warn("RTF: fo:leader reference-area not supported"); + } + return attrib; + } + + private static int convertMptToTwips(int mpt) { + return Math.round(FoUnitsConverter.getInstance().convertMptToTwips(mpt)); + } + private static void attrFont(CommonFont font, FOPRtfAttributes rtfAttr) { rtfAttr.set(RtfText.ATTR_FONT_FAMILY, RtfFontManager.getInstance().getFontNumber(font.getFirstFontFamily())); @@ -150,7 +282,7 @@ final class TextAttributesConverter { } else { rtfAttr.set("b", 0); } - + if (font.getFontStyle() == Constants.EN_ITALIC) { rtfAttr.set(RtfText.ATTR_ITALIC, 1); } else { @@ -176,20 +308,20 @@ final class TextAttributesConverter { - private static void attrTextDecoration(CommonTextDecoration textDecoration, + private static void attrTextDecoration(CommonTextDecoration textDecoration, RtfAttributes rtfAttr) { if (textDecoration == null) { rtfAttr.set(RtfText.ATTR_UNDERLINE, 0); rtfAttr.set(RtfText.ATTR_STRIKETHROUGH, 0); return; } - + if (textDecoration.hasUnderline()) { rtfAttr.set(RtfText.ATTR_UNDERLINE, 1); } else { rtfAttr.set(RtfText.ATTR_UNDERLINE, 0); } - + if (textDecoration.hasLineThrough()) { rtfAttr.set(RtfText.ATTR_STRIKETHROUGH, 1); } else { @@ -198,9 +330,9 @@ final class TextAttributesConverter { } private static void attrBlockMargin(CommonMarginBlock cmb, FOPRtfAttributes rtfAttr) { - rtfAttr.setTwips(RtfText.SPACE_BEFORE, + rtfAttr.setTwips(RtfText.SPACE_BEFORE, cmb.spaceBefore.getOptimum(null).getLength()); - rtfAttr.setTwips(RtfText.SPACE_AFTER, + rtfAttr.setTwips(RtfText.SPACE_AFTER, cmb.spaceAfter.getOptimum(null).getLength()); rtfAttr.setTwips(RtfText.LEFT_INDENT_BODY, cmb.startIndent); rtfAttr.setTwips(RtfText.RIGHT_INDENT_BODY, cmb.endIndent); @@ -283,20 +415,20 @@ final class TextAttributesConverter { CommonBorderPaddingBackground commonBorderPaddingBackground = null; if (node instanceof Block) { Block block = (Block) node; - commonBorderPaddingBackground = block.getCommonBorderPaddingBackground(); - } else if (node instanceof BlockContainer) { + commonBorderPaddingBackground = block.getCommonBorderPaddingBackground(); + } else if (node instanceof BlockContainer) { BlockContainer container = (BlockContainer) node; commonBorderPaddingBackground = container.getCommonBorderPaddingBackground(); - } + } - if (commonBorderPaddingBackground != null + if (commonBorderPaddingBackground != null && commonBorderPaddingBackground.hasBorder()) { return true; } node = node.getParent(); } - return false; + return false; } /** Adds inline border information from bpb to rtrAttr. */ @@ -313,7 +445,7 @@ final class TextAttributesConverter { * @param bl the Block object the properties are read from * @param rtfAttr the RtfAttributes object the attributes are written to */ - private static void attrBackgroundColor(CommonBorderPaddingBackground bpb, + private static void attrBackgroundColor(CommonBorderPaddingBackground bpb, RtfAttributes rtfAttr) { Color fopValue = bpb.backgroundColor; int rtfColor = 0; @@ -334,11 +466,11 @@ final class TextAttributesConverter { rtfAttr.set(RtfText.ATTR_BACKGROUND_COLOR, rtfColor); } - + private static void attrBaseLineShift(Length baselineShift, RtfAttributes rtfAttr) { - + int s = baselineShift.getEnum(); - + if (s == Constants.EN_SUPER) { rtfAttr.set(RtfText.ATTR_SUPERSCRIPT); } else if (s == Constants.EN_SUB) { diff --git a/src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfLeader.java b/src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfLeader.java new file mode 100644 index 000000000..b3f11bc0a --- /dev/null +++ b/src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfLeader.java @@ -0,0 +1,219 @@ +/* + * 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.rtflib.rtfdoc; + +import java.io.IOException; +import java.io.Writer; +import java.util.Iterator; + +/** + * Generates the leader in RTF. + */ +public class RtfLeader extends RtfContainer { + + /* + * Format : \tqr \style \tx## { \pard \format \tab } + * ## represents the width \style represents the style (tldot, tlth, ...) + * \format represents standard formats (color, fontsize, ...) + * + * + * \pard \zwnj {\fsxx } \zwnj + * + * : \\ulcN Underline color. \\uld Dotted underline. \\uldash Dashed + * underline. \\uldashd Dash-dotted underline. \\uldashdd Dash-dot-dotted + * underline. \\uldb Double underline. \\ulhwave Heavy wave underline. + * \\ulldash Long dashed underline. \\ulnone Stops all underlining. \\ulth + * Thick underline. \\ulthd Thick dotted underline. \\ulthdash Thick dashed + * underline. \\ulthdashd Thick dash-dotted underline. \\ulthdashdd Thick + * dash-dot-dotted underline. \\ulthldash Thick long dashed underline. + * \\ululdbwave Double wave underline. + */ + + private RtfAttributes attrs = null; + + /** Private attribute: tab style */ + public static final String LEADER_TABLEAD = "tablead"; + + /** Private attribute: tab usage indicator */ + public static final String LEADER_USETAB = "tabuse"; + + /** Private attribute: leader width */ + public static final String LEADER_WIDTH = "lwidth"; + + // +++++++++++++++ Styles Underline ++++++++++++++++++++++ + + /** Dotted underline */ + public static final String LEADER_DOTTED = "uld"; // dotted + + /** Dashed underline */ + public static final String LEADER_MIDDLEDOTTED = "uldash"; // dashed + + /** Heavy wave underline */ + public static final String LEADER_HYPHENS = "ulhwave"; // groove + + /** Dash-dot-dotted underline */ + public static final String LEADER_UNDERLINE = "ulthdashdd"; // ridge + + /** Double underline */ + public static final String LEADER_EQUAL = "uldb"; // double + + /** Thick underline */ + public static final String LEADER_THICK = "ulth"; // solid + + // +++++++++++++++ Styles Tabulator +++++++++++++++++++++++ + + /** Leader dots */ + public static final String LEADER_TAB_DOTTED = "tldot"; // dotted + + /** Leader middle dots */ + public static final String LEADER_TAB_MIDDLEDOTTED = "tlmdot"; // dashed + + /** Leader hyphens */ + public static final String LEADER_TAB_HYPHENS = "tlhyph"; // groove + + /** Leader underline */ + public static final String LEADER_TAB_UNDERLINE = "tlul"; // ridge + + /** Leader equal sign */ + public static final String LEADER_TAB_EQUAL = "tleq"; // double + + /** Leader thick line */ + public static final String LEADER_TAB_THICK = "tlth"; // solid + + // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + /** Resets to default properties */ + public static final String LEADER_IGNORE_STYLE = "pard"; + + /** Font size determines rule thickness */ + public static final String LEADER_RULE_THICKNESS = "fs"; // thickness = fontsize + + /** Expansion or compression of the space between characters in twips */ + public static final String LEADER_PATTERN_WIDTH = "expndtw"; + + /** Zero-width break opportunity */ + public static final String LEADER_ZERO_WIDTH = "zwbo"; + + /** Standard leader width */ + public static final int LEADER_STANDARD_WIDTH = 30; + + /** Move up 4 half-points */ + public static final String LEADER_UP = "up4"; + + /** Negative expansion */ + public static final String LEADER_EXPAND = "expnd-2"; // negative value + // for compression + + /** Tab */ + public static final String LEADER_TAB_VALUE = "tab"; + + /** Right-aligned tab */ + public static final String LEADER_TAB_RIGHT = "tqr"; + + /** Tab width */ + public static final String LEADER_TAB_WIDTH = "tx"; + + RtfLeader(RtfContainer parent, Writer w, RtfAttributes attrs) throws IOException { + super(parent, w); + this.attrs = attrs; + } + + /** {@inheritDoc} */ + protected void writeRtfContent() throws IOException { + + int thickness = LEADER_STANDARD_WIDTH; + String tablead = null; + String tabwidth = null; + for (Iterator it = attrs.nameIterator(); it.hasNext();) { + final String name = (String)it.next(); + if (attrs.isSet(name)) { + if (name.equals(LEADER_TABLEAD)) { + tablead = attrs.getValue(LEADER_TABLEAD).toString(); + } else if (name.equals(LEADER_WIDTH)) { + tabwidth = attrs.getValue(LEADER_WIDTH).toString(); + } + } + } + + if (attrs.getValue(LEADER_RULE_THICKNESS) != null) { + thickness += Integer.parseInt(attrs.getValue(LEADER_RULE_THICKNESS).toString()) + / 1000 * 2; + attrs.unset(LEADER_RULE_THICKNESS); + } + + //Remove private attributes + attrs.unset(LEADER_WIDTH); + attrs.unset(LEADER_TABLEAD); + + // If leader is 100% we use a tabulator, because its more + // comfortable, specially for the table of content + if (attrs.getValue(LEADER_USETAB) != null) { + attrs.unset(LEADER_USETAB); + writeControlWord(LEADER_TAB_RIGHT); + + if (tablead != null) { + writeControlWord(tablead); + } + writeControlWord(LEADER_TAB_WIDTH + tabwidth); + + writeGroupMark(true); + + writeControlWord(LEADER_IGNORE_STYLE); + writeAttributes(attrs, null); + writeControlWord(LEADER_EXPAND); + writeControlWord(LEADER_TAB_VALUE); + + writeGroupMark(false); + + } + // Using white spaces with different underline formats + else { + writeControlWord(LEADER_IGNORE_STYLE); + writeControlWord(LEADER_ZERO_WIDTH); + writeGroupMark(true); + + writeControlWord(LEADER_RULE_THICKNESS + thickness); + + writeControlWord(LEADER_UP); + + super.writeAttributes(attrs, null); + if (tablead != null) { + writeControlWord(tablead); + } + + // Calculation for the necessary amount of white spaces + // Depending on font-size 15 -> 1cm = 7,5 spaces + // TODO for rule-thickness this has to be done better + + for (double d = (Integer.parseInt(tabwidth) / 560) * 7.5; d >= 1; d--) { + RtfStringConverter.getInstance().writeRtfString(writer, " "); + } + + writeGroupMark(false); + writeControlWord(LEADER_ZERO_WIDTH); + } + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return false; + } + +} diff --git a/src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java b/src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java index b0db4576b..49148c407 100644 --- a/src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java +++ b/src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java @@ -248,6 +248,15 @@ public class RtfTextrun extends RtfContainer { } } + /** + * Inserts a leader. + * @param attrs Attributes for the leader + * @throws IOException for I/O problems + */ + public void addLeader(RtfAttributes attrs) throws IOException { + new RtfLeader(this, writer, attrs); + } + /** * Inserts a page number. * @param attr Attributes for the page number to insert. diff --git a/status.xml b/status.xml index 5367daf3f..752e2f1ca 100644 --- a/status.xml +++ b/status.xml @@ -60,6 +60,10 @@ --> + + Added support for fo:leader for RTF output (no full support!). Fixes problems with empty leaders + being used to force empty lines among other issues. + Added support for page-number-citation for RTF output. -- 2.39.5