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

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