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.

AWTRenderer.java 32KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006
  1. /*
  2. * $Id$
  3. * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
  4. * For details on use and redistribution please refer to the
  5. * LICENSE file included with these sources.
  6. */
  7. package org.apache.fop.render.awt;
  8. import org.apache.fop.apps.*;
  9. import org.apache.fop.datatypes.*;
  10. import org.apache.fop.image.*;
  11. import org.apache.fop.layout.*;
  12. import org.apache.fop.layout.inline.*;
  13. import org.apache.fop.render.AbstractRenderer;
  14. import org.apache.fop.render.pdf.*;
  15. import org.apache.fop.svg.*;
  16. import org.apache.fop.viewer.*;
  17. import org.w3c.dom.svg.*;
  18. import org.w3c.dom.Document;
  19. import org.w3c.dom.Element;
  20. import org.apache.batik.bridge.*;
  21. import org.apache.batik.swing.svg.*;
  22. import org.apache.batik.swing.gvt.*;
  23. import org.apache.batik.gvt.*;
  24. import org.apache.batik.gvt.renderer.*;
  25. import org.apache.batik.gvt.filter.*;
  26. import org.apache.batik.gvt.event.*;
  27. import java.awt.*;
  28. import java.awt.Image;
  29. import java.awt.font.*;
  30. import java.awt.geom.*;
  31. import java.awt.image.*;
  32. import java.awt.image.BufferedImage;
  33. import java.awt.print.*;
  34. import java.beans.*;
  35. import java.io.*;
  36. import java.net.MalformedURLException;
  37. import java.net.URL;
  38. import java.text.*;
  39. import java.util.*;
  40. import javax.swing.*;
  41. /**
  42. * @author <a href="mailto:Juergen.Verwohlt@jCatalog.com">Juergen Verwohlt</a>
  43. * @author <a href="mailto:Rainer.Steinkuhle@jCatalog.com">Rainer Steinkuhle</a>
  44. * @author <a href="mailto:Stanislav.Gorkhover@jCatalog.com">Stanislav
  45. * Gorkhover</a>
  46. * @author <a href="mailto:mark-fop@inomial.com">Mark Lillywhite</a>
  47. */
  48. /*
  49. * Mark Lillywhite(?) made the following comment: Did lots of
  50. * cleaning up and made the class implement the new Renderer
  51. * interface. This class could also do with a general audit,
  52. * and I suspect it's not swing-thread-safe either.
  53. */
  54. public class AWTRenderer extends AbstractRenderer implements Printable, Pageable {
  55. protected int pageWidth = 0;
  56. protected int pageHeight = 0;
  57. protected double scaleFactor = 100.0;
  58. protected int pageNumber = 0;
  59. protected Vector pageList = new Vector();
  60. protected ProgressListener progressListener = null;
  61. protected Translator res = null;
  62. protected HashMap fontNames = new HashMap();
  63. protected HashMap fontStyles = new HashMap();
  64. protected Color saveColor = null;
  65. protected IDReferences idReferences = null;
  66. /**
  67. * Image Object and Graphics Object. The Graphics Object is the Graphics
  68. * object that is contained withing the Image Object.
  69. */
  70. private BufferedImage pageImage = null;
  71. protected Graphics2D graphics = null;
  72. /**
  73. * The current (internal) font name
  74. */
  75. protected String currentFontName;
  76. /**
  77. * The current font size in millipoints
  78. */
  79. protected int currentFontSize;
  80. /**
  81. * The current colour's red, green and blue component
  82. */
  83. protected float currentRed = 0;
  84. protected float currentGreen = 0;
  85. protected float currentBlue = 0;
  86. /**
  87. * Used to make the last font and color available to
  88. * renderInlineSpace() to render text decorations.
  89. */
  90. protected java.awt.Font lastFont = null;
  91. protected Color lastColor = null;
  92. /**
  93. * The parent component, used to set up the font.
  94. * This is needed as FontSetup needs a live AWT component
  95. * in order to generate valid font measures.
  96. */
  97. protected Component parent;
  98. /**
  99. * options
  100. */
  101. protected java.util.HashMap options;
  102. /**
  103. * set up renderer options
  104. */
  105. public void setOptions(java.util.HashMap options) {
  106. this.options = options;
  107. }
  108. public AWTRenderer(Translator aRes) {
  109. res = aRes;
  110. }
  111. /**
  112. * Sets parent component which is used to set up the font.
  113. * This is needed as FontSetup needs a live AWT component
  114. * in order to generate valid font measures.
  115. * @param parent the live AWT component reference
  116. */
  117. public void setComponent(Component parent) {
  118. this.parent = parent;
  119. }
  120. public int getPageNumber() {
  121. return pageNumber;
  122. }
  123. public void setPageNumber(int aValue) {
  124. pageNumber = aValue;
  125. }
  126. public void setScaleFactor(double newScaleFactor) {
  127. scaleFactor = newScaleFactor;
  128. }
  129. public double getScaleFactor() {
  130. return scaleFactor;
  131. }
  132. public BufferedImage getLastRenderedPage() {
  133. return pageImage;
  134. }
  135. /**
  136. * add a line to the current stream
  137. *
  138. * @param x1 the start x location in millipoints
  139. * @param y1 the start y location in millipoints
  140. * @param x2 the end x location in millipoints
  141. * @param y2 the end y location in millipoints
  142. * @param th the thickness in millipoints
  143. * @param r the red component
  144. * @param g the green component
  145. * @param b the blue component
  146. */
  147. // corrected 7/13/01 aml,rlc to properly handle thickness
  148. //
  149. protected void addLine(int x1, int y1, int x2, int y2, int th, float r,
  150. float g, float b) {
  151. graphics.setColor(new Color(r, g, b));
  152. int x = x1;
  153. int y = y1;
  154. int height, width;
  155. if (x1 == x2) // vertical line
  156. {
  157. height = y2 - y1;
  158. if (height > 0) // y coordinates are reversed between fo and AWT
  159. {
  160. height = -height;
  161. y = y2;
  162. }
  163. width = th;
  164. if (width < 0) {
  165. width = -width;
  166. x -= width;
  167. }
  168. } else // horizontal line
  169. {
  170. width = x2 - x1;
  171. if (width < 0) {
  172. width = -width;
  173. x = x2;
  174. }
  175. height = th;
  176. if (height > 0) // y coordinates are reversed between fo and AWT
  177. {
  178. height = -height;
  179. y -= height;
  180. }
  181. }
  182. addRect(x, y, width, height, false);
  183. // // graphics.setColor(Color.red);
  184. // graphics.drawLine((int)(x1 / 1000f),
  185. // pageHeight - (int)(y1 / 1000f), (int)(x2 / 1000f),
  186. // pageHeight - (int)(y2 / 1000f));
  187. }
  188. /**
  189. * draw a rectangle
  190. *
  191. * @param x the x position of left edge in millipoints
  192. * @param y the y position of top edge in millipoints
  193. * @param w the width in millipoints
  194. * @param h the height in millipoints
  195. * @param r the red component
  196. * @param g the green component
  197. * @param b the blue component
  198. */
  199. // changed by aml/rlc to use helper function that
  200. // corrects for integer roundoff, and to remove 3D effect
  201. protected void addRect(int x, int y, int w, int h, float r, float g,
  202. float b) {
  203. graphics.setColor(new Color(r, g, b));
  204. // graphics.setColor(Color.green);
  205. addRect(x, y, w, h, true);
  206. }
  207. /**
  208. * draw a filled rectangle
  209. *
  210. * @param x the x position of left edge in millipoints
  211. * @param y the y position of top edge in millipoints
  212. * @param w the width in millipoints
  213. * @param h the height in millipoints
  214. * @param r the red component of edges
  215. * @param g the green component of edges
  216. * @param b the blue component of edges
  217. * @param fr the red component of the fill
  218. * @param fg the green component of the fill
  219. * @param fb the blue component of the fill
  220. */
  221. // changed by aml/rlc to use helper function that
  222. // corrects for integer roundoff
  223. protected void addRect(int x, int y, int w, int h, float r, float g,
  224. float b, float fr, float fg, float fb) {
  225. graphics.setColor(new Color(r, g, b));
  226. addRect(x, y, w, h, true);
  227. graphics.setColor(new Color(fr, fg, fb));
  228. addRect(x, y, w, h, false);
  229. }
  230. /**
  231. * draw a filled rectangle in the current color
  232. *
  233. * @param x the x position of left edge in millipoints
  234. * @param y the y position of top edge in millipoints
  235. * @param w the width in millipoints
  236. * @param h the height in millipoints
  237. * @param drawAsOutline true for draw, false for fill
  238. */
  239. // helper function by aml/rlc to correct integer roundoff problems
  240. //
  241. protected void addRect(int x, int y, int w, int h,
  242. boolean drawAsOutline) {
  243. int startx = (x + 500) / 1000;
  244. int starty = pageHeight - ((y + 500) / 1000);
  245. int endx = (x + w + 500) / 1000;
  246. int endy = pageHeight - ((y + h + 500) / 1000);
  247. if (drawAsOutline) {
  248. graphics.drawRect(startx, starty, endx - startx, endy - starty);
  249. } else {
  250. //don't round down to zero
  251. if (w != 0 && endx == startx) endx++;
  252. if (h != 0 && endy == starty) endy++;
  253. graphics.fillRect(startx, starty, endx - startx, endy - starty);
  254. }
  255. }
  256. protected void addFilledRect(int x, int y, int w, int h,
  257. ColorType col) {
  258. float r = col.red();
  259. float g = col.green();
  260. float b = col.blue();
  261. addRect(x, y, w, h, r, g, b, r, g, b);
  262. }
  263. /**
  264. * To configure before print.
  265. *
  266. * Choose pages
  267. * Zoom factor
  268. * Page format / Landscape or Portrait
  269. */
  270. public void transform(Graphics2D g2d, double zoomPercent, double angle) {
  271. AffineTransform at = g2d.getTransform();
  272. at.rotate(angle);
  273. at.scale(zoomPercent / 100.0, zoomPercent / 100.0);
  274. g2d.setTransform(at);
  275. }
  276. protected void drawFrame() {
  277. int width = pageWidth;
  278. int height = pageHeight;
  279. graphics.setColor(Color.white);
  280. graphics.fillRect(0, 0, width, height);
  281. graphics.setColor(Color.black);
  282. graphics.drawRect(-1, -1, width + 2, height + 2);
  283. graphics.drawLine(width + 2, 0, width + 2, height + 2);
  284. graphics.drawLine(width + 3, 1, width + 3, height + 3);
  285. graphics.drawLine(0, height + 2, width + 2, height + 2);
  286. graphics.drawLine(1, height + 3, width + 3, height + 3);
  287. }
  288. /**
  289. * Retrieve the number of pages in this document.
  290. *
  291. * @return the number of pages
  292. */
  293. public int getPageCount() {
  294. return pageList.size();
  295. }
  296. public void removePage(int page) {
  297. pageList.removeElementAt(page);
  298. }
  299. public void render(int aPageNumber) {
  300. if(aPageNumber >= pageList.size())
  301. return;
  302. try {
  303. render((Page) pageList.get(aPageNumber));
  304. } catch(IOException e) {
  305. e.printStackTrace();
  306. // This exception can't occur because we are not dealing with
  307. // any files
  308. }
  309. }
  310. public void render(Page page, OutputStream stream)
  311. throws IOException {
  312. pageList.add(page);
  313. }
  314. public void render(Page page)
  315. throws IOException {
  316. idReferences = page.getIDReferences();
  317. pageWidth = (int)((float)page.getWidth() / 1000f + .5);
  318. pageHeight = (int)((float)page.getHeight() / 1000f + .5);
  319. pageImage =
  320. new BufferedImage((int)((pageWidth * (int)scaleFactor) / 100),
  321. (int)((pageHeight * (int)scaleFactor) / 100),
  322. BufferedImage.TYPE_INT_RGB);
  323. graphics = pageImage.createGraphics();
  324. transform(graphics, scaleFactor, 0);
  325. drawFrame();
  326. renderPage(page);
  327. }
  328. public void renderPage(Page page) {
  329. this.currentFontName = "";
  330. this.currentFontSize = 0;
  331. renderRegions(page);
  332. // SG: Wollen wir Links abbilden?
  333. /*
  334. * if (page.hasLinks()) {
  335. * ....
  336. * }
  337. */
  338. }
  339. protected void doFrame(org.apache.fop.layout.Area area) {
  340. int w, h;
  341. int rx = this.currentAreaContainerXPosition;
  342. w = area.getContentWidth();
  343. if (area instanceof BlockArea) {
  344. rx += ((BlockArea)area).getStartIndent();
  345. }
  346. h = area.getContentHeight();
  347. int ry = this.currentYPosition;
  348. rx = rx - area.getPaddingLeft();
  349. ry = ry + area.getPaddingTop();
  350. w = w + area.getPaddingLeft() + area.getPaddingRight();
  351. h = h + area.getPaddingTop() + area.getPaddingBottom();
  352. doBackground(area, rx, ry, w, h);
  353. rx = rx - area.getBorderLeftWidth();
  354. ry = ry + area.getBorderTopWidth();
  355. w = w + area.getBorderLeftWidth() + area.getBorderRightWidth();
  356. h = h + area.getBorderTopWidth() + area.getBorderBottomWidth();
  357. BorderAndPadding bp = area.getBorderAndPadding();
  358. ColorType borderColor;
  359. if (area.getBorderTopWidth() != 0) {
  360. borderColor = bp.getBorderColor(BorderAndPadding.TOP);
  361. // addLine(rx, ry, rx + w, ry, area.getBorderTopWidth(), // corrected aml/rlc
  362. addLine(rx, ry, rx + w, ry, -area.getBorderTopWidth(),
  363. borderColor.red(), borderColor.green(),
  364. borderColor.blue());
  365. }
  366. if (area.getBorderLeftWidth() != 0) {
  367. borderColor = bp.getBorderColor(BorderAndPadding.LEFT);
  368. addLine(rx, ry, rx, ry - h, area.getBorderLeftWidth(),
  369. borderColor.red(), borderColor.green(),
  370. borderColor.blue());
  371. }
  372. if (area.getBorderRightWidth() != 0) {
  373. borderColor = bp.getBorderColor(BorderAndPadding.RIGHT);
  374. addLine(rx + w, ry, rx + w, ry - h,
  375. // area.getBorderRightWidth(), borderColor.red(), // corrected aml/rlc
  376. -area.getBorderRightWidth(), borderColor.red(),
  377. borderColor.green(),
  378. borderColor.blue());
  379. }
  380. if (area.getBorderBottomWidth() != 0) {
  381. borderColor = bp.getBorderColor(BorderAndPadding.BOTTOM);
  382. addLine(rx, ry - h, rx + w, ry - h, area.getBorderBottomWidth(),
  383. borderColor.red(), borderColor.green(),
  384. borderColor.blue());
  385. }
  386. }
  387. protected Rectangle2D getBounds(org.apache.fop.layout.Area a) {
  388. return new Rectangle2D.Double(currentAreaContainerXPosition,
  389. currentYPosition,
  390. a.getAllocationWidth(), a.getHeight());
  391. }
  392. public void setupFontInfo(FontInfo fontInfo)
  393. throws FOPException {
  394. // create a temp Image to test font metrics on
  395. BufferedImage fontImage =
  396. new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
  397. FontSetup.setup(fontInfo, fontImage.createGraphics());
  398. }
  399. public void renderDisplaySpace(DisplaySpace space) {
  400. int d = space.getSize();
  401. this.currentYPosition -= d;
  402. }
  403. /**
  404. * Renders an image, scaling it to the given width and height.
  405. * If the scaled width and height is the same intrinsic size
  406. * of the image, the image is not scaled.
  407. *
  408. * @param x the x position of left edge in millipoints
  409. * @param y the y position of top edge in millipoints
  410. * @param w the width in millipoints
  411. * @param h the height in millipoints
  412. * @param image the image to be rendered
  413. * @param fs the font state to use when rendering text
  414. * in non-bitmapped images.
  415. */
  416. protected void drawImageScaled(int x, int y, int w, int h,
  417. FopImage image,
  418. FontState fs) {
  419. // XXX: implement this
  420. }
  421. /**
  422. * Renders an image, clipping it as specified.
  423. *
  424. * @param x the x position of left edge in millipoints.
  425. * @param y the y position of top edge in millipoints.
  426. * @param clipX the left edge of the clip in millipoints
  427. * @param clipY the top edge of the clip in millipoints
  428. * @param clipW the clip width in millipoints
  429. * @param clipH the clip height in millipoints
  430. * @param fill the image to be rendered
  431. * @param fs the font state to use when rendering text
  432. * in non-bitmapped images.
  433. */
  434. protected void drawImageClipped(int x, int y,
  435. int clipX, int clipY,
  436. int clipW, int clipH,
  437. FopImage image,
  438. FontState fs) {
  439. // XXX: implement this
  440. }
  441. // correct integer roundoff (aml/rlc)
  442. public void renderImageArea(ImageArea area) {
  443. int x = currentXPosition + area.getXOffset();
  444. int y = currentYPosition;
  445. int w = area.getContentWidth();
  446. int h = area.getHeight();
  447. this.currentYPosition -= h;
  448. FopImage img = area.getImage();
  449. if (img == null) {
  450. log.error("Error while loading image : area.getImage() is null");
  451. // correct integer roundoff
  452. // graphics.drawRect(x / 1000, pageHeight - y / 1000,
  453. // w / 1000, h / 1000);
  454. addRect(x, y, w, h, true); // use helper function
  455. java.awt.Font f = graphics.getFont();
  456. java.awt.Font smallFont = new java.awt.Font(f.getFontName(),
  457. f.getStyle(), 8);
  458. graphics.setFont(smallFont);
  459. // correct integer roundoff // aml/rlc
  460. // graphics.drawString("area.getImage() is null", x / 1000,
  461. // pageHeight - y / 1000);
  462. graphics.drawString("area.getImage() is null", (x + 500) / 1000,
  463. pageHeight - (y + 500) / 1000);
  464. graphics.setFont(f);
  465. } else {
  466. if (img instanceof SVGImage) {
  467. try {
  468. SVGDocument svg = ((SVGImage)img).getSVGDocument();
  469. renderSVGDocument(svg, (int)x, (int)y);
  470. } catch (FopImageException e) {}
  471. } else {
  472. String urlString = img.getURL();
  473. try {
  474. URL url = new URL(urlString);
  475. ImageIcon icon = new ImageIcon(url);
  476. Image image = icon.getImage();
  477. // correct integer roundoff aml/rlc
  478. // graphics.drawImage(image, x / 1000,
  479. // pageHeight - y / 1000, w / 1000, h / 1000,
  480. // null);
  481. int startx = (x + 500) / 1000;
  482. int starty = pageHeight - ((y + 500) / 1000);
  483. int endx = (x + w + 500) / 1000;
  484. int endy = pageHeight - ((y + h + 500) / 1000);
  485. // reverse start and end y because h is positive
  486. graphics.drawImage(image, startx, starty, endx - startx,
  487. starty - endy, null);
  488. } catch (MalformedURLException mue) {
  489. // cannot normally occur because, if URL is wrong, constructing FopImage
  490. // will already have failed earlier on
  491. }
  492. }
  493. }
  494. this.currentXPosition += area.getContentWidth();
  495. }
  496. public void renderWordArea(WordArea area) {
  497. char ch;
  498. StringBuffer pdf = new StringBuffer();
  499. String fontname = area.getFontState().getFontName();
  500. int size = area.getFontState().getFontSize();
  501. float red = area.getRed();
  502. float green = area.getGreen();
  503. float blue = area.getBlue();
  504. FontMetricsMapper mapper;
  505. try {
  506. mapper =
  507. (FontMetricsMapper)area.getFontState().getFontInfo().getMetricsFor(fontname);
  508. } catch (FOPException iox) {
  509. mapper = new FontMetricsMapper("MonoSpaced", java.awt.Font.PLAIN,
  510. graphics);
  511. }
  512. if ((!fontname.equals(this.currentFontName))
  513. || (size != this.currentFontSize)) {
  514. this.currentFontName = fontname;
  515. this.currentFontSize = size;
  516. }
  517. if ((red != this.currentRed) || (green != this.currentGreen)
  518. || (blue != this.currentBlue)) {
  519. this.currentRed = red;
  520. this.currentGreen = green;
  521. this.currentBlue = blue;
  522. }
  523. int rx = this.currentXPosition;
  524. int bl = this.currentYPosition;
  525. String s;
  526. if (area.getPageNumberID()
  527. != null) { // this text is a page number, so resolve it
  528. s = idReferences.getPageNumber(area.getPageNumberID());
  529. if (s == null) {
  530. s = "";
  531. }
  532. } else {
  533. s = area.getText();
  534. }
  535. Color oldColor = graphics.getColor();
  536. java.awt.Font oldFont = graphics.getFont();
  537. java.awt.Font f = mapper.getFont(size);
  538. if (saveColor != null) {
  539. if (saveColor.getRed() != red || saveColor.getGreen() != green
  540. || saveColor.getBlue() != blue) {
  541. saveColor = new Color(red, green, blue);
  542. }
  543. } else {
  544. saveColor = new Color(red, green, blue);
  545. }
  546. graphics.setColor(saveColor);
  547. // Ralph LaChance (May 16, 2002)
  548. // AttributedString mechanism removed because of
  549. // rendering bug in both jdk 1.3.0_x and 1.4.
  550. // see bug parade 4650042 and others
  551. //
  552. graphics.setFont(f);
  553. // correct starting location for integer roundoff
  554. int newx = (int)(rx + 500) / 1000;
  555. int newy = (int)(pageHeight - (bl + 500) / 1000);
  556. // draw text, corrected for integer roundoff
  557. graphics.drawString(s, newx, newy);
  558. FontMetrics fm = graphics.getFontMetrics(f);
  559. int tdwidth = (int)fm.getStringBounds(s, graphics).getWidth();
  560. // text decorations
  561. renderTextDecoration(rx, bl, tdwidth, f, " ",
  562. area.getUnderlined(),
  563. area.getOverlined(),
  564. area.getLineThrough());
  565. // remember last font and color for possible inline spaces
  566. // (especially for text decorations)
  567. this.lastFont = graphics.getFont();
  568. this.lastColor = graphics.getColor();
  569. graphics.setFont(oldFont);
  570. graphics.setColor(oldColor);
  571. this.currentXPosition += area.getContentWidth();
  572. }
  573. public void renderInlineSpace(InlineSpace space) {
  574. if (space.getUnderlined() || space.getOverlined() || space.getLineThrough()) {
  575. int rx = this.currentXPosition;
  576. int bl = this.currentYPosition;
  577. java.awt.Font oldFont = graphics.getFont();
  578. if (this.lastFont != null) {
  579. graphics.setFont(this.lastFont);
  580. }
  581. Color oldColor = graphics.getColor();
  582. if (this.lastColor != null) {
  583. graphics.setColor(this.lastColor);
  584. }
  585. int width = (int)(space.getSize() + 500) / 1000;
  586. renderTextDecoration(rx, bl, width, graphics.getFont(), " ",
  587. space.getUnderlined(),
  588. space.getOverlined(),
  589. space.getLineThrough());
  590. graphics.setFont(oldFont);
  591. graphics.setColor(oldColor);
  592. }
  593. this.currentXPosition += space.getSize();
  594. }
  595. protected void renderTextDecoration(int x, int bl, int width,
  596. java.awt.Font font, String text,
  597. boolean underline,
  598. boolean overline,
  599. boolean linethrough) {
  600. if (!(underline || overline || linethrough)) return;
  601. int newx = (int)(x + 500) / 1000;
  602. int newy = (int)(pageHeight - (bl + 500) / 1000);
  603. // text decorations
  604. FontMetrics fm = graphics.getFontMetrics(font);
  605. LineMetrics lm = fm.getLineMetrics(text, graphics);
  606. int ulthick = (int)lm.getUnderlineThickness();
  607. if (ulthick < 1)
  608. ulthick = 1; // don't allow it to disappear
  609. if (underline) {
  610. // nothing in awt specifies underline location,
  611. // descent/2 seems to match my word processor
  612. int deltay = fm.getDescent() / 2;
  613. graphics.fillRect(newx, newy + deltay, width, ulthick);
  614. }
  615. if (overline) {
  616. // todo: maybe improve positioning of overline
  617. int deltay = -(int)(lm.getAscent() * 0.8);
  618. graphics.fillRect(newx, newy + deltay, width, ulthick);
  619. }
  620. if (linethrough) {
  621. int ltthick = (int)lm.getStrikethroughThickness();
  622. if (ltthick < 1)
  623. ltthick = 1; // don't allow it to disappear
  624. int deltay = (int)lm.getStrikethroughOffset();
  625. graphics.fillRect(newx, newy + deltay, width, ltthick);
  626. }
  627. }
  628. /**
  629. * render leader area into AWT
  630. *
  631. * @param area area to render
  632. */
  633. // call to addRect corrected by aml/rlc
  634. public void renderLeaderArea(LeaderArea area) {
  635. int rx = this.currentXPosition;
  636. int ry = this.currentYPosition;
  637. int w = area.getLeaderLength();
  638. int h = area.getHeight();
  639. int th = area.getRuleThickness();
  640. int st = area.getRuleStyle(); // not used at the moment
  641. float r = area.getRed();
  642. float g = area.getGreen();
  643. float b = area.getBlue();
  644. Color oldColor = graphics.getColor();
  645. graphics.setColor(new Color(r, g, b));
  646. // use helper function to correct integer roundoff - aml/rlc
  647. // graphics.fillRect((int)(rx / 1000f),
  648. // (int)(pageHeight - ry / 1000f), (int)(w / 1000f),
  649. // (int)(th / 1000f));
  650. addRect(rx, ry, w, -th, false); // NB addRect expects negative height
  651. graphics.setColor(oldColor);
  652. this.currentXPosition += area.getContentWidth();
  653. }
  654. public void renderSVGArea(SVGArea area) {
  655. int x = this.currentXPosition;
  656. int y = this.currentYPosition;
  657. int w = area.getContentWidth();
  658. int h = area.getHeight();
  659. Document doc = area.getSVGDocument();
  660. renderSVGDocument(doc, x, y);
  661. this.currentXPosition += area.getContentWidth();
  662. }
  663. protected void renderSVGDocument(Document doc, int x, int y) {
  664. MUserAgent userAgent = new MUserAgent(new AffineTransform());
  665. userAgent.setLogger(log);
  666. GVTBuilder builder = new GVTBuilder();
  667. BridgeContext ctx = new BridgeContext(userAgent);
  668. GraphicsNode root;
  669. try {
  670. root = builder.build(ctx, doc);
  671. } catch (Exception e) {
  672. log.error("svg graphic could not be built: "
  673. + e.getMessage(), e);
  674. return;
  675. }
  676. float w = (float)ctx.getDocumentSize().getWidth() * 1000f;
  677. float h = (float)ctx.getDocumentSize().getHeight() * 1000f;
  678. // correct integer roundoff aml/rlc
  679. // graphics.translate(x / 1000f, pageHeight - y / 1000f);
  680. graphics.translate((x + 500) / 1000, pageHeight - (y + 500) / 1000);
  681. SVGSVGElement svg = ((SVGDocument)doc).getRootElement();
  682. AffineTransform at = ViewBox.getPreserveAspectRatioTransform(svg, w / 1000f, h / 1000f);
  683. AffineTransform inverse = null;
  684. try {
  685. inverse = at.createInverse();
  686. } catch(NoninvertibleTransformException e) {
  687. }
  688. if(!at.isIdentity()) {
  689. graphics.transform(at);
  690. }
  691. try {
  692. root.paint(graphics);
  693. } catch (Exception e) {
  694. e.printStackTrace();
  695. }
  696. if(inverse != null && !inverse.isIdentity()) {
  697. graphics.transform(inverse);
  698. }
  699. // correct integer roundoff aml/rlc
  700. // graphics.translate(-x / 1000f, y / 1000f - pageHeight);
  701. graphics.translate(-(x + 500) / 1000, (y + 500) / 1000 - pageHeight);
  702. }
  703. public void setProducer(String producer) {
  704. // defined in Renderer Interface
  705. }
  706. public int print(Graphics g, PageFormat pageFormat,
  707. int pageIndex) throws PrinterException {
  708. if (pageIndex >= pageList.size())
  709. return NO_SUCH_PAGE;
  710. Graphics2D oldGraphics = graphics;
  711. int oldPageNumber = pageNumber;
  712. graphics = (Graphics2D)g;
  713. Page aPage = (Page)pageList.get(pageIndex);
  714. renderPage(aPage);
  715. graphics = oldGraphics;
  716. return PAGE_EXISTS;
  717. }
  718. public int getNumberOfPages() {
  719. return pageList.size();
  720. }
  721. public PageFormat getPageFormat(int pageIndex)
  722. throws IndexOutOfBoundsException {
  723. if (pageIndex >= pageList.size())
  724. return null;
  725. Page page = (Page)pageList.get(pageIndex);
  726. PageFormat pageFormat = new PageFormat();
  727. Paper paper = new Paper();
  728. double width = page.getWidth();
  729. double height = page.getHeight();
  730. // if the width is greater than the height assume lanscape mode
  731. // and swap the width and height values in the paper format
  732. if (width > height) {
  733. paper.setImageableArea(0, 0, height / 1000d, width / 1000d);
  734. paper.setSize(height / 1000d, width / 1000d);
  735. pageFormat.setOrientation(PageFormat.LANDSCAPE);
  736. } else {
  737. paper.setImageableArea(0, 0, width / 1000d, height / 1000d);
  738. paper.setSize(width / 1000d, height / 1000d);
  739. pageFormat.setOrientation(PageFormat.PORTRAIT);
  740. }
  741. pageFormat.setPaper(paper);
  742. return pageFormat;
  743. }
  744. public Printable getPrintable(int pageIndex)
  745. throws IndexOutOfBoundsException {
  746. return this;
  747. }
  748. public void setProgressListener(ProgressListener l) {
  749. progressListener = l;
  750. }
  751. public static Color colorType2Color(ColorType ct) {
  752. if (ct == null) {
  753. return null;
  754. }
  755. return new Color(ct.red(), ct.green(), ct.blue());
  756. }
  757. /**
  758. * Draws an image.
  759. * TODO: protect other image formats (JIMI)
  760. */
  761. /*
  762. * public void renderImage(String href, float x, float y, float width,
  763. * float height, Vector transform) {
  764. * // What is with transformations?
  765. * try {
  766. * URL url = new URL(href);
  767. * ImageIcon imageIcon = new ImageIcon(url);
  768. * AffineTransform fullTransform = new AffineTransform();
  769. * AffineTransform aTransform;
  770. * transform = (transform == null) ? new Vector() : transform;
  771. * for (int i = 0; i < transform.size(); i++) {
  772. * org.w3c.dom.svg.SVGTransform t =
  773. * (org.w3c.dom.svg.SVGTransform)
  774. * transform.get(i);
  775. * SVGMatrix matrix = t.getMatrix();
  776. * aTransform = new AffineTransform(matrix.getA(),
  777. * matrix.getB(), matrix.getC(), matrix.getD(),
  778. * matrix.getE(), matrix.getF());
  779. * fullTransform.concatenate(aTransform);
  780. * }
  781. * BufferedImage bi = new BufferedImage((int) width, (int) height,
  782. * BufferedImage.TYPE_INT_RGB);
  783. * Graphics2D g2d = bi.createGraphics();
  784. * BufferedImageOp bop = new AffineTransformOp(fullTransform,
  785. * AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
  786. * g2d.drawImage(imageIcon.getImage(), 0, 0, (int) width,
  787. * (int) height, imageIcon.getImageObserver());
  788. * graphics.drawImage(bi, bop, (int) x, (int) y);
  789. * } catch (Exception ex) {
  790. * log.error("AWTRenderer: renderImage(): " +
  791. * ex.getMessage(), ex);
  792. * }
  793. * }
  794. */
  795. public void renderForeignObjectArea(ForeignObjectArea area) {
  796. area.getObject().render(this);
  797. }
  798. protected class MUserAgent extends org.apache.fop.svg.SVGUserAgent {
  799. /**
  800. * Creates a new SVGUserAgent.
  801. */
  802. protected MUserAgent(AffineTransform at) {
  803. super(at);
  804. }
  805. /**
  806. * Opens a link in a new component.
  807. * @param doc The current document.
  808. * @param uri The document URI.
  809. */
  810. public void openLink(SVGAElement elt) {
  811. // application.openLink(uri);
  812. }
  813. public Point getClientAreaLocationOnScreen() {
  814. return new Point(0, 0);
  815. }
  816. public void setSVGCursor(java.awt.Cursor cursor) {}
  817. public Dimension2D getViewportSize() {
  818. return new Dimension(100, 100);
  819. }
  820. public EventDispatcher getEventDispatcher() {
  821. return null;
  822. }
  823. }
  824. public void startRenderer(OutputStream outputStream)
  825. throws IOException {}
  826. public void stopRenderer(OutputStream outputStream)
  827. throws IOException {
  828. render(0);
  829. }
  830. }