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.

RTFHandler.java 64KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803
  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. // Java
  20. import java.awt.Dimension;
  21. import java.awt.Rectangle;
  22. import java.awt.geom.Point2D;
  23. import java.io.FileNotFoundException;
  24. import java.io.IOException;
  25. import java.io.InputStream;
  26. import java.io.OutputStream;
  27. import java.io.OutputStreamWriter;
  28. import java.util.Iterator;
  29. import java.util.Map;
  30. import org.w3c.dom.Document;
  31. import org.xml.sax.SAXException;
  32. import org.apache.commons.io.IOUtils;
  33. import org.apache.commons.logging.Log;
  34. import org.apache.commons.logging.LogFactory;
  35. import org.apache.xmlgraphics.image.loader.Image;
  36. import org.apache.xmlgraphics.image.loader.ImageException;
  37. import org.apache.xmlgraphics.image.loader.ImageFlavor;
  38. import org.apache.xmlgraphics.image.loader.ImageInfo;
  39. import org.apache.xmlgraphics.image.loader.ImageManager;
  40. import org.apache.xmlgraphics.image.loader.ImageSessionContext;
  41. import org.apache.xmlgraphics.image.loader.ImageSize;
  42. import org.apache.xmlgraphics.image.loader.impl.ImageRawStream;
  43. import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
  44. import org.apache.xmlgraphics.image.loader.util.ImageUtil;
  45. import org.apache.fop.ResourceEventProducer;
  46. import org.apache.fop.apps.FOPException;
  47. import org.apache.fop.apps.FOUserAgent;
  48. import org.apache.fop.datatypes.LengthBase;
  49. import org.apache.fop.datatypes.PercentBaseContext;
  50. import org.apache.fop.fo.Constants;
  51. import org.apache.fop.fo.FOEventHandler;
  52. import org.apache.fop.fo.FONode;
  53. import org.apache.fop.fo.FOText;
  54. import org.apache.fop.fo.FObj;
  55. import org.apache.fop.fo.XMLObj;
  56. import org.apache.fop.fo.flow.AbstractGraphics;
  57. import org.apache.fop.fo.flow.BasicLink;
  58. import org.apache.fop.fo.flow.Block;
  59. import org.apache.fop.fo.flow.BlockContainer;
  60. import org.apache.fop.fo.flow.Character;
  61. import org.apache.fop.fo.flow.ExternalGraphic;
  62. import org.apache.fop.fo.flow.Footnote;
  63. import org.apache.fop.fo.flow.FootnoteBody;
  64. import org.apache.fop.fo.flow.Inline;
  65. import org.apache.fop.fo.flow.InstreamForeignObject;
  66. import org.apache.fop.fo.flow.Leader;
  67. import org.apache.fop.fo.flow.ListBlock;
  68. import org.apache.fop.fo.flow.ListItem;
  69. import org.apache.fop.fo.flow.ListItemBody;
  70. import org.apache.fop.fo.flow.ListItemLabel;
  71. import org.apache.fop.fo.flow.PageNumber;
  72. import org.apache.fop.fo.flow.PageNumberCitation;
  73. import org.apache.fop.fo.flow.PageNumberCitationLast;
  74. import org.apache.fop.fo.flow.table.Table;
  75. import org.apache.fop.fo.flow.table.TableBody;
  76. import org.apache.fop.fo.flow.table.TableCell;
  77. import org.apache.fop.fo.flow.table.TableColumn;
  78. import org.apache.fop.fo.flow.table.TableFooter;
  79. import org.apache.fop.fo.flow.table.TableHeader;
  80. import org.apache.fop.fo.flow.table.TablePart;
  81. import org.apache.fop.fo.flow.table.TableRow;
  82. import org.apache.fop.fo.pagination.Flow;
  83. import org.apache.fop.fo.pagination.PageSequence;
  84. import org.apache.fop.fo.pagination.PageSequenceMaster;
  85. import org.apache.fop.fo.pagination.Region;
  86. import org.apache.fop.fo.pagination.SimplePageMaster;
  87. import org.apache.fop.fo.pagination.StaticContent;
  88. import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
  89. import org.apache.fop.fo.properties.EnumLength;
  90. import org.apache.fop.fonts.FontSetup;
  91. import org.apache.fop.layoutmgr.inline.ImageLayout;
  92. import org.apache.fop.layoutmgr.table.ColumnSetup;
  93. import org.apache.fop.render.RendererEventProducer;
  94. import org.apache.fop.render.rtf.rtflib.exceptions.RtfException;
  95. import org.apache.fop.render.rtf.rtflib.rtfdoc.IRtfAfterContainer;
  96. import org.apache.fop.render.rtf.rtflib.rtfdoc.IRtfBeforeContainer;
  97. import org.apache.fop.render.rtf.rtflib.rtfdoc.IRtfListContainer;
  98. import org.apache.fop.render.rtf.rtflib.rtfdoc.IRtfTableContainer;
  99. import org.apache.fop.render.rtf.rtflib.rtfdoc.IRtfTextrunContainer;
  100. import org.apache.fop.render.rtf.rtflib.rtfdoc.ITableAttributes;
  101. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfAfter;
  102. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfAttributes;
  103. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfBefore;
  104. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfDocumentArea;
  105. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfElement;
  106. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfExternalGraphic;
  107. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfFile;
  108. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfFootnote;
  109. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfHyperLink;
  110. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfList;
  111. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfListItem;
  112. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfListItem.RtfListItemLabel;
  113. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfPage;
  114. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfParagraphBreak;
  115. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfSection;
  116. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfTable;
  117. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfTableCell;
  118. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfTableRow;
  119. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfTextrun;
  120. import org.apache.fop.render.rtf.rtflib.tools.BuilderContext;
  121. import org.apache.fop.render.rtf.rtflib.tools.PercentContext;
  122. import org.apache.fop.render.rtf.rtflib.tools.TableContext;
  123. /**
  124. * RTF Handler: generates RTF output using the structure events from
  125. * the FO Tree sent to this structure handler.
  126. */
  127. public class RTFHandler extends FOEventHandler {
  128. private RtfFile rtfFile;
  129. private final OutputStream os;
  130. private static Log log = LogFactory.getLog(RTFHandler.class);
  131. private RtfSection sect;
  132. private RtfDocumentArea docArea;
  133. private boolean bDefer; //true, if each called handler shall be
  134. //processed at later time.
  135. private boolean bPrevHeaderSpecified; //true, if there has been a
  136. //header in any page-sequence
  137. private boolean bPrevFooterSpecified; //true, if there has been a
  138. //footer in any page-sequence
  139. private boolean bHeaderSpecified; //true, if there is a header
  140. //in current page-sequence
  141. private boolean bFooterSpecified; //true, if there is a footer
  142. //in current page-sequence
  143. private BuilderContext builderContext = new BuilderContext(null);
  144. private SimplePageMaster pagemaster;
  145. private int nestedTableDepth = 1;
  146. private PercentContext percentManager = new PercentContext();
  147. /**
  148. * Creates a new RTF structure handler.
  149. * @param userAgent the FOUserAgent for this process
  150. * @param os OutputStream to write to
  151. */
  152. public RTFHandler(FOUserAgent userAgent, OutputStream os) {
  153. super(userAgent);
  154. this.os = os;
  155. bDefer = true;
  156. boolean base14Kerning = false;
  157. FontSetup.setup(fontInfo, null, userAgent.getResourceResolver(), base14Kerning);
  158. }
  159. /**
  160. * Central exception handler for I/O exceptions.
  161. * @param ioe IOException to handle
  162. */
  163. protected void handleIOTrouble(IOException ioe) {
  164. RendererEventProducer eventProducer = RendererEventProducer.Provider.get(
  165. getUserAgent().getEventBroadcaster());
  166. eventProducer.ioError(this, ioe);
  167. }
  168. /** {@inheritDoc} */
  169. public void startDocument() throws SAXException {
  170. // TODO sections should be created
  171. try {
  172. rtfFile = new RtfFile(new OutputStreamWriter(os));
  173. docArea = rtfFile.startDocumentArea();
  174. } catch (IOException ioe) {
  175. // TODO could we throw Exception in all FOEventHandler events?
  176. throw new SAXException(ioe);
  177. }
  178. }
  179. /** {@inheritDoc} */
  180. public void endDocument() throws SAXException {
  181. try {
  182. rtfFile.flush();
  183. } catch (IOException ioe) {
  184. // TODO could we throw Exception in all FOEventHandler events?
  185. throw new SAXException(ioe);
  186. }
  187. }
  188. /** {@inheritDoc} */
  189. public void startPageSequence(PageSequence pageSeq) {
  190. try {
  191. //This is needed for region handling
  192. if (this.pagemaster == null) {
  193. String reference = pageSeq.getMasterReference();
  194. this.pagemaster
  195. = pageSeq.getRoot().getLayoutMasterSet().getSimplePageMaster(reference);
  196. if (this.pagemaster == null) {
  197. RTFEventProducer eventProducer = RTFEventProducer.Provider.get(
  198. getUserAgent().getEventBroadcaster());
  199. eventProducer.onlySPMSupported(this, reference, pageSeq.getLocator());
  200. PageSequenceMaster master
  201. = pageSeq.getRoot().getLayoutMasterSet().getPageSequenceMaster(reference);
  202. if (pageSeq.getMainFlow() != null) {
  203. this.pagemaster = master.getNextSimplePageMaster(
  204. false, false, false, false, pageSeq.getMainFlow().getFlowName());
  205. }
  206. }
  207. }
  208. if (bDefer) {
  209. return;
  210. }
  211. sect = docArea.newSection();
  212. //read page size and margins, if specified
  213. //only simple-page-master supported, so pagemaster may be null
  214. if (pagemaster != null) {
  215. sect.getRtfAttributes().set(
  216. PageAttributesConverter.convertPageAttributes(
  217. pagemaster));
  218. } else {
  219. RTFEventProducer eventProducer = RTFEventProducer.Provider.get(
  220. getUserAgent().getEventBroadcaster());
  221. eventProducer.noSPMFound(this, pageSeq.getLocator());
  222. }
  223. builderContext.pushContainer(sect);
  224. //Calculate usable page width for this flow
  225. int useAblePageWidth = pagemaster.getPageWidth().getValue()
  226. - pagemaster.getCommonMarginBlock().marginLeft.getValue()
  227. - pagemaster.getCommonMarginBlock().marginRight.getValue()
  228. - sect.getRtfAttributes().getValueAsInteger(RtfPage.MARGIN_LEFT)
  229. - sect.getRtfAttributes().getValueAsInteger(RtfPage.MARGIN_RIGHT);
  230. percentManager.setDimension(pageSeq, useAblePageWidth);
  231. bHeaderSpecified = false;
  232. bFooterSpecified = false;
  233. } catch (IOException ioe) {
  234. handleIOTrouble(ioe);
  235. }
  236. }
  237. /** {@inheritDoc} */
  238. public void endPageSequence(PageSequence pageSeq) {
  239. if (bDefer) {
  240. //If endBlock was called while SAX parsing, and the passed FO is Block
  241. //nested within another Block, stop deferring.
  242. //Now process all deferred FOs.
  243. bDefer = false;
  244. recurseFONode(pageSeq);
  245. this.pagemaster = null;
  246. bDefer = true;
  247. return;
  248. } else {
  249. builderContext.popContainer(RtfSection.class, this);
  250. this.pagemaster = null;
  251. }
  252. }
  253. /** {@inheritDoc} */
  254. public void startFlow(Flow fl) {
  255. if (bDefer) {
  256. return;
  257. }
  258. try {
  259. log.debug("starting flow: " + fl.getFlowName());
  260. boolean handled = false;
  261. Region regionBody = pagemaster.getRegion(Constants.FO_REGION_BODY);
  262. Region regionBefore = pagemaster.getRegion(Constants.FO_REGION_BEFORE);
  263. Region regionAfter = pagemaster.getRegion(Constants.FO_REGION_AFTER);
  264. if (fl.getFlowName().equals(regionBody.getRegionName())) {
  265. // if there is no header in current page-sequence but there has been
  266. // a header in a previous page-sequence, insert an empty header.
  267. if (bPrevHeaderSpecified && !bHeaderSpecified) {
  268. RtfAttributes attr = new RtfAttributes();
  269. attr.set(RtfBefore.HEADER);
  270. final IRtfBeforeContainer contBefore
  271. = (IRtfBeforeContainer)builderContext.getContainer(
  272. IRtfBeforeContainer.class, true, this);
  273. contBefore.newBefore(attr);
  274. }
  275. // if there is no footer in current page-sequence but there has been
  276. // a footer in a previous page-sequence, insert an empty footer.
  277. if (bPrevFooterSpecified && !bFooterSpecified) {
  278. RtfAttributes attr = new RtfAttributes();
  279. attr.set(RtfAfter.FOOTER);
  280. final IRtfAfterContainer contAfter
  281. = (IRtfAfterContainer)builderContext.getContainer(
  282. IRtfAfterContainer.class, true, this);
  283. contAfter.newAfter(attr);
  284. }
  285. handled = true;
  286. } else if (regionBefore != null
  287. && fl.getFlowName().equals(regionBefore.getRegionName())) {
  288. bHeaderSpecified = true;
  289. bPrevHeaderSpecified = true;
  290. final IRtfBeforeContainer c
  291. = (IRtfBeforeContainer)builderContext.getContainer(
  292. IRtfBeforeContainer.class,
  293. true, this);
  294. RtfAttributes beforeAttributes = ((RtfElement)c).getRtfAttributes();
  295. if (beforeAttributes == null) {
  296. beforeAttributes = new RtfAttributes();
  297. }
  298. beforeAttributes.set(RtfBefore.HEADER);
  299. RtfBefore before = c.newBefore(beforeAttributes);
  300. builderContext.pushContainer(before);
  301. handled = true;
  302. } else if (regionAfter != null
  303. && fl.getFlowName().equals(regionAfter.getRegionName())) {
  304. bFooterSpecified = true;
  305. bPrevFooterSpecified = true;
  306. final IRtfAfterContainer c
  307. = (IRtfAfterContainer)builderContext.getContainer(
  308. IRtfAfterContainer.class,
  309. true, this);
  310. RtfAttributes afterAttributes = ((RtfElement)c).getRtfAttributes();
  311. if (afterAttributes == null) {
  312. afterAttributes = new RtfAttributes();
  313. }
  314. afterAttributes.set(RtfAfter.FOOTER);
  315. RtfAfter after = c.newAfter(afterAttributes);
  316. builderContext.pushContainer(after);
  317. handled = true;
  318. }
  319. if (!handled) {
  320. log.warn("A " + fl.getLocalName() + " has been skipped: " + fl.getFlowName());
  321. }
  322. } catch (IOException ioe) {
  323. handleIOTrouble(ioe);
  324. } catch (Exception e) {
  325. log.error("startFlow: " + e.getMessage());
  326. throw new RuntimeException(e.getMessage());
  327. }
  328. }
  329. /** {@inheritDoc} */
  330. public void endFlow(Flow fl) {
  331. if (bDefer) {
  332. return;
  333. }
  334. try {
  335. Region regionBody = pagemaster.getRegion(Constants.FO_REGION_BODY);
  336. Region regionBefore = pagemaster.getRegion(Constants.FO_REGION_BEFORE);
  337. Region regionAfter = pagemaster.getRegion(Constants.FO_REGION_AFTER);
  338. if (fl.getFlowName().equals(regionBody.getRegionName())) {
  339. //just do nothing
  340. } else if (regionBefore != null
  341. && fl.getFlowName().equals(regionBefore.getRegionName())) {
  342. builderContext.popContainer(RtfBefore.class, this);
  343. } else if (regionAfter != null
  344. && fl.getFlowName().equals(regionAfter.getRegionName())) {
  345. builderContext.popContainer(RtfAfter.class, this);
  346. }
  347. } catch (Exception e) {
  348. log.error("endFlow: " + e.getMessage());
  349. throw new RuntimeException(e.getMessage());
  350. }
  351. }
  352. /** {@inheritDoc} */
  353. public void startBlock(Block bl) {
  354. if (bDefer) {
  355. return;
  356. }
  357. try {
  358. RtfAttributes rtfAttr
  359. = TextAttributesConverter.convertAttributes(bl);
  360. IRtfTextrunContainer container
  361. = (IRtfTextrunContainer)builderContext.getContainer(
  362. IRtfTextrunContainer.class,
  363. true, this);
  364. RtfTextrun textrun = container.getTextrun();
  365. textrun.addParagraphBreak();
  366. textrun.pushBlockAttributes(rtfAttr);
  367. textrun.addBookmark(bl.getId());
  368. } catch (IOException ioe) {
  369. handleIOTrouble(ioe);
  370. } catch (Exception e) {
  371. log.error("startBlock: " + e.getMessage());
  372. throw new RuntimeException("Exception: " + e);
  373. }
  374. }
  375. /** {@inheritDoc} */
  376. public void endBlock(Block bl) {
  377. if (bDefer) {
  378. return;
  379. }
  380. try {
  381. IRtfTextrunContainer container
  382. = (IRtfTextrunContainer)builderContext.getContainer(
  383. IRtfTextrunContainer.class,
  384. true, this);
  385. RtfTextrun textrun = container.getTextrun();
  386. RtfParagraphBreak par = textrun.addParagraphBreak();
  387. RtfTableCell cellParent = (RtfTableCell)textrun.getParentOfClass(RtfTableCell.class);
  388. if (cellParent != null && par != null) {
  389. cellParent.setLastParagraph(par);
  390. }
  391. int breakValue = toRtfBreakValue(bl.getBreakAfter());
  392. textrun.popBlockAttributes(breakValue);
  393. } catch (IOException ioe) {
  394. handleIOTrouble(ioe);
  395. } catch (Exception e) {
  396. log.error("startBlock:" + e.getMessage());
  397. throw new RuntimeException(e.getMessage());
  398. }
  399. }
  400. /** {@inheritDoc} */
  401. public void startBlockContainer(BlockContainer blc) {
  402. if (bDefer) {
  403. return;
  404. }
  405. try {
  406. RtfAttributes rtfAttr
  407. = TextAttributesConverter.convertBlockContainerAttributes(blc);
  408. IRtfTextrunContainer container
  409. = (IRtfTextrunContainer)builderContext.getContainer(
  410. IRtfTextrunContainer.class,
  411. true, this);
  412. RtfTextrun textrun = container.getTextrun();
  413. textrun.addParagraphBreak();
  414. textrun.pushBlockAttributes(rtfAttr);
  415. } catch (IOException ioe) {
  416. handleIOTrouble(ioe);
  417. } catch (Exception e) {
  418. log.error("startBlock: " + e.getMessage());
  419. throw new RuntimeException("Exception: " + e);
  420. }
  421. }
  422. /** {@inheritDoc} */
  423. public void endBlockContainer(BlockContainer bl) {
  424. if (bDefer) {
  425. return;
  426. }
  427. try {
  428. IRtfTextrunContainer container
  429. = (IRtfTextrunContainer)builderContext.getContainer(
  430. IRtfTextrunContainer.class,
  431. true, this);
  432. RtfTextrun textrun = container.getTextrun();
  433. textrun.addParagraphBreak();
  434. int breakValue = toRtfBreakValue(bl.getBreakAfter());
  435. textrun.popBlockAttributes(breakValue);
  436. } catch (IOException ioe) {
  437. handleIOTrouble(ioe);
  438. } catch (Exception e) {
  439. log.error("startBlock:" + e.getMessage());
  440. throw new RuntimeException(e.getMessage());
  441. }
  442. }
  443. private int toRtfBreakValue(int foBreakValue) {
  444. switch (foBreakValue) {
  445. case Constants.EN_PAGE:
  446. return RtfTextrun.BREAK_PAGE;
  447. case Constants.EN_EVEN_PAGE:
  448. return RtfTextrun.BREAK_EVEN_PAGE;
  449. case Constants.EN_ODD_PAGE:
  450. return RtfTextrun.BREAK_ODD_PAGE;
  451. case Constants.EN_COLUMN:
  452. return RtfTextrun.BREAK_COLUMN;
  453. default:
  454. return RtfTextrun.BREAK_NONE;
  455. }
  456. }
  457. /** {@inheritDoc} */
  458. public void startTable(Table tbl) {
  459. if (bDefer) {
  460. return;
  461. }
  462. // create an RtfTable in the current table container
  463. TableContext tableContext = new TableContext(builderContext);
  464. try {
  465. final IRtfTableContainer tc
  466. = (IRtfTableContainer)builderContext.getContainer(
  467. IRtfTableContainer.class, true, null);
  468. RtfAttributes atts
  469. = TableAttributesConverter.convertTableAttributes(tbl);
  470. RtfTable table = tc.newTable(atts, tableContext);
  471. table.setNestedTableDepth(nestedTableDepth);
  472. nestedTableDepth++;
  473. CommonBorderPaddingBackground border = tbl.getCommonBorderPaddingBackground();
  474. RtfAttributes borderAttributes = new RtfAttributes();
  475. BorderAttributesConverter.makeBorder(border, CommonBorderPaddingBackground.BEFORE,
  476. borderAttributes, ITableAttributes.CELL_BORDER_TOP);
  477. BorderAttributesConverter.makeBorder(border, CommonBorderPaddingBackground.AFTER,
  478. borderAttributes, ITableAttributes.CELL_BORDER_BOTTOM);
  479. BorderAttributesConverter.makeBorder(border, CommonBorderPaddingBackground.START,
  480. borderAttributes, ITableAttributes.CELL_BORDER_LEFT);
  481. BorderAttributesConverter.makeBorder(border, CommonBorderPaddingBackground.END,
  482. borderAttributes, ITableAttributes.CELL_BORDER_RIGHT);
  483. table.setBorderAttributes(borderAttributes);
  484. builderContext.pushContainer(table);
  485. } catch (IOException ioe) {
  486. handleIOTrouble(ioe);
  487. } catch (Exception e) {
  488. log.error("startTable:" + e.getMessage());
  489. throw new RuntimeException(e.getMessage());
  490. }
  491. builderContext.pushTableContext(tableContext);
  492. }
  493. /** {@inheritDoc} */
  494. public void endTable(Table tbl) {
  495. if (bDefer) {
  496. return;
  497. }
  498. nestedTableDepth--;
  499. builderContext.popTableContext();
  500. builderContext.popContainer(RtfTable.class, this);
  501. }
  502. /** {@inheritDoc} */
  503. public void startColumn(TableColumn tc) {
  504. if (bDefer) {
  505. return;
  506. }
  507. try {
  508. int iWidth = tc.getColumnWidth().getValue(percentManager);
  509. percentManager.setDimension(tc, iWidth);
  510. //convert to twips
  511. Float width = FoUnitsConverter.getInstance().convertMptToTwips(iWidth);
  512. builderContext.getTableContext().setNextColumnWidth(width);
  513. builderContext.getTableContext().setNextColumnRowSpanning(
  514. 0, null);
  515. builderContext.getTableContext().setNextFirstSpanningCol(false);
  516. } catch (Exception e) {
  517. log.error("startColumn: " + e.getMessage());
  518. throw new RuntimeException(e.getMessage());
  519. }
  520. }
  521. /** {@inheritDoc} */
  522. public void endColumn(TableColumn tc) {
  523. }
  524. /** {@inheritDoc} */
  525. public void startHeader(TableHeader header) {
  526. builderContext.pushPart(header);
  527. startPart(header);
  528. }
  529. /** {@inheritDoc} */
  530. public void endHeader(TableHeader header) {
  531. builderContext.popPart(header.getClass(), this);
  532. endPart(header);
  533. }
  534. /** {@inheritDoc} */
  535. public void startFooter(TableFooter footer) {
  536. builderContext.pushPart(footer);
  537. startPart(footer);
  538. }
  539. /** {@inheritDoc} */
  540. public void endFooter(TableFooter footer) {
  541. builderContext.popPart(footer.getClass(), this);
  542. endPart(footer);
  543. }
  544. /** {@inheritDoc} */
  545. public void startInline(Inline inl) {
  546. if (bDefer) {
  547. return;
  548. }
  549. try {
  550. RtfAttributes rtfAttr
  551. = TextAttributesConverter.convertCharacterAttributes(inl);
  552. IRtfTextrunContainer container
  553. = (IRtfTextrunContainer)builderContext.getContainer(
  554. IRtfTextrunContainer.class, true, this);
  555. RtfTextrun textrun = container.getTextrun();
  556. textrun.pushInlineAttributes(rtfAttr);
  557. textrun.addBookmark(inl.getId());
  558. } catch (IOException ioe) {
  559. handleIOTrouble(ioe);
  560. } catch (FOPException fe) {
  561. log.error("startInline:" + fe.getMessage());
  562. throw new RuntimeException(fe.getMessage());
  563. } catch (Exception e) {
  564. log.error("startInline:" + e.getMessage());
  565. throw new RuntimeException(e.getMessage());
  566. }
  567. }
  568. /** {@inheritDoc} */
  569. public void endInline(Inline inl) {
  570. if (bDefer) {
  571. return;
  572. }
  573. try {
  574. IRtfTextrunContainer container
  575. = (IRtfTextrunContainer)builderContext.getContainer(
  576. IRtfTextrunContainer.class, true, this);
  577. RtfTextrun textrun = container.getTextrun();
  578. textrun.popInlineAttributes();
  579. } catch (IOException ioe) {
  580. handleIOTrouble(ioe);
  581. } catch (Exception e) {
  582. log.error("startInline:" + e.getMessage());
  583. throw new RuntimeException(e.getMessage());
  584. }
  585. }
  586. private void startPart(TablePart part) {
  587. if (bDefer) {
  588. return;
  589. }
  590. try {
  591. RtfAttributes atts = TableAttributesConverter.convertTablePartAttributes(part);
  592. // @SuppressFBWarnings("BC_UNCONFIRMED_CAST_OF_RETURN_VALUE")
  593. RtfTable tbl = (RtfTable)builderContext.getContainer(RtfTable.class, true, this);
  594. tbl.setHeaderAttribs(atts);
  595. } catch (IOException ioe) {
  596. handleIOTrouble(ioe);
  597. } catch (Exception e) {
  598. log.error("startPart: " + e.getMessage());
  599. throw new RuntimeException(e.getMessage());
  600. }
  601. }
  602. private void endPart(TablePart tb) {
  603. if (bDefer) {
  604. return;
  605. }
  606. try {
  607. // @SuppressFBWarnings("BC_UNCONFIRMED_CAST_OF_RETURN_VALUE")
  608. RtfTable tbl = (RtfTable)builderContext.getContainer(RtfTable.class, true, this);
  609. tbl.setHeaderAttribs(null);
  610. } catch (IOException ioe) {
  611. handleIOTrouble(ioe);
  612. } catch (Exception e) {
  613. log.error("endPart: " + e.getMessage());
  614. throw new RuntimeException(e.getMessage());
  615. }
  616. }
  617. /**
  618. * {@inheritDoc}
  619. */
  620. public void startBody(TableBody body) {
  621. builderContext.pushPart(body);
  622. startPart(body);
  623. }
  624. /** {@inheritDoc} */
  625. public void endBody(TableBody body) {
  626. builderContext.popPart(TableBody.class, this);
  627. endPart(body);
  628. }
  629. /**
  630. * {@inheritDoc}
  631. */
  632. public void startRow(TableRow tr) {
  633. if (bDefer) {
  634. return;
  635. }
  636. try {
  637. // create an RtfTableRow in the current RtfTable
  638. // @SuppressFBWarnings("BC_UNCONFIRMED_CAST_OF_RETURN_VALUE")
  639. final RtfTable tbl = (RtfTable)builderContext.getContainer(RtfTable.class,
  640. true, null);
  641. RtfAttributes atts = TableAttributesConverter.convertRowAttributes(tr,
  642. tbl.getHeaderAttribs());
  643. if (tr.getParent() instanceof TableHeader) {
  644. atts.set(ITableAttributes.ATTR_HEADER);
  645. }
  646. builderContext.pushContainer(tbl.newTableRow(atts));
  647. // reset column iteration index to correctly access column widths
  648. builderContext.getTableContext().selectFirstColumn();
  649. } catch (IOException ioe) {
  650. handleIOTrouble(ioe);
  651. } catch (Exception e) {
  652. log.error("startRow: " + e.getMessage());
  653. throw new RuntimeException(e.getMessage());
  654. }
  655. }
  656. /** {@inheritDoc} */
  657. public void endRow(TableRow tr) {
  658. if (bDefer) {
  659. return;
  660. }
  661. try {
  662. TableContext tctx = builderContext.getTableContext();
  663. // @SuppressFBWarnings("BC_UNCONFIRMED_CAST_OF_RETURN_VALUE")
  664. final RtfTableRow row = (RtfTableRow)builderContext.getContainer(RtfTableRow.class,
  665. true, null);
  666. //while the current column is in row-spanning, act as if
  667. //a vertical merged cell would have been specified.
  668. while (tctx.getNumberOfColumns() > tctx.getColumnIndex()
  669. && tctx.getColumnRowSpanningNumber() > 0) {
  670. RtfTableCell vCell = row.newTableCellMergedVertically(
  671. (int)tctx.getColumnWidth(),
  672. tctx.getColumnRowSpanningAttrs());
  673. if (!tctx.getFirstSpanningCol()) {
  674. vCell.setHMerge(RtfTableCell.MERGE_WITH_PREVIOUS);
  675. }
  676. tctx.selectNextColumn();
  677. }
  678. } catch (IOException ioe) {
  679. handleIOTrouble(ioe);
  680. } catch (Exception e) {
  681. log.error("endRow: " + e.getMessage());
  682. throw new RuntimeException(e.getMessage());
  683. }
  684. builderContext.popContainer(RtfTableRow.class, this);
  685. builderContext.getTableContext().decreaseRowSpannings();
  686. }
  687. /** {@inheritDoc} */
  688. public void startCell(TableCell tc) {
  689. if (bDefer) {
  690. return;
  691. }
  692. try {
  693. TableContext tctx = builderContext.getTableContext();
  694. // @SuppressFBWarnings("BC_UNCONFIRMED_CAST_OF_RETURN_VALUE")
  695. final RtfTableRow row = (RtfTableRow)builderContext.getContainer(RtfTableRow.class,
  696. true, null);
  697. int numberRowsSpanned = tc.getNumberRowsSpanned();
  698. int numberColumnsSpanned = tc.getNumberColumnsSpanned();
  699. //while the current column is in row-spanning, act as if
  700. //a vertical merged cell would have been specified.
  701. while (tctx.getNumberOfColumns() > tctx.getColumnIndex()
  702. && tctx.getColumnRowSpanningNumber() > 0) {
  703. RtfTableCell vCell = row.newTableCellMergedVertically(
  704. (int)tctx.getColumnWidth(),
  705. tctx.getColumnRowSpanningAttrs());
  706. if (!tctx.getFirstSpanningCol()) {
  707. vCell.setHMerge(RtfTableCell.MERGE_WITH_PREVIOUS);
  708. }
  709. tctx.selectNextColumn();
  710. }
  711. //get the width of the currently started cell
  712. float width = tctx.getColumnWidth();
  713. // create an RtfTableCell in the current RtfTableRow
  714. RtfAttributes atts = TableAttributesConverter.convertCellAttributes(tc);
  715. RtfTableCell cell = row.newTableCell((int)width, atts);
  716. //process number-rows-spanned attribute
  717. if (numberRowsSpanned > 1) {
  718. // Start vertical merge
  719. cell.setVMerge(RtfTableCell.MERGE_START);
  720. // set the number of rows spanned
  721. tctx.setCurrentColumnRowSpanning(numberRowsSpanned,
  722. cell.getRtfAttributes());
  723. } else {
  724. tctx.setCurrentColumnRowSpanning(
  725. numberRowsSpanned, null);
  726. }
  727. //process number-columns-spanned attribute
  728. if (numberColumnsSpanned > 0) {
  729. // Get the number of columns spanned
  730. tctx.setCurrentFirstSpanningCol(true);
  731. // We widthdraw one cell because the first cell is already created
  732. // (it's the current cell) !
  733. for (int i = 0; i < numberColumnsSpanned - 1; ++i) {
  734. tctx.selectNextColumn();
  735. //aggregate width for further elements
  736. width += tctx.getColumnWidth();
  737. tctx.setCurrentFirstSpanningCol(false);
  738. RtfTableCell hCell = row.newTableCellMergedHorizontally(
  739. 0, null);
  740. if (numberRowsSpanned > 1) {
  741. // Start vertical merge
  742. hCell.setVMerge(RtfTableCell.MERGE_START);
  743. // set the number of rows spanned
  744. tctx.setCurrentColumnRowSpanning(
  745. numberRowsSpanned,
  746. cell.getRtfAttributes());
  747. } else {
  748. tctx.setCurrentColumnRowSpanning(
  749. numberRowsSpanned, cell.getRtfAttributes());
  750. }
  751. }
  752. }
  753. //save width of the cell, convert from twips to mpt
  754. percentManager.setDimension(tc, (int)width * 50);
  755. builderContext.pushContainer(cell);
  756. } catch (IOException ioe) {
  757. handleIOTrouble(ioe);
  758. } catch (Exception e) {
  759. log.error("startCell: " + e.getMessage());
  760. throw new RuntimeException(e.getMessage());
  761. }
  762. }
  763. /** {@inheritDoc} */
  764. public void endCell(TableCell tc) {
  765. if (bDefer) {
  766. return;
  767. }
  768. try {
  769. // @SuppressFBWarnings("BC_UNCONFIRMED_CAST_OF_RETURN_VALUE")
  770. RtfTableCell cell = (RtfTableCell)builderContext.getContainer(RtfTableCell.class, false, this);
  771. cell.finish();
  772. } catch (Exception e) {
  773. log.error("endCell: " + e.getMessage());
  774. throw new RuntimeException(e.getMessage());
  775. }
  776. builderContext.popContainer(RtfTableCell.class, this);
  777. builderContext.getTableContext().selectNextColumn();
  778. }
  779. // Lists
  780. /** {@inheritDoc} */
  781. public void startList(ListBlock lb) {
  782. if (bDefer) {
  783. return;
  784. }
  785. try {
  786. // create an RtfList in the current list container
  787. final IRtfListContainer c
  788. = (IRtfListContainer)builderContext.getContainer(
  789. IRtfListContainer.class, true, this);
  790. final RtfList newList = c.newList(
  791. ListAttributesConverter.convertAttributes(lb));
  792. builderContext.pushContainer(newList);
  793. } catch (IOException ioe) {
  794. handleIOTrouble(ioe);
  795. } catch (FOPException fe) {
  796. log.error("startList: " + fe.getMessage());
  797. throw new RuntimeException(fe.getMessage());
  798. } catch (Exception e) {
  799. log.error("startList: " + e.getMessage());
  800. throw new RuntimeException(e.getMessage());
  801. }
  802. }
  803. /** {@inheritDoc} */
  804. public void endList(ListBlock lb) {
  805. if (bDefer) {
  806. return;
  807. }
  808. builderContext.popContainer(RtfList.class, this);
  809. }
  810. /** {@inheritDoc} */
  811. public void startListItem(ListItem li) {
  812. if (bDefer) {
  813. return;
  814. }
  815. // create an RtfListItem in the current RtfList
  816. try {
  817. // @SuppressFBWarnings("BC_UNCONFIRMED_CAST_OF_RETURN_VALUE")
  818. RtfList list = (RtfList)builderContext.getContainer(
  819. RtfList.class, true, this);
  820. /**
  821. * If the current list already contains a list item, then close the
  822. * list and open a new one, so every single list item gets its own
  823. * list. This allows every item to have a different list label.
  824. * If all the items would be in the same list, they had all the
  825. * same label.
  826. */
  827. //TODO: do this only, if the labels content <> previous labels content
  828. if (list.getChildCount() > 0) {
  829. this.endListBody(null);
  830. this.endList((ListBlock) li.getParent());
  831. this.startList((ListBlock) li.getParent());
  832. this.startListBody(null);
  833. list = (RtfList)builderContext.getContainer(
  834. RtfList.class, true, this);
  835. }
  836. builderContext.pushContainer(list.newListItem());
  837. } catch (IOException ioe) {
  838. handleIOTrouble(ioe);
  839. } catch (Exception e) {
  840. log.error("startList: " + e.getMessage());
  841. throw new RuntimeException(e.getMessage());
  842. }
  843. }
  844. /** {@inheritDoc} */
  845. public void endListItem(ListItem li) {
  846. if (bDefer) {
  847. return;
  848. }
  849. builderContext.popContainer(RtfListItem.class, this);
  850. }
  851. /** {@inheritDoc} */
  852. public void startListLabel(ListItemLabel listItemLabel) {
  853. if (bDefer) {
  854. return;
  855. }
  856. try {
  857. // @SuppressFBWarnings("BC_UNCONFIRMED_CAST_OF_RETURN_VALUE")
  858. RtfListItem item
  859. = (RtfListItem)builderContext.getContainer(RtfListItem.class, true, this);
  860. RtfListItemLabel label = item.new RtfListItemLabel(item);
  861. builderContext.pushContainer(label);
  862. } catch (IOException ioe) {
  863. handleIOTrouble(ioe);
  864. } catch (Exception e) {
  865. log.error("startPageNumber: " + e.getMessage());
  866. throw new RuntimeException(e.getMessage());
  867. }
  868. }
  869. /** {@inheritDoc} */
  870. public void endListLabel(ListItemLabel listItemLabel) {
  871. if (bDefer) {
  872. return;
  873. }
  874. builderContext.popContainer(RtfListItemLabel.class, this);
  875. }
  876. /** {@inheritDoc} */
  877. public void startListBody(ListItemBody listItemBody) {
  878. }
  879. /** {@inheritDoc} */
  880. public void endListBody(ListItemBody listItemBody) {
  881. }
  882. // Static Regions
  883. /** {@inheritDoc} */
  884. public void startStatic(StaticContent staticContent) {
  885. }
  886. /** {@inheritDoc} */
  887. public void endStatic(StaticContent statisContent) {
  888. }
  889. /** {@inheritDoc} */
  890. public void startMarkup() {
  891. }
  892. /** {@inheritDoc} */
  893. public void endMarkup() {
  894. }
  895. /** {@inheritDoc} */
  896. public void startLink(BasicLink basicLink) {
  897. if (bDefer) {
  898. return;
  899. }
  900. try {
  901. IRtfTextrunContainer container
  902. = (IRtfTextrunContainer)builderContext.getContainer(
  903. IRtfTextrunContainer.class, true, this);
  904. RtfTextrun textrun = container.getTextrun();
  905. RtfHyperLink link = textrun.addHyperlink(new RtfAttributes());
  906. if (basicLink.hasExternalDestination()) {
  907. link.setExternalURL(basicLink.getExternalDestination());
  908. } else {
  909. link.setInternalURL(basicLink.getInternalDestination());
  910. }
  911. builderContext.pushContainer(link);
  912. } catch (IOException ioe) {
  913. handleIOTrouble(ioe);
  914. } catch (Exception e) {
  915. log.error("startLink: " + e.getMessage());
  916. throw new RuntimeException(e.getMessage());
  917. }
  918. }
  919. /** {@inheritDoc} */
  920. public void endLink(BasicLink basicLink) {
  921. if (bDefer) {
  922. return;
  923. }
  924. builderContext.popContainer(RtfHyperLink.class, this);
  925. }
  926. /** {@inheritDoc} */
  927. public void image(ExternalGraphic eg) {
  928. if (bDefer) {
  929. return;
  930. }
  931. String uri = eg.getURL();
  932. ImageInfo info = null;
  933. try {
  934. //set image data
  935. FOUserAgent userAgent = eg.getUserAgent();
  936. ImageManager manager = userAgent.getImageManager();
  937. info = manager.getImageInfo(uri, userAgent.getImageSessionContext());
  938. putGraphic(eg, info);
  939. } catch (ImageException ie) {
  940. ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
  941. getUserAgent().getEventBroadcaster());
  942. eventProducer.imageError(this, uri, ie, null);
  943. } catch (FileNotFoundException fe) {
  944. ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
  945. getUserAgent().getEventBroadcaster());
  946. eventProducer.imageNotFound(this, (info != null ? info.toString() : uri), fe, null);
  947. } catch (IOException ioe) {
  948. ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
  949. getUserAgent().getEventBroadcaster());
  950. eventProducer.imageIOError(this, (info != null ? info.toString() : uri), ioe, null);
  951. }
  952. }
  953. /** {@inheritDoc} */
  954. public void endInstreamForeignObject(InstreamForeignObject ifo) {
  955. if (bDefer) {
  956. return;
  957. }
  958. try {
  959. XMLObj child = ifo.getChildXMLObj();
  960. Document doc = child.getDOMDocument();
  961. String ns = child.getNamespaceURI();
  962. ImageInfo info = new ImageInfo(null, null);
  963. // Set the resolution to that of the FOUserAgent
  964. FOUserAgent ua = ifo.getUserAgent();
  965. ImageSize size = new ImageSize();
  966. size.setResolution(ua.getSourceResolution());
  967. // Set the image size to the size of the svg.
  968. Point2D csize = new Point2D.Float(-1, -1);
  969. Point2D intrinsicDimensions = child.getDimension(csize);
  970. if (intrinsicDimensions == null) {
  971. ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
  972. getUserAgent().getEventBroadcaster());
  973. eventProducer.ifoNoIntrinsicSize(this, child.getLocator());
  974. return;
  975. }
  976. size.setSizeInMillipoints(
  977. (int)Math.round(intrinsicDimensions.getX() * 1000),
  978. (int)Math.round(intrinsicDimensions.getY() * 1000));
  979. size.calcPixelsFromSize();
  980. info.setSize(size);
  981. ImageXMLDOM image = new ImageXMLDOM(info, doc, ns);
  982. FOUserAgent userAgent = ifo.getUserAgent();
  983. ImageManager manager = userAgent.getImageManager();
  984. Map hints = ImageUtil.getDefaultHints(ua.getImageSessionContext());
  985. Image converted = manager.convertImage(image, FLAVORS, hints);
  986. putGraphic(ifo, converted);
  987. } catch (ImageException ie) {
  988. ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
  989. getUserAgent().getEventBroadcaster());
  990. eventProducer.imageError(this, null, ie, null);
  991. } catch (IOException ioe) {
  992. ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
  993. getUserAgent().getEventBroadcaster());
  994. eventProducer.imageIOError(this, null, ioe, null);
  995. }
  996. }
  997. private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
  998. ImageFlavor.RAW_EMF, ImageFlavor.RAW_PNG, ImageFlavor.RAW_JPEG
  999. };
  1000. /**
  1001. * Puts a graphic/image into the generated RTF file.
  1002. * @param abstractGraphic the graphic (external-graphic or instream-foreign-object)
  1003. * @param info the image info object
  1004. * @throws IOException In case of an I/O error
  1005. */
  1006. private void putGraphic(AbstractGraphics abstractGraphic, ImageInfo info)
  1007. throws IOException {
  1008. try {
  1009. FOUserAgent userAgent = abstractGraphic.getUserAgent();
  1010. ImageManager manager = userAgent.getImageManager();
  1011. ImageSessionContext sessionContext = userAgent.getImageSessionContext();
  1012. Map hints = ImageUtil.getDefaultHints(sessionContext);
  1013. Image image = manager.getImage(info, FLAVORS, hints, sessionContext);
  1014. putGraphic(abstractGraphic, image);
  1015. } catch (ImageException ie) {
  1016. ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
  1017. getUserAgent().getEventBroadcaster());
  1018. eventProducer.imageError(this, null, ie, null);
  1019. }
  1020. }
  1021. /**
  1022. * Puts a graphic/image into the generated RTF file.
  1023. * @param abstractGraphic the graphic (external-graphic or instream-foreign-object)
  1024. * @param image the image
  1025. * @throws IOException In case of an I/O error
  1026. */
  1027. private void putGraphic(AbstractGraphics abstractGraphic, Image image)
  1028. throws IOException {
  1029. byte[] rawData = null;
  1030. final ImageInfo info = image.getInfo();
  1031. if (image instanceof ImageRawStream) {
  1032. ImageRawStream rawImage = (ImageRawStream)image;
  1033. InputStream in = rawImage.createInputStream();
  1034. try {
  1035. rawData = IOUtils.toByteArray(in);
  1036. } finally {
  1037. IOUtils.closeQuietly(in);
  1038. }
  1039. }
  1040. if (rawData == null) {
  1041. ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
  1042. getUserAgent().getEventBroadcaster());
  1043. eventProducer.imageWritingError(this, null);
  1044. return;
  1045. }
  1046. //Set up percentage calculations
  1047. this.percentManager.setDimension(abstractGraphic);
  1048. PercentBaseContext pContext = new PercentBaseContext() {
  1049. public int getBaseLength(int lengthBase, FObj fobj) {
  1050. switch (lengthBase) {
  1051. case LengthBase.IMAGE_INTRINSIC_WIDTH:
  1052. return info.getSize().getWidthMpt();
  1053. case LengthBase.IMAGE_INTRINSIC_HEIGHT:
  1054. return info.getSize().getHeightMpt();
  1055. default:
  1056. return percentManager.getBaseLength(lengthBase, fobj);
  1057. }
  1058. }
  1059. };
  1060. ImageLayout layout = new ImageLayout(abstractGraphic, pContext,
  1061. image.getInfo().getSize().getDimensionMpt());
  1062. final IRtfTextrunContainer c
  1063. = (IRtfTextrunContainer)builderContext.getContainer(
  1064. IRtfTextrunContainer.class, true, this);
  1065. final RtfExternalGraphic rtfGraphic = c.getTextrun().newImage();
  1066. //set URL
  1067. if (info.getOriginalURI() != null) {
  1068. rtfGraphic.setURL(info.getOriginalURI());
  1069. }
  1070. rtfGraphic.setImageData(rawData);
  1071. FoUnitsConverter converter = FoUnitsConverter.getInstance();
  1072. Dimension viewport = layout.getViewportSize();
  1073. Rectangle placement = layout.getPlacement();
  1074. int cropLeft = Math.round(converter.convertMptToTwips(-placement.x));
  1075. int cropTop = Math.round(converter.convertMptToTwips(-placement.y));
  1076. int cropRight = Math.round(converter.convertMptToTwips(
  1077. -1 * (viewport.width - placement.x - placement.width)));
  1078. int cropBottom = Math.round(converter.convertMptToTwips(
  1079. -1 * (viewport.height - placement.y - placement.height)));
  1080. rtfGraphic.setCropping(cropLeft, cropTop, cropRight, cropBottom);
  1081. int width = Math.round(converter.convertMptToTwips(viewport.width));
  1082. int height = Math.round(converter.convertMptToTwips(viewport.height));
  1083. width += cropLeft + cropRight;
  1084. height += cropTop + cropBottom;
  1085. rtfGraphic.setWidthTwips(width);
  1086. rtfGraphic.setHeightTwips(height);
  1087. //TODO: make this configurable:
  1088. // int compression = m_context.m_options.getRtfExternalGraphicCompressionRate ();
  1089. int compression = 0;
  1090. if (compression != 0) {
  1091. if (!rtfGraphic.setCompressionRate(compression)) {
  1092. log.warn("The compression rate " + compression
  1093. + " is invalid. The value has to be between 1 and 100 %.");
  1094. }
  1095. }
  1096. }
  1097. /** {@inheritDoc} */
  1098. public void pageRef() {
  1099. }
  1100. /** {@inheritDoc} */
  1101. public void startFootnote(Footnote footnote) {
  1102. if (bDefer) {
  1103. return;
  1104. }
  1105. try {
  1106. IRtfTextrunContainer container
  1107. = (IRtfTextrunContainer)builderContext.getContainer(
  1108. IRtfTextrunContainer.class,
  1109. true, this);
  1110. RtfTextrun textrun = container.getTextrun();
  1111. RtfFootnote rtfFootnote = textrun.addFootnote();
  1112. builderContext.pushContainer(rtfFootnote);
  1113. } catch (IOException ioe) {
  1114. handleIOTrouble(ioe);
  1115. } catch (Exception e) {
  1116. log.error("startFootnote: " + e.getMessage());
  1117. throw new RuntimeException("Exception: " + e);
  1118. }
  1119. }
  1120. /** {@inheritDoc} */
  1121. public void endFootnote(Footnote footnote) {
  1122. if (bDefer) {
  1123. return;
  1124. }
  1125. builderContext.popContainer(RtfFootnote.class, this);
  1126. }
  1127. /** {@inheritDoc} */
  1128. public void startFootnoteBody(FootnoteBody body) {
  1129. if (bDefer) {
  1130. return;
  1131. }
  1132. try {
  1133. // @SuppressFBWarnings("BC_UNCONFIRMED_CAST_OF_RETURN_VALUE")
  1134. RtfFootnote rtfFootnote
  1135. = (RtfFootnote)builderContext.getContainer(
  1136. RtfFootnote.class,
  1137. true, this);
  1138. rtfFootnote.startBody();
  1139. } catch (IOException ioe) {
  1140. handleIOTrouble(ioe);
  1141. } catch (Exception e) {
  1142. log.error("startFootnoteBody: " + e.getMessage());
  1143. throw new RuntimeException("Exception: " + e);
  1144. }
  1145. }
  1146. /** {@inheritDoc} */
  1147. public void endFootnoteBody(FootnoteBody body) {
  1148. if (bDefer) {
  1149. return;
  1150. }
  1151. try {
  1152. // @SuppressFBWarnings("BC_UNCONFIRMED_CAST_OF_RETURN_VALUE")
  1153. RtfFootnote rtfFootnote
  1154. = (RtfFootnote)builderContext.getContainer(
  1155. RtfFootnote.class,
  1156. true, this);
  1157. rtfFootnote.endBody();
  1158. } catch (IOException ioe) {
  1159. handleIOTrouble(ioe);
  1160. } catch (Exception e) {
  1161. log.error("endFootnoteBody: " + e.getMessage());
  1162. throw new RuntimeException("Exception: " + e);
  1163. }
  1164. }
  1165. /** {@inheritDoc} */
  1166. public void startLeader(Leader l) {
  1167. if (bDefer) {
  1168. return;
  1169. }
  1170. try {
  1171. percentManager.setDimension(l);
  1172. RtfAttributes rtfAttr = TextAttributesConverter.convertLeaderAttributes(
  1173. l, percentManager);
  1174. IRtfTextrunContainer container
  1175. = (IRtfTextrunContainer)builderContext.getContainer(
  1176. IRtfTextrunContainer.class, true, this);
  1177. RtfTextrun textrun = container.getTextrun();
  1178. textrun.addLeader(rtfAttr);
  1179. } catch (IOException e) {
  1180. log.error("startLeader: " + e.getMessage());
  1181. throw new RuntimeException(e.getMessage());
  1182. } catch (FOPException e) {
  1183. log.error("startLeader: " + e.getMessage());
  1184. throw new RuntimeException(e.getMessage());
  1185. }
  1186. }
  1187. /**
  1188. * @param text FOText object
  1189. * @param characters CharSequence of the characters to process.
  1190. */
  1191. public void text(FOText text, CharSequence characters) {
  1192. if (bDefer) {
  1193. return;
  1194. }
  1195. try {
  1196. IRtfTextrunContainer container
  1197. = (IRtfTextrunContainer)builderContext.getContainer(
  1198. IRtfTextrunContainer.class, true, this);
  1199. RtfTextrun textrun = container.getTextrun();
  1200. RtfAttributes rtfAttr
  1201. = TextAttributesConverter.convertCharacterAttributes(text);
  1202. textrun.pushInlineAttributes(rtfAttr);
  1203. textrun.addString(characters.toString());
  1204. textrun.popInlineAttributes();
  1205. } catch (IOException ioe) {
  1206. handleIOTrouble(ioe);
  1207. } catch (Exception e) {
  1208. log.error("characters:" + e.getMessage());
  1209. throw new RuntimeException(e.getMessage());
  1210. }
  1211. }
  1212. /** {@inheritDoc} */
  1213. public void startPageNumber(PageNumber pagenum) {
  1214. if (bDefer) {
  1215. return;
  1216. }
  1217. try {
  1218. RtfAttributes rtfAttr
  1219. = TextAttributesConverter.convertCharacterAttributes(
  1220. pagenum);
  1221. IRtfTextrunContainer container
  1222. = (IRtfTextrunContainer)builderContext.getContainer(
  1223. IRtfTextrunContainer.class, true, this);
  1224. RtfTextrun textrun = container.getTextrun();
  1225. textrun.addPageNumber(rtfAttr);
  1226. } catch (IOException ioe) {
  1227. handleIOTrouble(ioe);
  1228. } catch (Exception e) {
  1229. log.error("startPageNumber: " + e.getMessage());
  1230. throw new RuntimeException(e.getMessage());
  1231. }
  1232. }
  1233. /** {@inheritDoc} */
  1234. public void endPageNumber(PageNumber pagenum) {
  1235. }
  1236. /** {@inheritDoc} */
  1237. public void startPageNumberCitation(PageNumberCitation l) {
  1238. if (bDefer) {
  1239. return;
  1240. }
  1241. try {
  1242. IRtfTextrunContainer container
  1243. = (IRtfTextrunContainer)builderContext.getContainer(
  1244. IRtfTextrunContainer.class, true, this);
  1245. RtfTextrun textrun = container.getTextrun();
  1246. textrun.addPageNumberCitation(l.getRefId());
  1247. } catch (Exception e) {
  1248. log.error("startPageNumberCitation: " + e.getMessage());
  1249. throw new RuntimeException(e.getMessage());
  1250. }
  1251. }
  1252. /** {@inheritDoc} */
  1253. public void startPageNumberCitationLast(PageNumberCitationLast l) {
  1254. if (bDefer) {
  1255. return;
  1256. }
  1257. try {
  1258. IRtfTextrunContainer container
  1259. = (IRtfTextrunContainer)builderContext.getContainer(
  1260. IRtfTextrunContainer.class, true, this);
  1261. RtfTextrun textrun = container.getTextrun();
  1262. textrun.addPageNumberCitation(l.getRefId());
  1263. } catch (RtfException e) {
  1264. log.error("startPageNumberCitationLast: " + e.getMessage());
  1265. throw new RuntimeException(e.getMessage());
  1266. } catch (IOException e) {
  1267. log.error("startPageNumberCitationLast: " + e.getMessage());
  1268. throw new RuntimeException(e.getMessage());
  1269. }
  1270. }
  1271. private void prepareTable(Table tab) {
  1272. // Allows to receive the available width of the table
  1273. percentManager.setDimension(tab);
  1274. // Table gets expanded by half of the border on each side inside Word
  1275. // When using wide borders the table gets cut off
  1276. int tabDiff = tab.getCommonBorderPaddingBackground().getBorderStartWidth(false) / 2
  1277. + tab.getCommonBorderPaddingBackground().getBorderEndWidth(false);
  1278. // check for "auto" value
  1279. if (!(tab.getInlineProgressionDimension().getMaximum(null).getLength()
  1280. instanceof EnumLength)) {
  1281. // value specified
  1282. percentManager.setDimension(tab,
  1283. tab.getInlineProgressionDimension().getMaximum(null)
  1284. .getLength().getValue(percentManager)
  1285. - tabDiff);
  1286. } else {
  1287. // set table width again without border width
  1288. percentManager.setDimension(tab, percentManager.getBaseLength(
  1289. LengthBase.CONTAINING_BLOCK_WIDTH, tab) - tabDiff);
  1290. }
  1291. ColumnSetup columnSetup = new ColumnSetup(tab);
  1292. //int sumOfColumns = columnSetup.getSumOfColumnWidths(percentManager);
  1293. float tableWidth = percentManager.getBaseLength(LengthBase.CONTAINING_BLOCK_WIDTH, tab);
  1294. float tableUnit = columnSetup.computeTableUnit(percentManager, Math.round(tableWidth));
  1295. percentManager.setTableUnit(tab, Math.round(tableUnit));
  1296. }
  1297. /**
  1298. * Calls the appropriate event handler for the passed FObj.
  1299. *
  1300. * @param foNode FO node whose event is to be called
  1301. * @param bStart TRUE calls the start handler, FALSE the end handler
  1302. */
  1303. private void invokeDeferredEvent(FONode foNode, boolean bStart) {
  1304. if (foNode instanceof PageSequence) {
  1305. if (bStart) {
  1306. startPageSequence((PageSequence) foNode);
  1307. } else {
  1308. endPageSequence((PageSequence) foNode);
  1309. }
  1310. } else if (foNode instanceof Flow) {
  1311. if (bStart) {
  1312. startFlow((Flow) foNode);
  1313. } else {
  1314. endFlow((Flow) foNode);
  1315. }
  1316. } else if (foNode instanceof StaticContent) {
  1317. if (bStart) {
  1318. startStatic(null);
  1319. } else {
  1320. endStatic(null);
  1321. }
  1322. } else if (foNode instanceof ExternalGraphic) {
  1323. if (bStart) {
  1324. image((ExternalGraphic) foNode);
  1325. }
  1326. } else if (foNode instanceof InstreamForeignObject) {
  1327. if (bStart) {
  1328. endInstreamForeignObject((InstreamForeignObject) foNode);
  1329. }
  1330. } else if (foNode instanceof Block) {
  1331. if (bStart) {
  1332. startBlock((Block) foNode);
  1333. } else {
  1334. endBlock((Block) foNode);
  1335. }
  1336. } else if (foNode instanceof BlockContainer) {
  1337. if (bStart) {
  1338. startBlockContainer((BlockContainer) foNode);
  1339. } else {
  1340. endBlockContainer((BlockContainer) foNode);
  1341. }
  1342. } else if (foNode instanceof BasicLink) {
  1343. //BasicLink must be placed before Inline
  1344. if (bStart) {
  1345. startLink((BasicLink) foNode);
  1346. } else {
  1347. endLink(null);
  1348. }
  1349. } else if (foNode instanceof Inline) {
  1350. if (bStart) {
  1351. startInline((Inline) foNode);
  1352. } else {
  1353. endInline((Inline) foNode);
  1354. }
  1355. } else if (foNode instanceof FOText) {
  1356. if (bStart) {
  1357. FOText text = (FOText) foNode;
  1358. text(text, text.getCharSequence());
  1359. }
  1360. } else if (foNode instanceof Character) {
  1361. if (bStart) {
  1362. Character c = (Character) foNode;
  1363. character(c);
  1364. }
  1365. } else if (foNode instanceof PageNumber) {
  1366. if (bStart) {
  1367. startPageNumber((PageNumber) foNode);
  1368. } else {
  1369. endPageNumber((PageNumber) foNode);
  1370. }
  1371. } else if (foNode instanceof Footnote) {
  1372. if (bStart) {
  1373. startFootnote((Footnote) foNode);
  1374. } else {
  1375. endFootnote((Footnote) foNode);
  1376. }
  1377. } else if (foNode instanceof FootnoteBody) {
  1378. if (bStart) {
  1379. startFootnoteBody((FootnoteBody) foNode);
  1380. } else {
  1381. endFootnoteBody((FootnoteBody) foNode);
  1382. }
  1383. } else if (foNode instanceof ListBlock) {
  1384. if (bStart) {
  1385. startList((ListBlock) foNode);
  1386. } else {
  1387. endList((ListBlock) foNode);
  1388. }
  1389. } else if (foNode instanceof ListItemBody) {
  1390. if (bStart) {
  1391. startListBody(null);
  1392. } else {
  1393. endListBody(null);
  1394. }
  1395. } else if (foNode instanceof ListItem) {
  1396. if (bStart) {
  1397. startListItem((ListItem) foNode);
  1398. } else {
  1399. endListItem((ListItem) foNode);
  1400. }
  1401. } else if (foNode instanceof ListItemLabel) {
  1402. if (bStart) {
  1403. startListLabel(null);
  1404. } else {
  1405. endListLabel(null);
  1406. }
  1407. } else if (foNode instanceof Table) {
  1408. if (bStart) {
  1409. startTable((Table) foNode);
  1410. } else {
  1411. endTable((Table) foNode);
  1412. }
  1413. } else if (foNode instanceof TableHeader) {
  1414. if (bStart) {
  1415. startHeader((TableHeader) foNode);
  1416. } else {
  1417. endHeader((TableHeader) foNode);
  1418. }
  1419. } else if (foNode instanceof TableFooter) {
  1420. if (bStart) {
  1421. startFooter((TableFooter) foNode);
  1422. } else {
  1423. endFooter((TableFooter) foNode);
  1424. }
  1425. } else if (foNode instanceof TableBody) {
  1426. if (bStart) {
  1427. startBody((TableBody) foNode);
  1428. } else {
  1429. endBody((TableBody) foNode);
  1430. }
  1431. } else if (foNode instanceof TableColumn) {
  1432. if (bStart) {
  1433. startColumn((TableColumn) foNode);
  1434. } else {
  1435. endColumn((TableColumn) foNode);
  1436. }
  1437. } else if (foNode instanceof TableRow) {
  1438. if (bStart) {
  1439. startRow((TableRow) foNode);
  1440. } else {
  1441. endRow((TableRow) foNode);
  1442. }
  1443. } else if (foNode instanceof TableCell) {
  1444. if (bStart) {
  1445. startCell((TableCell) foNode);
  1446. } else {
  1447. endCell((TableCell) foNode);
  1448. }
  1449. } else if (foNode instanceof Leader) {
  1450. if (bStart) {
  1451. startLeader((Leader) foNode);
  1452. }
  1453. } else if (foNode instanceof PageNumberCitation) {
  1454. if (bStart) {
  1455. startPageNumberCitation((PageNumberCitation) foNode);
  1456. } else {
  1457. endPageNumberCitation((PageNumberCitation) foNode);
  1458. }
  1459. } else if (foNode instanceof PageNumberCitationLast) {
  1460. if (bStart) {
  1461. startPageNumberCitationLast((PageNumberCitationLast) foNode);
  1462. } else {
  1463. endPageNumberCitationLast((PageNumberCitationLast) foNode);
  1464. }
  1465. } else {
  1466. RTFEventProducer eventProducer = RTFEventProducer.Provider.get(
  1467. getUserAgent().getEventBroadcaster());
  1468. eventProducer.ignoredDeferredEvent(this, foNode, bStart, foNode.getLocator());
  1469. }
  1470. }
  1471. /**
  1472. * Closes any mismatched tags that are detected in the RTF structure.
  1473. * @param containerClass The class representing the tag to close.
  1474. * @return Determines whether the tag mismatch has been handled.
  1475. */
  1476. public boolean endContainer(Class containerClass) {
  1477. if (containerClass == RtfTableRow.class) {
  1478. endRow(null);
  1479. return true;
  1480. }
  1481. return false;
  1482. }
  1483. /**
  1484. * Calls the event handlers for the passed FONode and all its elements.
  1485. *
  1486. * @param foNode FONode object which shall be recursed
  1487. */
  1488. private void recurseFONode(FONode foNode) {
  1489. invokeDeferredEvent(foNode, true);
  1490. if (foNode instanceof PageSequence) {
  1491. PageSequence pageSequence = (PageSequence) foNode;
  1492. Region regionBefore = pagemaster.getRegion(Constants.FO_REGION_BEFORE);
  1493. if (regionBefore != null) {
  1494. FONode staticBefore = pageSequence.getFlowMap().get(
  1495. regionBefore.getRegionName());
  1496. if (staticBefore != null) {
  1497. recurseFONode(staticBefore);
  1498. }
  1499. }
  1500. Region regionAfter = pagemaster.getRegion(Constants.FO_REGION_AFTER);
  1501. if (regionAfter != null) {
  1502. FONode staticAfter = pageSequence.getFlowMap().get(
  1503. regionAfter.getRegionName());
  1504. if (staticAfter != null) {
  1505. recurseFONode(staticAfter);
  1506. }
  1507. }
  1508. recurseFONode(pageSequence.getMainFlow());
  1509. } else if (foNode instanceof Table) {
  1510. Table table = (Table) foNode;
  1511. //recurse all table-columns
  1512. if (table.getColumns() != null) {
  1513. //Calculation for column-widths which are not set
  1514. prepareTable(table);
  1515. for (Object o : table.getColumns()) {
  1516. recurseFONode((FONode) o);
  1517. }
  1518. } else {
  1519. //TODO Implement implicit column setup handling!
  1520. RTFEventProducer eventProducer = RTFEventProducer.Provider.get(
  1521. getUserAgent().getEventBroadcaster());
  1522. eventProducer.explicitTableColumnsRequired(this, table.getLocator());
  1523. }
  1524. //recurse table-header
  1525. if (table.getTableHeader() != null) {
  1526. recurseFONode(table.getTableHeader());
  1527. }
  1528. //recurse table-footer
  1529. if (table.getTableFooter() != null) {
  1530. recurseFONode(table.getTableFooter());
  1531. }
  1532. if (foNode.getChildNodes() != null) {
  1533. for (Iterator it = foNode.getChildNodes(); it.hasNext();) {
  1534. recurseFONode((FONode) it.next());
  1535. }
  1536. }
  1537. } else if (foNode instanceof ListItem) {
  1538. ListItem item = (ListItem) foNode;
  1539. recurseFONode(item.getLabel());
  1540. recurseFONode(item.getBody());
  1541. } else if (foNode instanceof Footnote) {
  1542. Footnote fn = (Footnote)foNode;
  1543. recurseFONode(fn.getFootnoteCitation());
  1544. recurseFONode(fn.getFootnoteBody());
  1545. } else {
  1546. //Any other FO-Object: Simply recurse through all childNodes.
  1547. if (foNode.getChildNodes() != null) {
  1548. for (Iterator it = foNode.getChildNodes(); it.hasNext();) {
  1549. FONode fn = (FONode)it.next();
  1550. if (log.isTraceEnabled()) {
  1551. log.trace(" ChildNode for " + fn + " (" + fn.getName() + ")");
  1552. }
  1553. recurseFONode(fn);
  1554. }
  1555. }
  1556. }
  1557. invokeDeferredEvent(foNode, false);
  1558. }
  1559. }