You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TextAttributesConverter.java 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /* $Id$ */
  18. package org.apache.fop.render.rtf;
  19. import java.awt.Color;
  20. import org.apache.commons.logging.Log;
  21. import org.apache.commons.logging.LogFactory;
  22. import org.apache.fop.apps.FOPException;
  23. import org.apache.fop.datatypes.Length;
  24. import org.apache.fop.datatypes.PercentBaseContext;
  25. import org.apache.fop.fo.Constants;
  26. import org.apache.fop.fo.FONode;
  27. import org.apache.fop.fo.FOText;
  28. import org.apache.fop.fo.flow.Block;
  29. import org.apache.fop.fo.flow.BlockContainer;
  30. import org.apache.fop.fo.flow.Inline;
  31. import org.apache.fop.fo.flow.Leader;
  32. import org.apache.fop.fo.flow.PageNumber;
  33. import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
  34. import org.apache.fop.fo.properties.CommonFont;
  35. import org.apache.fop.fo.properties.CommonMarginBlock;
  36. import org.apache.fop.fo.properties.CommonTextDecoration;
  37. import org.apache.fop.fo.properties.PercentLength;
  38. import org.apache.fop.render.rtf.rtflib.rtfdoc.IBorderAttributes;
  39. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfAttributes;
  40. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfColorTable;
  41. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfFontManager;
  42. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfLeader;
  43. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfText;
  44. /** Converts FO properties to RtfAttributes
  45. * @author Bertrand Delacretaz bdelacretaz@codeconsult.ch
  46. * @author Andreas Putz a.putz@skynamics.com
  47. * @author Boris Poudérous boris.pouderous@eads-telecom.com
  48. * @author Peter Herweg, pherweg@web.de
  49. * @author Normand Massé
  50. * @author Chris Scott
  51. * @author rmarra
  52. */
  53. final class TextAttributesConverter {
  54. private static Log log = LogFactory.getLog(TextAttributesConverter.class);
  55. /**
  56. * Constructor is private, because it's just a utility class.
  57. */
  58. private TextAttributesConverter() {
  59. }
  60. /**
  61. * Converts all known text FO properties to RtfAttributes
  62. * @param props list of FO properites, which are to be converted
  63. */
  64. public static RtfAttributes convertAttributes(Block fobj)
  65. throws FOPException {
  66. FOPRtfAttributes attrib = new FOPRtfAttributes();
  67. attrFont(fobj.getCommonFont(), attrib);
  68. attrFontColor(fobj.getColor(), attrib);
  69. //attrTextDecoration(fobj.getTextDecoration(), attrib);
  70. attrBlockBackgroundColor(fobj.getCommonBorderPaddingBackground(), attrib);
  71. attrBlockMargin(fobj.getCommonMarginBlock(), attrib);
  72. attrBlockTextAlign(fobj.getTextAlign(), attrib);
  73. attrBorder(fobj.getCommonBorderPaddingBackground(), attrib, fobj);
  74. return attrib;
  75. }
  76. /**
  77. * Converts all known text FO properties to RtfAttributes
  78. * @param props list of FO properites, which are to be converted
  79. */
  80. public static RtfAttributes convertBlockContainerAttributes(BlockContainer fobj)
  81. throws FOPException {
  82. FOPRtfAttributes attrib = new FOPRtfAttributes();
  83. attrBackgroundColor(fobj.getCommonBorderPaddingBackground(), attrib);
  84. attrBlockMargin(fobj.getCommonMarginBlock(), attrib);
  85. //attrBlockDimension(fobj, attrib);
  86. attrBorder(fobj.getCommonBorderPaddingBackground(), attrib, fobj);
  87. return attrib;
  88. }
  89. /**
  90. * Converts all character related FO properties to RtfAttributes.
  91. * @param fobj FObj whose properties are to be converted
  92. */
  93. public static RtfAttributes convertCharacterAttributes(
  94. FOText fobj) throws FOPException {
  95. FOPRtfAttributes attrib = new FOPRtfAttributes();
  96. attrFont(fobj.getCommonFont(), attrib);
  97. attrFontColor(fobj.getColor(), attrib);
  98. attrTextDecoration(fobj.getTextDecoration(), attrib);
  99. attrBaseLineShift(fobj.getBaseLineShift(), attrib);
  100. return attrib;
  101. }
  102. /**
  103. * Converts all character related FO properties to RtfAttributes.
  104. * @param fobj FObj whose properties are to be converted
  105. */
  106. public static RtfAttributes convertCharacterAttributes(
  107. PageNumber fobj) throws FOPException {
  108. FOPRtfAttributes attrib = new FOPRtfAttributes();
  109. attrFont(fobj.getCommonFont(), attrib);
  110. attrTextDecoration(fobj.getTextDecoration(), attrib);
  111. attrBackgroundColor(fobj.getCommonBorderPaddingBackground(), attrib);
  112. return attrib;
  113. }
  114. /**
  115. * Converts all character related FO properties to RtfAttributes.
  116. * @param fobj FObj whose properties are to be converted
  117. */
  118. public static RtfAttributes convertCharacterAttributes(
  119. Inline fobj) throws FOPException {
  120. FOPRtfAttributes attrib = new FOPRtfAttributes();
  121. attrFont(fobj.getCommonFont(), attrib);
  122. attrFontColor(fobj.getColor(), attrib);
  123. attrBackgroundColor(fobj.getCommonBorderPaddingBackground(), attrib);
  124. attrInlineBorder(fobj.getCommonBorderPaddingBackground(), attrib);
  125. return attrib;
  126. }
  127. /**
  128. * Converts FO properties used by RtfLeader to RtfAttributes.
  129. * @param fobj Leader
  130. * @param context PercentBaseContext
  131. * @return RtfAttributes
  132. * @throws FOPException
  133. */
  134. public static RtfAttributes convertLeaderAttributes(Leader fobj, PercentBaseContext context)
  135. throws FOPException {
  136. boolean tab = false;
  137. FOPRtfAttributes attrib = new FOPRtfAttributes();
  138. attrib.set(RtfText.ATTR_FONT_FAMILY,
  139. RtfFontManager.getInstance().getFontNumber(fobj.getCommonFont().getFirstFontFamily()));
  140. if (fobj.getLeaderLength() != null) {
  141. attrib.set(RtfLeader.LEADER_WIDTH, convertMptToTwips(fobj.getLeaderLength().getMaximum(
  142. context).getLength().getValue(context)));
  143. if (fobj.getLeaderLength().getMaximum(context) instanceof PercentLength) {
  144. if (((PercentLength)fobj.getLeaderLength().getMaximum(context)).getString().equals(
  145. "100.0%")) {
  146. // Use Tab instead of white spaces
  147. attrib.set(RtfLeader.LEADER_USETAB, 1);
  148. tab = true;
  149. }
  150. }
  151. }
  152. attrFontColor(fobj.getColor(), attrib);
  153. if (fobj.getLeaderPatternWidth() != null) {
  154. //TODO calculate pattern width not possible for white spaces, because its using
  155. //underlines for tab it would work with LEADER_PATTERN_WIDTH (expndtw)
  156. }
  157. switch(fobj.getLeaderPattern()) {
  158. case Constants.EN_DOTS:
  159. if (tab) {
  160. attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_TAB_DOTTED);
  161. } else {
  162. attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_DOTTED);
  163. }
  164. break;
  165. case Constants.EN_SPACE:
  166. //nothing has to be set for spaces
  167. break;
  168. case Constants.EN_RULE:
  169. //Things like start-indent, space-after, ... not supported?
  170. //Leader class does not offer these properties
  171. //TODO aggregate them with the leader width or
  172. // create a second - blank leader - before
  173. if (fobj.getRuleThickness() != null) {
  174. //TODO See inside RtfLeader, better calculation for
  175. //white spaces would be necessary
  176. //attrib.set(RtfLeader.LEADER_RULE_THICKNESS,
  177. // fobj.getRuleThickness().getValue(context));
  178. log.warn("RTF: fo:leader rule-thickness not supported");
  179. }
  180. switch (fobj.getRuleStyle()) {
  181. case Constants.EN_SOLID:
  182. if (tab) {
  183. attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_TAB_THICK);
  184. } else {
  185. attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_THICK);
  186. }
  187. break;
  188. case Constants.EN_DASHED:
  189. if (tab) {
  190. attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_TAB_MIDDLEDOTTED);
  191. } else {
  192. attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_MIDDLEDOTTED);
  193. }
  194. break;
  195. case Constants.EN_DOTTED:
  196. if (tab) {
  197. attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_TAB_DOTTED);
  198. } else {
  199. attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_DOTTED);
  200. }
  201. break;
  202. case Constants.EN_DOUBLE:
  203. if (tab) {
  204. attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_TAB_EQUAL);
  205. } else {
  206. attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_EQUAL);
  207. }
  208. break;
  209. case Constants.EN_GROOVE:
  210. if (tab) {
  211. attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_TAB_HYPHENS);
  212. } else {
  213. attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_HYPHENS);
  214. }
  215. break;
  216. case Constants.EN_RIDGE:
  217. if (tab) {
  218. attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_TAB_UNDERLINE);
  219. } else {
  220. attrib.set(RtfLeader.LEADER_TABLEAD, RtfLeader.LEADER_UNDERLINE);
  221. }
  222. break;
  223. default:
  224. break;
  225. }
  226. break;
  227. case Constants.EN_USECONTENT:
  228. log.warn("RTF: fo:leader use-content not supported");
  229. break;
  230. default:
  231. break;
  232. }
  233. if (fobj.getLeaderAlignment() == Constants.EN_REFERENCE_AREA) {
  234. log.warn("RTF: fo:leader reference-area not supported");
  235. }
  236. return attrib;
  237. }
  238. private static int convertMptToTwips(int mpt) {
  239. return Math.round(FoUnitsConverter.getInstance().convertMptToTwips(mpt));
  240. }
  241. private static void attrFont(CommonFont font, FOPRtfAttributes rtfAttr) {
  242. rtfAttr.set(RtfText.ATTR_FONT_FAMILY,
  243. RtfFontManager.getInstance().getFontNumber(font.getFirstFontFamily()));
  244. rtfAttr.setHalfPoints(RtfText.ATTR_FONT_SIZE, font.fontSize);
  245. if (font.getFontWeight() == Constants.EN_700
  246. || font.getFontWeight() == Constants.EN_800
  247. || font.getFontWeight() == Constants.EN_900) {
  248. //Everything from 700 and above is declared as bold
  249. rtfAttr.set("b", 1);
  250. } else {
  251. rtfAttr.set("b", 0);
  252. }
  253. if (font.getFontStyle() == Constants.EN_ITALIC) {
  254. rtfAttr.set(RtfText.ATTR_ITALIC, 1);
  255. } else {
  256. rtfAttr.set(RtfText.ATTR_ITALIC, 0);
  257. }
  258. }
  259. private static void attrFontColor(Color colorType, RtfAttributes rtfAttr) {
  260. // Cell background color
  261. if (colorType != null) {
  262. if (colorType.getAlpha() != 0
  263. || colorType.getRed() != 0
  264. || colorType.getGreen() != 0
  265. || colorType.getBlue() != 0) {
  266. rtfAttr.set(RtfText.ATTR_FONT_COLOR,
  267. convertFOPColorToRTF(colorType));
  268. }
  269. }
  270. }
  271. private static void attrTextDecoration(CommonTextDecoration textDecoration,
  272. RtfAttributes rtfAttr) {
  273. if (textDecoration == null) {
  274. rtfAttr.set(RtfText.ATTR_UNDERLINE, 0);
  275. rtfAttr.set(RtfText.ATTR_STRIKETHROUGH, 0);
  276. return;
  277. }
  278. if (textDecoration.hasUnderline()) {
  279. rtfAttr.set(RtfText.ATTR_UNDERLINE, 1);
  280. } else {
  281. rtfAttr.set(RtfText.ATTR_UNDERLINE, 0);
  282. }
  283. if (textDecoration.hasLineThrough()) {
  284. rtfAttr.set(RtfText.ATTR_STRIKETHROUGH, 1);
  285. } else {
  286. rtfAttr.set(RtfText.ATTR_STRIKETHROUGH, 0);
  287. }
  288. }
  289. private static void attrBlockMargin(CommonMarginBlock cmb, FOPRtfAttributes rtfAttr) {
  290. rtfAttr.setTwips(RtfText.SPACE_BEFORE,
  291. cmb.spaceBefore.getOptimum(null).getLength());
  292. rtfAttr.setTwips(RtfText.SPACE_AFTER,
  293. cmb.spaceAfter.getOptimum(null).getLength());
  294. rtfAttr.setTwips(RtfText.LEFT_INDENT_BODY, cmb.startIndent);
  295. rtfAttr.setTwips(RtfText.RIGHT_INDENT_BODY, cmb.endIndent);
  296. }
  297. /*
  298. private static void attrBlockDimension(FObj fobj, FOPRtfAttributes rtfAttr) {
  299. Length ipd = fobj.getProperty(Constants.PR_INLINE_PROGRESSION_DIMENSION)
  300. .getLengthRange().getOptimum().getLength();
  301. if (ipd.getEnum() != Constants.EN_AUTO) {
  302. rtfAttr.set(RtfText.FRAME_WIDTH, ipd);
  303. }
  304. Length bpd = fobj.getProperty(Constants.PR_BLOCK_PROGRESSION_DIMENSION)
  305. .getLengthRange().getOptimum().getLength();
  306. if (bpd.getEnum() != Constants.EN_AUTO) {
  307. rtfAttr.set(RtfText.FRAME_HEIGHT, bpd);
  308. }
  309. }
  310. */
  311. private static void attrBlockTextAlign(int alignment, RtfAttributes rtfAttr) {
  312. String rtfValue = null;
  313. switch (alignment) {
  314. case Constants.EN_CENTER:
  315. rtfValue = RtfText.ALIGN_CENTER;
  316. break;
  317. case Constants.EN_END:
  318. rtfValue = RtfText.ALIGN_RIGHT;
  319. break;
  320. case Constants.EN_JUSTIFY:
  321. rtfValue = RtfText.ALIGN_JUSTIFIED;
  322. break;
  323. default:
  324. rtfValue = RtfText.ALIGN_LEFT;
  325. break;
  326. }
  327. rtfAttr.set(rtfValue);
  328. }
  329. /**
  330. * Reads background-color for block from <code>bpb</code> and writes it to
  331. * <code>rtfAttr</code>.
  332. */
  333. private static void attrBlockBackgroundColor(
  334. CommonBorderPaddingBackground bpb, RtfAttributes rtfAttr) {
  335. if (bpb.hasBackground()) {
  336. rtfAttr.set(RtfText.SHADING, RtfText.FULL_SHADING);
  337. rtfAttr.set(RtfText.SHADING_FRONT_COLOR,
  338. convertFOPColorToRTF(bpb.backgroundColor));
  339. }
  340. }
  341. /** Adds border information from <code>bpb</code> to <code>rtrAttr</code>. */
  342. private static void attrBorder(CommonBorderPaddingBackground bpb,
  343. RtfAttributes rtfAttr, FONode fobj) {
  344. if (hasBorder(fobj.getParent())) {
  345. attrInlineBorder(bpb, rtfAttr);
  346. return;
  347. }
  348. BorderAttributesConverter.makeBorder(bpb,
  349. CommonBorderPaddingBackground.BEFORE, rtfAttr,
  350. IBorderAttributes.BORDER_TOP);
  351. BorderAttributesConverter.makeBorder(bpb,
  352. CommonBorderPaddingBackground.AFTER, rtfAttr,
  353. IBorderAttributes.BORDER_BOTTOM);
  354. BorderAttributesConverter.makeBorder(bpb,
  355. CommonBorderPaddingBackground.START, rtfAttr,
  356. IBorderAttributes.BORDER_LEFT);
  357. BorderAttributesConverter.makeBorder(bpb,
  358. CommonBorderPaddingBackground.END, rtfAttr,
  359. IBorderAttributes.BORDER_RIGHT);
  360. }
  361. /** @return true, if element <code>node</code> has border. */
  362. private static boolean hasBorder(FONode node) {
  363. while (node != null) {
  364. CommonBorderPaddingBackground commonBorderPaddingBackground = null;
  365. if (node instanceof Block) {
  366. Block block = (Block) node;
  367. commonBorderPaddingBackground = block.getCommonBorderPaddingBackground();
  368. } else if (node instanceof BlockContainer) {
  369. BlockContainer container = (BlockContainer) node;
  370. commonBorderPaddingBackground = container.getCommonBorderPaddingBackground();
  371. }
  372. if (commonBorderPaddingBackground != null
  373. && commonBorderPaddingBackground.hasBorder()) {
  374. return true;
  375. }
  376. node = node.getParent();
  377. }
  378. return false;
  379. }
  380. /** Adds inline border information from <code>bpb</code> to <code>rtrAttr</code>. */
  381. private static void attrInlineBorder(CommonBorderPaddingBackground bpb,
  382. RtfAttributes rtfAttr) {
  383. BorderAttributesConverter.makeBorder(bpb,
  384. CommonBorderPaddingBackground.BEFORE, rtfAttr,
  385. IBorderAttributes.BORDER_CHARACTER);
  386. }
  387. /**
  388. * Reads background-color from bl and writes it to rtfAttr.
  389. *
  390. * @param bl the Block object the properties are read from
  391. * @param rtfAttr the RtfAttributes object the attributes are written to
  392. */
  393. private static void attrBackgroundColor(CommonBorderPaddingBackground bpb,
  394. RtfAttributes rtfAttr) {
  395. Color fopValue = bpb.backgroundColor;
  396. int rtfColor = 0;
  397. /* FOP uses a default background color of "transparent", which is
  398. actually a transparent black, which is generally not suitable as a
  399. default here. Changing FOP's default to "white" causes problems in
  400. PDF output, so we will look for the default here & change it to
  401. "auto". */
  402. if ((fopValue == null)
  403. || ((fopValue.getRed() == 0)
  404. && (fopValue.getGreen() == 0)
  405. && (fopValue.getBlue() == 0)
  406. && (fopValue.getAlpha() == 0))) {
  407. return;
  408. } else {
  409. rtfColor = convertFOPColorToRTF(fopValue);
  410. }
  411. rtfAttr.set(RtfText.ATTR_BACKGROUND_COLOR, rtfColor);
  412. }
  413. private static void attrBaseLineShift(Length baselineShift, RtfAttributes rtfAttr) {
  414. int s = baselineShift.getEnum();
  415. if (s == Constants.EN_SUPER) {
  416. rtfAttr.set(RtfText.ATTR_SUPERSCRIPT);
  417. } else if (s == Constants.EN_SUB) {
  418. rtfAttr.set(RtfText.ATTR_SUBSCRIPT);
  419. }
  420. }
  421. /**
  422. * Converts a FOP ColorType to the integer pointing into the RTF color table
  423. * @param fopColor the ColorType object to be converted
  424. * @return integer pointing into the RTF color table
  425. */
  426. public static int convertFOPColorToRTF(Color fopColor) {
  427. // TODO: This code is duplicated in FOPRtfAttributesConverter
  428. int redComponent = fopColor.getRed();
  429. int greenComponent = fopColor.getGreen();
  430. int blueComponent = fopColor.getBlue();
  431. return RtfColorTable.getInstance().getColorNumber(redComponent,
  432. greenComponent, blueComponent).intValue();
  433. }
  434. }