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 62KB

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