/*
 * 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: TextAttributesConverter.java 1822095 2018-01-24 11:53:32Z ssteiner $ */

package org.apache.fop.render.rtf;

import java.awt.Color;

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.flow.table.TableCell;
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.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.

This work was authored by Bertrand Delacretaz (bdelacretaz@codeconsult.ch), Boris Poudérous (boris.pouderous@eads-telecom.com), Peter Herweg (pherweg@web.de), Normand Massé, Christopher Scott (scottc@westinghouse.com), and Roberto Marra (roberto@link-u.com).

/** * <p>Converts FO properties to RtfAttributes.</p> * * <p>This work was authored by Bertrand Delacretaz (bdelacretaz@codeconsult.ch), * Boris Poudérous (boris.pouderous@eads-telecom.com), * Peter Herweg (pherweg@web.de), * Normand Massé, * Christopher Scott (scottc@westinghouse.com), and * Roberto Marra (roberto@link-u.com).</p> */
final class TextAttributesConverter { private static Log log = LogFactory.getLog(TextAttributesConverter.class);
Constructor is private, because it's just a utility class.
/** * Constructor is private, because it's just a utility class. */
private TextAttributesConverter() { }
Converts all known text FO properties to RtfAttributes
Params:
  • fobj – the FO for which the attributes are to be converted
/** * Converts all known text FO properties to RtfAttributes * @param fobj the FO for which the attributes are to be converted */
public static RtfAttributes convertAttributes(Block fobj) throws FOPException { FOPRtfAttributes attrib = new FOPRtfAttributes(); attrFont(fobj.getCommonFont(), attrib); attrFontColor(fobj.getColor(), attrib); //attrTextDecoration(fobj.getTextDecoration(), attrib); attrBlockBackgroundColor(fobj.getCommonBorderPaddingBackground(), attrib); attrBlockMargin(fobj.getCommonMarginBlock(), attrib); attrBlockTextAlign(fobj.getTextAlign(), attrib); attrBorder(fobj.getCommonBorderPaddingBackground(), attrib, fobj); attrBreak(fobj, attrib); attrBlockTextIndent(fobj.getTextIndent(), attrib); return attrib; } private static void attrBreak(Block fobj, FOPRtfAttributes attrib) { int breakValue = fobj.getBreakBefore(); if (breakValue != Constants.EN_AUTO) { //"sect" Creates a new section and a page break, //a simple page break with control word "page" caused //some problems boolean bHasTableCellParent = false; FONode f = fobj; while (f.getParent() != null) { f = f.getParent(); if (f instanceof TableCell) { bHasTableCellParent = true; break; } } if (!bHasTableCellParent) { attrib.set("sect"); switch (breakValue) { case Constants.EN_EVEN_PAGE: attrib.set("sbkeven"); break; case Constants.EN_ODD_PAGE: attrib.set("sbkodd"); break; case Constants.EN_COLUMN: attrib.set("sbkcol"); break; default: attrib.set("sbkpage"); } } else { log.warn("Cannot create break-before for a block inside a table."); } } //Break after is handled in RtfCloseGroupMark }
Converts all known text FO properties to RtfAttributes
Params:
  • fobj – FObj whose properties are to be converted
/** * Converts all known text FO properties to RtfAttributes * @param fobj FObj whose properties are to be converted */
public static RtfAttributes convertBlockContainerAttributes(BlockContainer fobj) throws FOPException { FOPRtfAttributes attrib = new FOPRtfAttributes(); attrBackgroundColor(fobj.getCommonBorderPaddingBackground(), attrib); attrBlockMargin(fobj.getCommonMarginBlock(), attrib); //attrBlockDimension(fobj, attrib); attrBorder(fobj.getCommonBorderPaddingBackground(), attrib, fobj); return attrib; }
Converts all character related FO properties to RtfAttributes.
Params:
  • fobj – FObj whose properties are to be converted
/** * Converts all character related FO properties to RtfAttributes. * @param fobj FObj whose properties are to be converted */
public static RtfAttributes convertCharacterAttributes( FOText fobj) throws FOPException { FOPRtfAttributes attrib = new FOPRtfAttributes(); attrFont(fobj.getCommonFont(), attrib); attrFontColor(fobj.getColor(), attrib); attrTextDecoration(fobj.getTextDecoration(), attrib); attrBaseLineShift(fobj.getBaseLineShift(), attrib); return attrib; }
Converts all character related FO properties to RtfAttributes.
Params:
  • fobj – FObj whose properties are to be converted
/** * Converts all character related FO properties to RtfAttributes. * @param fobj FObj whose properties are to be converted */
public static RtfAttributes convertCharacterAttributes( PageNumber fobj) throws FOPException { FOPRtfAttributes attrib = new FOPRtfAttributes(); attrFont(fobj.getCommonFont(), attrib); attrTextDecoration(fobj.getTextDecoration(), attrib); attrBackgroundColor(fobj.getCommonBorderPaddingBackground(), attrib); return attrib; }
Converts all character related FO properties to RtfAttributes.
Params:
  • fobj – FObj whose properties are to be converted
/** * Converts all character related FO properties to RtfAttributes. * @param fobj FObj whose properties are to be converted */
public static RtfAttributes convertCharacterAttributes( Inline fobj) throws FOPException { FOPRtfAttributes attrib = new FOPRtfAttributes(); attrFont(fobj.getCommonFont(), attrib); attrFontColor(fobj.getColor(), attrib); attrBackgroundColor(fobj.getCommonBorderPaddingBackground(), attrib); attrInlineBorder(fobj.getCommonBorderPaddingBackground(), attrib); return attrib; }
Converts FO properties used by RtfLeader to RtfAttributes.
Params:
  • fobj – Leader
  • context – PercentBaseContext
Throws:
Returns:RtfAttributes
/** * 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())); rtfAttr.setHalfPoints(RtfText.ATTR_FONT_SIZE, font.fontSize); if (font.getFontWeight() == Constants.EN_700 || font.getFontWeight() == Constants.EN_800 || font.getFontWeight() == Constants.EN_900) { //Everything from 700 and above is declared as bold rtfAttr.set("b", 1); } else { rtfAttr.set("b", 0); } if (font.getFontStyle() == Constants.EN_ITALIC) { rtfAttr.set(RtfText.ATTR_ITALIC, 1); } else { rtfAttr.set(RtfText.ATTR_ITALIC, 0); } } private static void attrFontColor(Color colorType, RtfAttributes rtfAttr) { // Cell background color if (colorType != null) { if (colorType.getAlpha() != 0 || colorType.getRed() != 0 || colorType.getGreen() != 0 || colorType.getBlue() != 0) { rtfAttr.set(RtfText.ATTR_FONT_COLOR, convertFOPColorToRTF(colorType)); } } } 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 { rtfAttr.set(RtfText.ATTR_STRIKETHROUGH, 0); } } private static void attrBlockMargin(CommonMarginBlock cmb, FOPRtfAttributes rtfAttr) { rtfAttr.setTwips(RtfText.SPACE_BEFORE, cmb.spaceBefore.getOptimum(null).getLength()); 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); } private static void attrBlockTextIndent(Length textIndent, FOPRtfAttributes rtfAttr) { rtfAttr.setTwips(RtfText.LEFT_INDENT_FIRST, textIndent.getValue()); } /* private static void attrBlockDimension(FObj fobj, FOPRtfAttributes rtfAttr) { Length ipd = fobj.getProperty(Constants.PR_INLINE_PROGRESSION_DIMENSION) .getLengthRange().getOptimum().getLength(); if (ipd.getEnum() != Constants.EN_AUTO) { rtfAttr.set(RtfText.FRAME_WIDTH, ipd); } Length bpd = fobj.getProperty(Constants.PR_BLOCK_PROGRESSION_DIMENSION) .getLengthRange().getOptimum().getLength(); if (bpd.getEnum() != Constants.EN_AUTO) { rtfAttr.set(RtfText.FRAME_HEIGHT, bpd); } } */ private static void attrBlockTextAlign(int alignment, RtfAttributes rtfAttr) { String rtfValue = null; switch (alignment) { case Constants.EN_CENTER: rtfValue = RtfText.ALIGN_CENTER; break; case Constants.EN_END: rtfValue = RtfText.ALIGN_RIGHT; break; case Constants.EN_JUSTIFY: rtfValue = RtfText.ALIGN_JUSTIFIED; break; default: rtfValue = RtfText.ALIGN_LEFT; break; } rtfAttr.set(rtfValue); }
Reads background-color for block from bpb and writes it to rtfAttr.
/** * Reads background-color for block from <code>bpb</code> and writes it to * <code>rtfAttr</code>. */
private static void attrBlockBackgroundColor( CommonBorderPaddingBackground bpb, RtfAttributes rtfAttr) { if (bpb.hasBackground()) { rtfAttr.set(RtfText.SHADING, RtfText.FULL_SHADING); rtfAttr.set(RtfText.SHADING_FRONT_COLOR, convertFOPColorToRTF(bpb.backgroundColor)); } }
Adds border information from bpb to rtrAttr.
/** Adds border information from <code>bpb</code> to <code>rtrAttr</code>. */
private static void attrBorder(CommonBorderPaddingBackground bpb, RtfAttributes rtfAttr, FONode fobj) { if (hasBorder(fobj.getParent())) { attrInlineBorder(bpb, rtfAttr); return; } BorderAttributesConverter.makeBorder(bpb, CommonBorderPaddingBackground.BEFORE, rtfAttr, IBorderAttributes.BORDER_TOP); BorderAttributesConverter.makeBorder(bpb, CommonBorderPaddingBackground.AFTER, rtfAttr, IBorderAttributes.BORDER_BOTTOM); BorderAttributesConverter.makeBorder(bpb, CommonBorderPaddingBackground.START, rtfAttr, IBorderAttributes.BORDER_LEFT); BorderAttributesConverter.makeBorder(bpb, CommonBorderPaddingBackground.END, rtfAttr, IBorderAttributes.BORDER_RIGHT); }
Returns:true, if element node has border.
/** @return true, if element <code>node</code> has border. */
private static boolean hasBorder(FONode node) { while (node != null) { CommonBorderPaddingBackground commonBorderPaddingBackground = null; if (node instanceof Block) { Block block = (Block) node; commonBorderPaddingBackground = block.getCommonBorderPaddingBackground(); } else if (node instanceof BlockContainer) { BlockContainer container = (BlockContainer) node; commonBorderPaddingBackground = container.getCommonBorderPaddingBackground(); } if (commonBorderPaddingBackground != null && commonBorderPaddingBackground.hasBorder()) { return true; } node = node.getParent(); } return false; }
Adds inline border information from bpb to rtrAttr.
/** Adds inline border information from <code>bpb</code> to <code>rtrAttr</code>. */
private static void attrInlineBorder(CommonBorderPaddingBackground bpb, RtfAttributes rtfAttr) { BorderAttributesConverter.makeBorder(bpb, CommonBorderPaddingBackground.BEFORE, rtfAttr, IBorderAttributes.BORDER_CHARACTER); }
Reads background-color from bl and writes it to rtfAttr.
Params:
  • bpb – the CommonBorderPaddingBackground from which the properties are read
  • rtfAttr – the RtfAttributes object the attributes are written to
/** * Reads background-color from bl and writes it to rtfAttr. * * @param bpb the CommonBorderPaddingBackground from which the properties are read * @param rtfAttr the RtfAttributes object the attributes are written to */
private static void attrBackgroundColor(CommonBorderPaddingBackground bpb, RtfAttributes rtfAttr) { Color fopValue = bpb.backgroundColor; int rtfColor = 0; /* FOP uses a default background color of "transparent", which is actually a transparent black, which is generally not suitable as a default here. Changing FOP's default to "white" causes problems in PDF output, so we will look for the default here & change it to "auto". */ if ((fopValue == null) || ((fopValue.getRed() == 0) && (fopValue.getGreen() == 0) && (fopValue.getBlue() == 0) && (fopValue.getAlpha() == 0))) { return; } else { rtfColor = convertFOPColorToRTF(fopValue); } 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) { rtfAttr.set(RtfText.ATTR_SUBSCRIPT); } }
Converts a FOP ColorType to the integer pointing into the RTF color table
Params:
  • fopColor – the ColorType object to be converted
Returns:integer pointing into the RTF color table
/** * Converts a FOP ColorType to the integer pointing into the RTF color table * @param fopColor the ColorType object to be converted * @return integer pointing into the RTF color table */
public static int convertFOPColorToRTF(Color fopColor) { // TODO: This code is duplicated in FOPRtfAttributesConverter int redComponent = fopColor.getRed(); int greenComponent = fopColor.getGreen(); int blueComponent = fopColor.getBlue(); return RtfColorTable.getInstance().getColorNumber(redComponent, greenComponent, blueComponent); } }