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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860
  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.ResourceEventProducer;
  32. import org.apache.fop.apps.FOPException;
  33. import org.apache.fop.apps.FOUserAgent;
  34. import org.apache.fop.area.Area;
  35. import org.apache.fop.area.BeforeFloat;
  36. import org.apache.fop.area.Block;
  37. import org.apache.fop.area.BlockViewport;
  38. import org.apache.fop.area.BodyRegion;
  39. import org.apache.fop.area.CTM;
  40. import org.apache.fop.area.Footnote;
  41. import org.apache.fop.area.LineArea;
  42. import org.apache.fop.area.MainReference;
  43. import org.apache.fop.area.NormalFlow;
  44. import org.apache.fop.area.OffDocumentItem;
  45. import org.apache.fop.area.Page;
  46. import org.apache.fop.area.PageSequence;
  47. import org.apache.fop.area.PageViewport;
  48. import org.apache.fop.area.RegionReference;
  49. import org.apache.fop.area.RegionViewport;
  50. import org.apache.fop.area.Span;
  51. import org.apache.fop.area.Trait;
  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.fo.Constants;
  65. import org.apache.fop.fonts.FontInfo;
  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 final 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. //TODO Discuss removing old deprecated method startPageSequence(LineArea)
  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. if (viewport != null) {
  217. renderRegionViewport(viewport);
  218. }
  219. viewport = page.getRegionViewport(FO_REGION_START);
  220. if (viewport != null) {
  221. renderRegionViewport(viewport);
  222. }
  223. viewport = page.getRegionViewport(FO_REGION_END);
  224. if (viewport != null) {
  225. renderRegionViewport(viewport);
  226. }
  227. viewport = page.getRegionViewport(FO_REGION_AFTER);
  228. if (viewport != null) {
  229. renderRegionViewport(viewport);
  230. }
  231. viewport = page.getRegionViewport(FO_REGION_BODY);
  232. if (viewport != null) {
  233. renderRegionViewport(viewport);
  234. }
  235. }
  236. /**
  237. * Renders a region viewport. <p>
  238. *
  239. * The region may clip the area and it establishes a position from where
  240. * the region is placed.</p>
  241. *
  242. * @param port The region viewport to be rendered
  243. */
  244. protected void renderRegionViewport(RegionViewport port) {
  245. Rectangle2D view = port.getViewArea();
  246. // The CTM will transform coordinates relative to
  247. // this region-reference area into page coords, so
  248. // set origin for the region to 0,0.
  249. currentBPPosition = 0;
  250. currentIPPosition = 0;
  251. RegionReference regionReference = port.getRegionReference();
  252. handleRegionTraits(port);
  253. // shouldn't the viewport have the CTM
  254. startVParea(regionReference.getCTM(), port.isClip() ? view : null);
  255. // do after starting viewport area
  256. if (regionReference.getRegionClass() == FO_REGION_BODY) {
  257. renderBodyRegion((BodyRegion) regionReference);
  258. } else {
  259. renderRegion(regionReference);
  260. }
  261. endVParea();
  262. }
  263. /**
  264. * Establishes a new viewport area.
  265. *
  266. * @param ctm the coordinate transformation matrix to use
  267. * @param clippingRect the clipping rectangle if the viewport should be clipping,
  268. * null if no clipping is performed.
  269. */
  270. protected abstract void startVParea(CTM ctm, Rectangle2D clippingRect);
  271. /**
  272. * Signals exit from a viewport area. Subclasses can restore transformation matrices
  273. * valid before the viewport area was started.
  274. */
  275. protected abstract void endVParea();
  276. /**
  277. * Handle the traits for a region
  278. * This is used to draw the traits for the given page region.
  279. * (See Sect. 6.4.1.2 of XSL-FO spec.)
  280. * @param rv the RegionViewport whose region is to be drawn
  281. */
  282. protected void handleRegionTraits(RegionViewport rv) {
  283. // draw border and background
  284. }
  285. /**
  286. * Renders a region reference area.
  287. *
  288. * @param region The region reference area
  289. */
  290. protected void renderRegion(RegionReference region) {
  291. renderBlocks(null, region.getBlocks());
  292. }
  293. /**
  294. * Renders a body region area.
  295. *
  296. * @param region The body region
  297. */
  298. protected void renderBodyRegion(BodyRegion region) {
  299. BeforeFloat bf = region.getBeforeFloat();
  300. if (bf != null) {
  301. renderBeforeFloat(bf);
  302. }
  303. MainReference mr = region.getMainReference();
  304. if (mr != null) {
  305. renderMainReference(mr);
  306. }
  307. Footnote foot = region.getFootnote();
  308. if (foot != null) {
  309. renderFootnote(foot);
  310. }
  311. }
  312. /**
  313. * Renders a before float area.
  314. *
  315. * @param bf The before float area
  316. */
  317. protected void renderBeforeFloat(BeforeFloat bf) {
  318. List blocks = bf.getChildAreas();
  319. if (blocks != null) {
  320. renderBlocks(null, blocks);
  321. Block sep = bf.getSeparator();
  322. if (sep != null) {
  323. renderBlock(sep);
  324. }
  325. }
  326. }
  327. /**
  328. * Renders a footnote
  329. *
  330. * @param footnote The footnote
  331. */
  332. protected void renderFootnote(Footnote footnote) {
  333. currentBPPosition += footnote.getTop();
  334. List blocks = footnote.getChildAreas();
  335. if (blocks != null) {
  336. Block sep = footnote.getSeparator();
  337. if (sep != null) {
  338. renderBlock(sep);
  339. }
  340. renderBlocks(null, blocks);
  341. }
  342. }
  343. /**
  344. * Renders the main reference area.
  345. * <p>
  346. * The main reference area contains a list of spans that are
  347. * stacked on the page.
  348. * The spans contain a list of normal flow reference areas
  349. * that are positioned into columns.
  350. * </p>
  351. *
  352. * @param mr The main reference area
  353. */
  354. protected void renderMainReference(MainReference mr) {
  355. int saveIPPos = currentIPPosition;
  356. Span span = null;
  357. List spans = mr.getSpans();
  358. int saveBPPos = currentBPPosition;
  359. int saveSpanBPPos = saveBPPos;
  360. for (int count = 0; count < spans.size(); count++) {
  361. span = (Span) spans.get(count);
  362. for (int c = 0; c < span.getColumnCount(); c++) {
  363. NormalFlow flow = span.getNormalFlow(c);
  364. if (flow != null) {
  365. currentBPPosition = saveSpanBPPos;
  366. renderFlow(flow);
  367. currentIPPosition += flow.getIPD();
  368. currentIPPosition += mr.getColumnGap();
  369. }
  370. }
  371. currentIPPosition = saveIPPos;
  372. currentBPPosition = saveSpanBPPos + span.getHeight();
  373. saveSpanBPPos = currentBPPosition;
  374. }
  375. currentBPPosition = saveBPPos;
  376. }
  377. /**
  378. * Renders a flow reference area.
  379. *
  380. * @param flow The flow reference area
  381. */
  382. protected void renderFlow(NormalFlow flow) {
  383. // the normal flow reference area contains stacked blocks
  384. List blocks = flow.getChildAreas();
  385. if (blocks != null) {
  386. renderBlocks(null, blocks);
  387. }
  388. }
  389. /**
  390. * Handle block traits.
  391. * This method is called when the correct ip and bp posiiton is
  392. * set. This should be overridden to draw border and background
  393. * traits for the block area.
  394. *
  395. * @param block the block area
  396. */
  397. protected void handleBlockTraits(Block block) {
  398. // draw border and background
  399. }
  400. /**
  401. * Renders a block viewport.
  402. *
  403. * @param bv The block viewport
  404. * @param children The children to render within the block viewport
  405. */
  406. protected void renderBlockViewport(BlockViewport bv, List children) {
  407. // clip and position viewport if necessary
  408. if (bv.getPositioning() == Block.ABSOLUTE) {
  409. // save positions
  410. int saveIP = currentIPPosition;
  411. int saveBP = currentBPPosition;
  412. Rectangle2D clippingRect = null;
  413. if (bv.getClip()) {
  414. clippingRect = new Rectangle(saveIP, saveBP, bv.getIPD(), bv.getBPD());
  415. }
  416. CTM ctm = bv.getCTM();
  417. currentIPPosition = 0;
  418. currentBPPosition = 0;
  419. startVParea(ctm, clippingRect);
  420. handleBlockTraits(bv);
  421. renderBlocks(bv, children);
  422. endVParea();
  423. // clip if necessary
  424. currentIPPosition = saveIP;
  425. currentBPPosition = saveBP;
  426. } else {
  427. // save position and offset
  428. int saveIP = currentIPPosition;
  429. int saveBP = currentBPPosition;
  430. handleBlockTraits(bv);
  431. renderBlocks(bv, children);
  432. currentIPPosition = saveIP;
  433. currentBPPosition = saveBP + bv.getAllocBPD();
  434. }
  435. }
  436. /**
  437. * Renders a block area that represents a reference area. The reference area establishes
  438. * a new coordinate system.
  439. * @param block the block area
  440. */
  441. protected abstract void renderReferenceArea(Block block);
  442. /**
  443. * Renders a list of block areas.
  444. *
  445. * @param parent the parent block if the parent is a block, otherwise
  446. * a null value.
  447. * @param blocks The block areas
  448. */
  449. protected void renderBlocks(Block parent, List blocks) {
  450. int saveIP = currentIPPosition;
  451. // int saveBP = currentBPPosition;
  452. // Calculate the position of the content rectangle.
  453. if (parent != null && !parent.getTraitAsBoolean(Trait.IS_VIEWPORT_AREA)) {
  454. currentBPPosition += parent.getBorderAndPaddingWidthBefore();
  455. /* This is unnecessary now as we're going to use the *-indent traits
  456. currentIPPosition += parent.getBorderAndPaddingWidthStart();
  457. Integer spaceStart = (Integer) parent.getTrait(Trait.SPACE_START);
  458. if (spaceStart != null) {
  459. currentIPPosition += spaceStart.intValue();
  460. }*/
  461. }
  462. // the position of the containing block is used for
  463. // absolutely positioned areas
  464. int contBP = currentBPPosition;
  465. int contIP = currentIPPosition;
  466. containingBPPosition = currentBPPosition;
  467. containingIPPosition = currentIPPosition;
  468. for (int count = 0; count < blocks.size(); count++) {
  469. Object obj = blocks.get(count);
  470. if (obj instanceof Block) {
  471. currentIPPosition = contIP;
  472. containingBPPosition = contBP;
  473. containingIPPosition = contIP;
  474. renderBlock((Block) obj);
  475. containingBPPosition = contBP;
  476. containingIPPosition = contIP;
  477. } else {
  478. // a line area is rendered from the top left position
  479. // of the line, each inline object is offset from there
  480. LineArea line = (LineArea) obj;
  481. currentIPPosition = contIP
  482. + parent.getStartIndent()
  483. + line.getStartIndent();
  484. renderLineArea(line);
  485. //InlineArea child = (InlineArea) line.getInlineAreas().get(0);
  486. currentBPPosition += line.getAllocBPD();
  487. }
  488. currentIPPosition = saveIP;
  489. }
  490. }
  491. /**
  492. * Renders a block area.
  493. *
  494. * @param block The block area
  495. */
  496. protected void renderBlock(Block block) {
  497. List children = block.getChildAreas();
  498. if (block instanceof BlockViewport) {
  499. if (children != null) {
  500. renderBlockViewport((BlockViewport) block, children);
  501. } else {
  502. handleBlockTraits(block);
  503. // simply move position
  504. currentBPPosition += block.getAllocBPD();
  505. }
  506. } else if (block.getTraitAsBoolean(Trait.IS_REFERENCE_AREA)) {
  507. renderReferenceArea(block);
  508. } else {
  509. // save position and offset
  510. int saveIP = currentIPPosition;
  511. int saveBP = currentBPPosition;
  512. currentIPPosition += block.getXOffset();
  513. currentBPPosition += block.getYOffset();
  514. currentBPPosition += block.getSpaceBefore();
  515. handleBlockTraits(block);
  516. if (children != null) {
  517. renderBlocks(block, children);
  518. }
  519. if (block.getPositioning() == Block.ABSOLUTE) {
  520. // absolute blocks do not effect the layout
  521. currentBPPosition = saveBP;
  522. } else {
  523. // stacked and relative blocks effect stacking
  524. currentIPPosition = saveIP;
  525. currentBPPosition = saveBP + block.getAllocBPD();
  526. }
  527. }
  528. }
  529. /**
  530. * Renders a line area. <p>
  531. *
  532. * A line area may have grouped styling for its children such as underline,
  533. * background.</p>
  534. *
  535. * @param line The line area
  536. */
  537. protected void renderLineArea(LineArea line) {
  538. List children = line.getInlineAreas();
  539. int saveBP = currentBPPosition;
  540. currentBPPosition += line.getSpaceBefore();
  541. for (int count = 0; count < children.size(); count++) {
  542. InlineArea inline = (InlineArea) children.get(count);
  543. renderInlineArea(inline);
  544. }
  545. currentBPPosition = saveBP;
  546. }
  547. /**
  548. * Render the given InlineArea.
  549. * @param inlineArea inline area text to render
  550. */
  551. protected void renderInlineArea(InlineArea inlineArea) {
  552. if (inlineArea instanceof TextArea) {
  553. renderText((TextArea) inlineArea);
  554. //} else if (inlineArea instanceof Character) {
  555. //renderCharacter((Character) inlineArea);
  556. } else if (inlineArea instanceof WordArea) {
  557. renderWord((WordArea) inlineArea);
  558. } else if (inlineArea instanceof SpaceArea) {
  559. renderSpace((SpaceArea) inlineArea);
  560. } else if (inlineArea instanceof InlineParent) {
  561. renderInlineParent((InlineParent) inlineArea);
  562. } else if (inlineArea instanceof InlineBlockParent) {
  563. renderInlineBlockParent((InlineBlockParent) inlineArea);
  564. } else if (inlineArea instanceof Space) {
  565. renderInlineSpace((Space) inlineArea);
  566. } else if (inlineArea instanceof Viewport) {
  567. renderViewport((Viewport) inlineArea);
  568. } else if (inlineArea instanceof Leader) {
  569. renderLeader((Leader) inlineArea);
  570. }
  571. }
  572. /**
  573. * Common method to render the background and borders for any inline area.
  574. * The all borders and padding are drawn outside the specified area.
  575. * @param area the inline area for which the background, border and padding is to be
  576. * rendered
  577. */
  578. protected abstract void renderInlineAreaBackAndBorders(InlineArea area);
  579. /**
  580. * Render the given Space.
  581. * @param space the space to render
  582. */
  583. protected void renderInlineSpace(Space space) {
  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. * Converts a millipoint-based transformation matrix to points.
  750. * @param at a millipoint-based transformation matrix
  751. * @return a point-based transformation matrix
  752. */
  753. protected AffineTransform mptToPt(AffineTransform at) {
  754. double[] matrix = new double[6];
  755. at.getMatrix(matrix);
  756. //Convert to points
  757. matrix[4] = matrix[4] / 1000;
  758. matrix[5] = matrix[5] / 1000;
  759. return new AffineTransform(matrix);
  760. }
  761. /**
  762. * Converts a point-based transformation matrix to millipoints.
  763. * @param at a point-based transformation matrix
  764. * @return a millipoint-based transformation matrix
  765. */
  766. protected AffineTransform ptToMpt(AffineTransform at) {
  767. double[] matrix = new double[6];
  768. at.getMatrix(matrix);
  769. //Convert to millipoints
  770. //Math.round() because things like this can happen: 65.6 * 1000 = 65.599999999999999
  771. //which is bad for testing
  772. matrix[4] = Math.round(matrix[4] * 1000);
  773. matrix[5] = Math.round(matrix[5] * 1000);
  774. return new AffineTransform(matrix);
  775. }
  776. }