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