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.

AbstractRenderer.java 28KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  1. /*
  2. * Copyright 1999-2005 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /* $Id$ */
  17. package org.apache.fop.render;
  18. // Java
  19. import java.awt.Rectangle;
  20. import java.awt.geom.Rectangle2D;
  21. import java.io.IOException;
  22. import java.io.OutputStream;
  23. import java.util.List;
  24. import java.util.Iterator;
  25. import java.util.Set;
  26. // XML
  27. import org.w3c.dom.Document;
  28. // FOP
  29. import org.apache.fop.apps.FOPException;
  30. import org.apache.fop.area.Area;
  31. import org.apache.fop.area.BeforeFloat;
  32. import org.apache.fop.area.Block;
  33. import org.apache.fop.area.BlockViewport;
  34. import org.apache.fop.area.BodyRegion;
  35. import org.apache.fop.area.CTM;
  36. import org.apache.fop.area.NormalFlow;
  37. import org.apache.fop.area.Footnote;
  38. import org.apache.fop.area.LineArea;
  39. import org.apache.fop.area.MainReference;
  40. import org.apache.fop.area.Span;
  41. import org.apache.fop.area.Page;
  42. import org.apache.fop.area.PageViewport;
  43. import org.apache.fop.area.RegionViewport;
  44. import org.apache.fop.area.RegionReference;
  45. import org.apache.fop.area.Trait;
  46. import org.apache.fop.area.OffDocumentItem;
  47. import org.apache.fop.area.inline.Container;
  48. import org.apache.fop.area.inline.ForeignObject;
  49. import org.apache.fop.area.inline.Image;
  50. import org.apache.fop.area.inline.InlineArea;
  51. import org.apache.fop.area.inline.InlineBlockParent;
  52. import org.apache.fop.area.inline.InlineParent;
  53. import org.apache.fop.area.inline.Leader;
  54. import org.apache.fop.area.inline.Space;
  55. import org.apache.fop.area.inline.Viewport;
  56. import org.apache.fop.area.inline.TextArea;
  57. import org.apache.fop.area.inline.Character;
  58. import org.apache.fop.area.inline.WordArea;
  59. import org.apache.fop.area.inline.SpaceArea;
  60. import org.apache.fop.apps.FOUserAgent;
  61. import org.apache.fop.fo.Constants;
  62. import org.apache.fop.fonts.FontInfo;
  63. import org.apache.commons.logging.Log;
  64. import org.apache.commons.logging.LogFactory;
  65. // Avalon
  66. import org.apache.avalon.framework.configuration.Configurable;
  67. import org.apache.avalon.framework.configuration.Configuration;
  68. import org.apache.avalon.framework.configuration.ConfigurationException;
  69. /**
  70. * Abstract base class for all renderers. The Abstract renderer does all the
  71. * top level processing of the area tree and adds some abstract methods to
  72. * handle viewports. This keeps track of the current block and inline position.
  73. */
  74. public abstract class AbstractRenderer
  75. implements Renderer, Configurable, Constants {
  76. /** logging instance */
  77. protected static Log log = LogFactory.getLog("org.apache.fop.render");
  78. /**
  79. * user agent
  80. */
  81. protected FOUserAgent userAgent;
  82. /**
  83. * block progression position
  84. */
  85. protected int currentBPPosition = 0;
  86. /**
  87. * inline progression position
  88. */
  89. protected int currentIPPosition = 0;
  90. /**
  91. * the block progression position of the containing block used for
  92. * absolutely positioned blocks
  93. */
  94. protected int containingBPPosition = 0;
  95. /**
  96. * the inline progression position of the containing block used for
  97. * absolutely positioned blocks
  98. */
  99. protected int containingIPPosition = 0;
  100. private Set warnedXMLHandlers;
  101. /**
  102. * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
  103. */
  104. public void configure(Configuration conf) throws ConfigurationException {
  105. }
  106. /**
  107. * @see org.apache.fop.render.Renderer#setupFontInfo(FontInfo)
  108. */
  109. public abstract void setupFontInfo(FontInfo fontInfo);
  110. /**
  111. * @see org.apache.fop.render.Renderer#setUserAgent(FOUserAgent)
  112. */
  113. public void setUserAgent(FOUserAgent agent) {
  114. userAgent = agent;
  115. }
  116. /** @see org.apache.fop.render.Renderer#startRenderer(OutputStream) */
  117. public void startRenderer(OutputStream outputStream)
  118. throws IOException { }
  119. /** @see org.apache.fop.render.Renderer#stopRenderer() */
  120. public void stopRenderer()
  121. throws IOException { }
  122. /**
  123. * Check if this renderer supports out of order rendering. If this renderer
  124. * supports out of order rendering then it means that the pages that are
  125. * not ready will be prepared and a future page will be rendered.
  126. *
  127. * @return True if the renderer supports out of order rendering
  128. * @see org.apache.fop.render.Renderer
  129. */
  130. public boolean supportsOutOfOrder() {
  131. return false;
  132. }
  133. /**
  134. * @see org.apache.fop.render.Renderer#processOffDocumentItem(OffDocumentItem)
  135. */
  136. public void processOffDocumentItem(OffDocumentItem oDI) { }
  137. /** @see org.apache.fop.render.Renderer#getGraphics2DAdapter() */
  138. public Graphics2DAdapter getGraphics2DAdapter() {
  139. return null;
  140. }
  141. /**
  142. * Prepare a page for rendering. This is called if the renderer supports
  143. * out of order rendering. The renderer should prepare the page so that a
  144. * page further on in the set of pages can be rendered. The body of the
  145. * page should not be rendered. The page will be rendered at a later time
  146. * by the call to render page.
  147. *
  148. * @see org.apache.fop.render.Renderer#preparePage(PageViewport)
  149. */
  150. public void preparePage(PageViewport page) { }
  151. /**
  152. * Utility method to convert a page sequence title to a string. Some
  153. * renderers may only be able to use a string title. A title is a sequence
  154. * of inline areas that this method attempts to convert to an equivalent
  155. * string.
  156. *
  157. * @param title The Title to convert
  158. * @return An expanded string representing the title
  159. */
  160. protected String convertTitleToString(LineArea title) {
  161. List children = title.getInlineAreas();
  162. String str = convertToString(children);
  163. return str.trim();
  164. }
  165. private String convertToString(List children) {
  166. StringBuffer sb = new StringBuffer();
  167. for (int count = 0; count < children.size(); count++) {
  168. InlineArea inline = (InlineArea) children.get(count);
  169. if (inline instanceof Character) {
  170. sb.append(((Character) inline).getChar());
  171. } else if (inline instanceof TextArea) {
  172. sb.append(((TextArea) inline).getText());
  173. } else if (inline instanceof InlineParent) {
  174. sb.append(convertToString(
  175. ((InlineParent) inline).getChildAreas()));
  176. } else {
  177. sb.append(" ");
  178. }
  179. }
  180. return sb.toString();
  181. }
  182. /** @see org.apache.fop.render.Renderer#startPageSequence(LineArea) */
  183. public void startPageSequence(LineArea seqTitle) {
  184. //do nothing
  185. }
  186. // normally this would be overriden to create a page in the
  187. // output
  188. /** @see org.apache.fop.render.Renderer#renderPage(PageViewport) */
  189. public void renderPage(PageViewport page)
  190. throws IOException, FOPException {
  191. Page p = page.getPage();
  192. renderPageAreas(p);
  193. }
  194. /**
  195. * Renders page areas.
  196. *
  197. * @param page The page whos page areas are to be rendered
  198. */
  199. protected void renderPageAreas(Page page) {
  200. /* Spec does not appear to specify whether fo:region-body should
  201. appear above or below side regions in cases of overlap. FOP
  202. decision is to have fo:region-body on top, hence it is rendered
  203. last here. */
  204. RegionViewport viewport;
  205. viewport = page.getRegionViewport(FO_REGION_BEFORE);
  206. renderRegionViewport(viewport);
  207. viewport = page.getRegionViewport(FO_REGION_START);
  208. renderRegionViewport(viewport);
  209. viewport = page.getRegionViewport(FO_REGION_END);
  210. renderRegionViewport(viewport);
  211. viewport = page.getRegionViewport(FO_REGION_AFTER);
  212. renderRegionViewport(viewport);
  213. viewport = page.getRegionViewport(FO_REGION_BODY);
  214. renderRegionViewport(viewport);
  215. }
  216. /**
  217. * Renders a region viewport. <p>
  218. *
  219. * The region may clip the area and it establishes a position from where
  220. * the region is placed.</p>
  221. *
  222. * @param port The region viewport to be rendered
  223. */
  224. protected void renderRegionViewport(RegionViewport port) {
  225. if (port != null) {
  226. Rectangle2D view = port.getViewArea();
  227. // The CTM will transform coordinates relative to
  228. // this region-reference area into page coords, so
  229. // set origin for the region to 0,0.
  230. currentBPPosition = 0;
  231. currentIPPosition = 0;
  232. RegionReference regionReference = port.getRegionReference();
  233. handleRegionTraits(port);
  234. // shouldn't the viewport have the CTM
  235. startVParea(regionReference.getCTM(), port.isClip() ? view : null);
  236. // do after starting viewport area
  237. if (regionReference.getRegionClass() == FO_REGION_BODY) {
  238. renderBodyRegion((BodyRegion) regionReference);
  239. } else {
  240. renderRegion(regionReference);
  241. }
  242. endVParea();
  243. }
  244. }
  245. /**
  246. * Establishes a new viewport area.
  247. *
  248. * @param ctm the coordinate transformation matrix to use
  249. * @param clippingRect the clipping rectangle if the viewport should be clipping,
  250. * null if no clipping is performed.
  251. */
  252. protected abstract void startVParea(CTM ctm, Rectangle2D clippingRect);
  253. /**
  254. * Signals exit from a viewport area. Subclasses can restore transformation matrices
  255. * valid before the viewport area was started.
  256. */
  257. protected abstract void endVParea();
  258. /**
  259. * Handle the traits for a region
  260. * This is used to draw the traits for the given page region.
  261. * (See Sect. 6.4.1.2 of XSL-FO spec.)
  262. * @param rv the RegionViewport whose region is to be drawn
  263. */
  264. protected void handleRegionTraits(RegionViewport rv) {
  265. // draw border and background
  266. }
  267. /**
  268. * Renders a region reference area.
  269. *
  270. * @param region The region reference area
  271. */
  272. protected void renderRegion(RegionReference region) {
  273. List blocks = region.getBlocks();
  274. renderBlocks(null, blocks);
  275. }
  276. /**
  277. * Renders a body region area.
  278. *
  279. * @param region The body region
  280. */
  281. protected void renderBodyRegion(BodyRegion region) {
  282. BeforeFloat bf = region.getBeforeFloat();
  283. if (bf != null) {
  284. renderBeforeFloat(bf);
  285. }
  286. MainReference mr = region.getMainReference();
  287. if (mr != null) {
  288. renderMainReference(mr);
  289. }
  290. Footnote foot = region.getFootnote();
  291. if (foot != null) {
  292. renderFootnote(foot);
  293. }
  294. }
  295. /**
  296. * Renders a before float area.
  297. *
  298. * @param bf The before float area
  299. */
  300. protected void renderBeforeFloat(BeforeFloat bf) {
  301. List blocks = bf.getChildAreas();
  302. if (blocks != null) {
  303. renderBlocks(null, blocks);
  304. Block sep = bf.getSeparator();
  305. if (sep != null) {
  306. renderBlock(sep);
  307. }
  308. }
  309. }
  310. /**
  311. * Renders a footnote
  312. *
  313. * @param footnote The footnote
  314. */
  315. protected void renderFootnote(Footnote footnote) {
  316. currentBPPosition += footnote.getTop();
  317. List blocks = footnote.getChildAreas();
  318. if (blocks != null) {
  319. Block sep = footnote.getSeparator();
  320. if (sep != null) {
  321. renderBlock(sep);
  322. }
  323. renderBlocks(null, blocks);
  324. }
  325. }
  326. /**
  327. * Renders the main reference area.
  328. * <p>
  329. * The main reference area contains a list of spans that are
  330. * stacked on the page.
  331. * The spans contain a list of normal flow reference areas
  332. * that are positioned into columns.
  333. * </p>
  334. *
  335. * @param mr The main reference area
  336. */
  337. protected void renderMainReference(MainReference mr) {
  338. int saveIPPos = currentIPPosition;
  339. Span span = null;
  340. List spans = mr.getSpans();
  341. int saveBPPos = currentBPPosition;
  342. int saveSpanBPPos = saveBPPos;
  343. for (int count = 0; count < spans.size(); count++) {
  344. span = (Span) spans.get(count);
  345. for (int c = 0; c < span.getColumnCount(); c++) {
  346. NormalFlow flow = (NormalFlow) span.getNormalFlow(c);
  347. if (flow != null) {
  348. currentBPPosition = saveSpanBPPos;
  349. renderFlow(flow);
  350. currentIPPosition += flow.getIPD();
  351. currentIPPosition += mr.getColumnGap();
  352. }
  353. }
  354. currentIPPosition = saveIPPos;
  355. currentBPPosition = saveSpanBPPos + span.getHeight();
  356. saveSpanBPPos = currentBPPosition;
  357. }
  358. currentBPPosition = saveBPPos;
  359. }
  360. /**
  361. * Renders a flow reference area.
  362. *
  363. * @param flow The flow reference area
  364. */
  365. protected void renderFlow(NormalFlow flow) {
  366. // the normal flow reference area contains stacked blocks
  367. List blocks = flow.getChildAreas();
  368. if (blocks != null) {
  369. renderBlocks(null, blocks);
  370. }
  371. }
  372. /**
  373. * Handle block traits.
  374. * This method is called when the correct ip and bp posiiton is
  375. * set. This should be overridden to draw border and background
  376. * traits for the block area.
  377. *
  378. * @param block the block area
  379. */
  380. protected void handleBlockTraits(Block block) {
  381. // draw border and background
  382. }
  383. /**
  384. * Renders a block viewport.
  385. *
  386. * @param bv The block viewport
  387. * @param children The children to render within the block viewport
  388. */
  389. protected void renderBlockViewport(BlockViewport bv, List children) {
  390. // clip and position viewport if necessary
  391. if (bv.getPositioning() == Block.ABSOLUTE) {
  392. // save positions
  393. int saveIP = currentIPPosition;
  394. int saveBP = currentBPPosition;
  395. Rectangle2D clippingRect = null;
  396. if (bv.getClip()) {
  397. clippingRect = new Rectangle(saveIP, saveBP, bv.getIPD(), bv.getIPD());
  398. }
  399. CTM ctm = bv.getCTM();
  400. currentIPPosition = 0;
  401. currentBPPosition = 0;
  402. startVParea(ctm, clippingRect);
  403. handleBlockTraits(bv);
  404. renderBlocks(bv, children);
  405. endVParea();
  406. // clip if necessary
  407. currentIPPosition = saveIP;
  408. currentBPPosition = saveBP;
  409. } else {
  410. // save position and offset
  411. int saveIP = currentIPPosition;
  412. int saveBP = currentBPPosition;
  413. handleBlockTraits(bv);
  414. renderBlocks(bv, children);
  415. currentIPPosition = saveIP;
  416. currentBPPosition = saveBP + bv.getAllocBPD();
  417. }
  418. }
  419. /**
  420. * Renders a list of block areas.
  421. *
  422. * @param parent the parent block if the parent is a block, otherwise
  423. * a null value.
  424. * @param blocks The block areas
  425. */
  426. protected void renderBlocks(Block parent, List blocks) {
  427. int saveIP = currentIPPosition;
  428. int saveBP = currentBPPosition;
  429. // Calculate the position of the content rectangle.
  430. if (parent != null && !Boolean.TRUE.equals(parent.getTrait(Trait.IS_VIEWPORT_AREA))) {
  431. currentBPPosition += parent.getBorderAndPaddingWidthBefore();
  432. /* This is unnecessary now as we're going to use the *-indent traits
  433. currentIPPosition += parent.getBorderAndPaddingWidthStart();
  434. Integer spaceStart = (Integer) parent.getTrait(Trait.SPACE_START);
  435. if (spaceStart != null) {
  436. currentIPPosition += spaceStart.intValue();
  437. }*/
  438. }
  439. // the position of the containing block is used for
  440. // absolutely positioned areas
  441. int contBP = currentBPPosition;
  442. int contIP = currentIPPosition;
  443. containingBPPosition = currentBPPosition;
  444. containingIPPosition = currentIPPosition;
  445. for (int count = 0; count < blocks.size(); count++) {
  446. Object obj = blocks.get(count);
  447. if (obj instanceof Block) {
  448. currentIPPosition = contIP;
  449. containingBPPosition = contBP;
  450. containingIPPosition = contIP;
  451. renderBlock((Block) obj);
  452. containingBPPosition = contBP;
  453. containingIPPosition = contIP;
  454. } else {
  455. // a line area is rendered from the top left position
  456. // of the line, each inline object is offset from there
  457. LineArea line = (LineArea) obj;
  458. currentIPPosition = contIP
  459. + parent.getStartIndent()
  460. + line.getStartIndent();
  461. renderLineArea(line);
  462. //InlineArea child = (InlineArea) line.getInlineAreas().get(0);
  463. currentBPPosition += line.getAllocBPD();
  464. }
  465. currentIPPosition = saveIP;
  466. }
  467. }
  468. /**
  469. * Renders a block area.
  470. *
  471. * @param block The block area
  472. */
  473. protected void renderBlock(Block block) {
  474. List children = block.getChildAreas();
  475. if (block instanceof BlockViewport) {
  476. if (children != null) {
  477. renderBlockViewport((BlockViewport) block, children);
  478. } else {
  479. handleBlockTraits(block);
  480. // simply move position
  481. currentBPPosition += block.getAllocBPD();
  482. }
  483. } else {
  484. // save position and offset
  485. int saveIP = currentIPPosition;
  486. int saveBP = currentBPPosition;
  487. if (block.getPositioning() == Block.ABSOLUTE) {
  488. currentIPPosition += block.getXOffset();
  489. currentBPPosition += block.getYOffset();
  490. currentBPPosition += block.getSpaceBefore();
  491. handleBlockTraits(block);
  492. if (children != null) {
  493. renderBlocks(block, children);
  494. }
  495. // absolute blocks do not effect the layout
  496. currentBPPosition = saveBP;
  497. } else {
  498. // relative blocks are offset
  499. currentIPPosition += block.getXOffset();
  500. currentBPPosition += block.getYOffset();
  501. currentBPPosition += block.getSpaceBefore();
  502. handleBlockTraits(block);
  503. if (children != null) {
  504. renderBlocks(block, children);
  505. }
  506. // stacked and relative blocks effect stacking
  507. currentIPPosition = saveIP;
  508. currentBPPosition = saveBP + block.getAllocBPD();
  509. }
  510. }
  511. }
  512. /**
  513. * Renders a line area. <p>
  514. *
  515. * A line area may have grouped styling for its children such as underline,
  516. * background.</p>
  517. *
  518. * @param line The line area
  519. */
  520. protected void renderLineArea(LineArea line) {
  521. List children = line.getInlineAreas();
  522. int saveBP = currentBPPosition;
  523. currentBPPosition += line.getSpaceBefore();
  524. for (int count = 0; count < children.size(); count++) {
  525. InlineArea inline = (InlineArea) children.get(count);
  526. renderInlineArea(inline);
  527. }
  528. currentBPPosition = saveBP;
  529. }
  530. /**
  531. * Render the given InlineArea.
  532. * @param inlineArea inline area text to render
  533. */
  534. protected void renderInlineArea(InlineArea inlineArea) {
  535. if (inlineArea instanceof TextArea) {
  536. renderText((TextArea) inlineArea);
  537. } else if (inlineArea instanceof Character) {
  538. renderCharacter((Character) inlineArea);
  539. } else if (inlineArea instanceof WordArea) {
  540. renderWord((WordArea) inlineArea);
  541. } else if (inlineArea instanceof SpaceArea) {
  542. renderSpace((SpaceArea) inlineArea);
  543. } else if (inlineArea instanceof InlineParent) {
  544. renderInlineParent((InlineParent) inlineArea);
  545. } else if (inlineArea instanceof InlineBlockParent) {
  546. renderInlineBlockParent((InlineBlockParent) inlineArea);
  547. } else if (inlineArea instanceof Space) {
  548. renderInlineSpace((Space) inlineArea);
  549. } else if (inlineArea instanceof Viewport) {
  550. renderViewport((Viewport) inlineArea);
  551. } else if (inlineArea instanceof Leader) {
  552. renderLeader((Leader) inlineArea);
  553. }
  554. }
  555. /**
  556. * Render the given Character.
  557. * @param ch the character to render
  558. */
  559. protected void renderCharacter(Character ch) {
  560. currentIPPosition += ch.getAllocIPD();
  561. }
  562. /**
  563. * Render the given Space.
  564. * @param space the space to render
  565. */
  566. protected void renderInlineSpace(Space space) {
  567. // an inline space moves the inline progression position
  568. // for the current block by the width or height of the space
  569. // it may also have styling (only on this object) that needs
  570. // handling
  571. currentIPPosition += space.getAllocIPD();
  572. }
  573. /**
  574. * Render the given Leader.
  575. * @param area the leader to render
  576. */
  577. protected void renderLeader(Leader area) {
  578. currentIPPosition += area.getAllocIPD();
  579. }
  580. /**
  581. * Render the given TextArea.
  582. * @param text the text to render
  583. */
  584. protected void renderText(TextArea text) {
  585. int saveIP = currentIPPosition;
  586. int saveBP = currentBPPosition;
  587. Iterator iter = text.getChildAreas().iterator();
  588. while (iter.hasNext()) {
  589. renderInlineArea((InlineArea) iter.next());
  590. }
  591. currentIPPosition = saveIP + text.getAllocIPD();
  592. }
  593. /**
  594. * Render the given WordArea.
  595. * @param word the word to render
  596. */
  597. protected void renderWord(WordArea word) {
  598. currentIPPosition += word.getAllocIPD();
  599. }
  600. /**
  601. * Render the given SpaceArea.
  602. * @param space the space to render
  603. */
  604. protected void renderSpace(SpaceArea space) {
  605. currentIPPosition += space.getAllocIPD();
  606. }
  607. /**
  608. * Render the given InlineParent.
  609. * @param ip the inline parent to render
  610. */
  611. protected void renderInlineParent(InlineParent ip) {
  612. int saveIP = currentIPPosition;
  613. int saveBP = currentBPPosition;
  614. currentIPPosition += ip.getBorderAndPaddingWidthStart();
  615. currentBPPosition += ip.getOffset();
  616. Iterator iter = ip.getChildAreas().iterator();
  617. while (iter.hasNext()) {
  618. renderInlineArea((InlineArea) iter.next());
  619. }
  620. currentIPPosition = saveIP + ip.getAllocIPD();
  621. currentBPPosition = saveBP;
  622. }
  623. /**
  624. * Render the given InlineBlockParent.
  625. * @param ibp the inline block parent to render
  626. */
  627. protected void renderInlineBlockParent(InlineBlockParent ibp) {
  628. currentIPPosition += ibp.getBorderAndPaddingWidthStart();
  629. // For inline content the BP position is updated by the enclosing line area
  630. int saveBP = currentBPPosition;
  631. currentBPPosition += ibp.getOffset();
  632. renderBlock(ibp.getChildArea());
  633. currentBPPosition = saveBP;
  634. }
  635. /**
  636. * Render the given Viewport.
  637. * @param viewport the viewport to render
  638. */
  639. protected void renderViewport(Viewport viewport) {
  640. Area content = viewport.getContent();
  641. int saveBP = currentBPPosition;
  642. currentBPPosition += viewport.getOffset();
  643. Rectangle2D contpos = viewport.getContentPosition();
  644. if (content instanceof Image) {
  645. renderImage((Image) content, contpos);
  646. } else if (content instanceof Container) {
  647. renderContainer((Container) content);
  648. } else if (content instanceof ForeignObject) {
  649. renderForeignObject((ForeignObject) content, contpos);
  650. }
  651. currentIPPosition += viewport.getAllocIPD();
  652. currentBPPosition = saveBP;
  653. }
  654. /**
  655. * Renders an image area.
  656. *
  657. * @param image The image
  658. * @param pos The target position of the image
  659. * (todo) Make renderImage() protected
  660. */
  661. public void renderImage(Image image, Rectangle2D pos) {
  662. // Default: do nothing.
  663. // Some renderers (ex. Text) don't support images.
  664. }
  665. /**
  666. * Tells the renderer to render an inline container.
  667. * @param cont The inline container area
  668. */
  669. protected void renderContainer(Container cont) {
  670. int saveIP = currentIPPosition;
  671. int saveBP = currentBPPosition;
  672. List blocks = cont.getBlocks();
  673. renderBlocks(null, blocks);
  674. currentIPPosition = saveIP;
  675. currentBPPosition = saveBP;
  676. }
  677. /**
  678. * Renders a foreign object area.
  679. *
  680. * @param fo The foreign object area
  681. * @param pos The target position of the foreign object
  682. * (todo) Make renderForeignObject() protected
  683. */
  684. public void renderForeignObject(ForeignObject fo, Rectangle2D pos) {
  685. // Default: do nothing.
  686. // Some renderers (ex. Text) don't support foreign objects.
  687. }
  688. /**
  689. * Returns the configuration subtree for a specific renderer.
  690. * @param cfg the renderer configuration
  691. * @param namespace the namespace (i.e. the XMLHandler) for which the configuration should
  692. * be returned
  693. * @return the requested configuration subtree, null if there's no configuration
  694. */
  695. public static Configuration getHandlerConfig(Configuration cfg, String namespace) {
  696. if (cfg == null || namespace == null) {
  697. return null;
  698. }
  699. Configuration handlerConfig = null;
  700. Configuration[] children = cfg.getChildren("xml-handler");
  701. for (int i = 0; i < children.length; ++i) {
  702. try {
  703. if (children[i].getAttribute("namespace").equals(namespace)) {
  704. handlerConfig = children[i];
  705. break;
  706. }
  707. } catch (ConfigurationException e) {
  708. // silently pass over configurations without namespace
  709. }
  710. }
  711. if (log.isDebugEnabled()) {
  712. log.debug((handlerConfig == null ? "No" : "")
  713. + "XML handler configuration found for namespace " + namespace);
  714. }
  715. return handlerConfig;
  716. }
  717. /**
  718. * Render the xml document with the given xml namespace.
  719. * The Render Context is by the handle to render into the current
  720. * rendering target.
  721. * @param ctx rendering context
  722. * @param doc DOM Document containing the source document
  723. * @param namespace Namespace URI of the document
  724. */
  725. public void renderXML(RendererContext ctx, Document doc,
  726. String namespace) {
  727. XMLHandler handler = userAgent.getXMLHandlerRegistry().getXMLHandler(
  728. this, namespace);
  729. if (handler != null) {
  730. try {
  731. //Optional XML handler configuration
  732. Configuration cfg = userAgent.getUserRendererConfig(getMimeType());
  733. if (cfg != null) {
  734. cfg = getHandlerConfig(cfg, namespace);
  735. if (cfg != null) {
  736. ctx.setProperty(RendererContextConstants.HANDLER_CONFIGURATION, cfg);
  737. }
  738. }
  739. handler.handleXML(ctx, doc, namespace);
  740. } catch (Throwable t) {
  741. // could not handle document
  742. log.error("Some XML content will be ignored. "
  743. + "Could not render XML", t);
  744. }
  745. } else {
  746. if (warnedXMLHandlers == null) {
  747. warnedXMLHandlers = new java.util.HashSet();
  748. }
  749. if (!warnedXMLHandlers.contains(namespace)) {
  750. // no handler found for document
  751. warnedXMLHandlers.add(namespace);
  752. log.warn("Some XML content will be ignored. "
  753. + "No handler defined for XML: " + namespace);
  754. }
  755. }
  756. }
  757. /**
  758. * Get the MIME type of the renderer.
  759. *
  760. * @return The MIME type of the renderer
  761. */
  762. public String getMimeType() {
  763. return null;
  764. }
  765. }