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.

PSRenderer.java 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841
  1. /*
  2. * Copyright 1999-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /* $Id$ */
  17. package org.apache.fop.render.ps;
  18. // Java
  19. import java.awt.geom.Rectangle2D;
  20. import java.io.IOException;
  21. import java.io.OutputStream;
  22. import java.util.List;
  23. // FOP
  24. import org.apache.avalon.framework.configuration.Configuration;
  25. import org.apache.avalon.framework.configuration.ConfigurationException;
  26. import org.apache.fop.area.Area;
  27. import org.apache.fop.area.RegionViewport;
  28. import org.apache.fop.apps.FOPException;
  29. import org.apache.fop.area.Block;
  30. import org.apache.fop.area.BlockViewport;
  31. import org.apache.fop.area.CTM;
  32. import org.apache.fop.area.PageViewport;
  33. import org.apache.fop.area.Trait;
  34. import org.apache.fop.area.inline.ForeignObject;
  35. import org.apache.fop.area.inline.TextArea;
  36. import org.apache.fop.datatypes.ColorType;
  37. import org.apache.fop.apps.FOUserAgent;
  38. import org.apache.fop.fonts.FontSetup;
  39. import org.apache.fop.fonts.Typeface;
  40. import org.apache.fop.fonts.FontInfo;
  41. import org.apache.fop.render.AbstractRenderer;
  42. import org.apache.fop.render.RendererContext;
  43. import org.apache.fop.image.FopImage;
  44. import org.apache.fop.image.ImageFactory;
  45. import org.apache.fop.traits.BorderProps;
  46. import org.w3c.dom.Document;
  47. /**
  48. * Renderer that renders to PostScript.
  49. * <br>
  50. * This class currently generates PostScript Level 2 code. The only exception
  51. * is the FlateEncode filter which is a Level 3 feature. The filters in use
  52. * are hardcoded at the moment.
  53. * <br>
  54. * This class follows the Document Structuring Conventions (DSC) version 3.0.
  55. * If anyone modifies this renderer please make
  56. * sure to also follow the DSC to make it simpler to programmatically modify
  57. * the generated Postscript files (ex. extract pages etc.).
  58. * <br>
  59. * The PS renderer operates in millipoints as the layout engine. Since PostScript
  60. * initially uses points, scaling is applied as needed.
  61. *
  62. * @author <a href="mailto:fop-dev@xml.apache.org">Apache XML FOP Development Team</a>
  63. * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a>
  64. * @version $Id: PSRenderer.java,v 1.31 2003/03/11 08:42:24 jeremias Exp $
  65. */
  66. public class PSRenderer extends AbstractRenderer {
  67. /** The MIME type for PostScript */
  68. public static final String MIME_TYPE = "application/postscript";
  69. /** The application producing the PostScript */
  70. private int currentPageNumber = 0;
  71. private boolean enableComments = true;
  72. private boolean autoRotateLandscape = false;
  73. /** The PostScript generator used to output the PostScript */
  74. protected PSGenerator gen;
  75. private boolean ioTrouble = false;
  76. private String currentFontName;
  77. private int currentFontSize;
  78. private float currRed;
  79. private float currGreen;
  80. private float currBlue;
  81. private FontInfo fontInfo;
  82. /**
  83. * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
  84. */
  85. public void configure(Configuration cfg) throws ConfigurationException {
  86. super.configure(cfg);
  87. this.autoRotateLandscape = cfg.getChild("auto-rotate-landscape").getValueAsBoolean(false);
  88. }
  89. /**
  90. * @see org.apache.fop.render.Renderer#setUserAgent(FOUserAgent)
  91. */
  92. public void setUserAgent(FOUserAgent agent) {
  93. super.setUserAgent(agent);
  94. PSXMLHandler xmlHandler = new PSXMLHandler();
  95. //userAgent.setDefaultXMLHandler(MIME_TYPE, xmlHandler);
  96. String svg = "http://www.w3.org/2000/svg";
  97. addXMLHandler(userAgent, MIME_TYPE, svg, xmlHandler);
  98. }
  99. /**
  100. * Write out a command
  101. * @param cmd PostScript command
  102. */
  103. protected void writeln(String cmd) {
  104. try {
  105. gen.writeln(cmd);
  106. } catch (IOException ioe) {
  107. handleIOTrouble(ioe);
  108. }
  109. }
  110. /**
  111. * Central exception handler for I/O exceptions.
  112. * @param ioe IOException to handle
  113. */
  114. protected void handleIOTrouble(IOException ioe) {
  115. if (!ioTrouble) {
  116. getLogger().error("Error while writing to target file", ioe);
  117. ioTrouble = true;
  118. }
  119. }
  120. /**
  121. * Write out a comment
  122. * @param comment Comment to write
  123. */
  124. protected void comment(String comment) {
  125. if (this.enableComments) {
  126. writeln(comment);
  127. }
  128. }
  129. /**
  130. * Make sure the cursor is in the right place.
  131. */
  132. protected void movetoCurrPosition() {
  133. moveTo(this.currentIPPosition, this.currentBPPosition);
  134. }
  135. /**
  136. * Moves the cursor.
  137. * @param x X coordinate
  138. * @param y Y coordinate
  139. */
  140. protected void moveTo(int x, int y) {
  141. writeln(x + " " + y + " M");
  142. }
  143. /** Saves the graphics state of the rendering engine. */
  144. public void saveGraphicsState() {
  145. try {
  146. //delegate
  147. gen.saveGraphicsState();
  148. } catch (IOException ioe) {
  149. handleIOTrouble(ioe);
  150. }
  151. }
  152. /** Restores the last graphics state of the rendering engine. */
  153. public void restoreGraphicsState() {
  154. try {
  155. //delegate
  156. gen.restoreGraphicsState();
  157. } catch (IOException ioe) {
  158. handleIOTrouble(ioe);
  159. }
  160. }
  161. /** Indicates the beginning of a text object. */
  162. protected void beginTextObject() {
  163. writeln("BT");
  164. }
  165. /** Indicates the end of a text object. */
  166. protected void endTextObject() {
  167. writeln("ET");
  168. }
  169. /**
  170. * Concats the transformation matrix.
  171. * @param a A part
  172. * @param b B part
  173. * @param c C part
  174. * @param d D part
  175. * @param e E part
  176. * @param f F part
  177. */
  178. protected void concatMatrix(double a, double b,
  179. double c, double d,
  180. double e, double f) {
  181. try {
  182. gen.concatMatrix(a, b, c, d, e, f);
  183. } catch (IOException ioe) {
  184. handleIOTrouble(ioe);
  185. }
  186. }
  187. /**
  188. * Concats the transformations matrix.
  189. * @param matrix Matrix to use
  190. */
  191. protected void concatMatrix(double[] matrix) {
  192. try {
  193. gen.concatMatrix(matrix);
  194. } catch (IOException ioe) {
  195. handleIOTrouble(ioe);
  196. }
  197. }
  198. /**
  199. * Set up the font info
  200. *
  201. * @param inFontInfo the font info object to set up
  202. */
  203. public void setupFontInfo(FontInfo inFontInfo) {
  204. this.fontInfo = inFontInfo;
  205. FontSetup.setup(fontInfo, null);
  206. }
  207. /**
  208. * Draws a filled rectangle.
  209. * @param x x-coordinate
  210. * @param y y-coordinate
  211. * @param w width
  212. * @param h height
  213. * @param col color to fill with
  214. */
  215. protected void fillRect(float x, float y, float w, float h,
  216. ColorType col) {
  217. useColor(col);
  218. writeln(gen.formatDouble(x)
  219. + " " + gen.formatDouble(y)
  220. + " " + gen.formatDouble(w)
  221. + " " + gen.formatDouble(h)
  222. + " rectfill");
  223. }
  224. /**
  225. * Draws a stroked rectangle with the current stroke settings.
  226. * @param x x-coordinate
  227. * @param y y-coordinate
  228. * @param w width
  229. * @param h height
  230. */
  231. protected void drawRect(float x, float y, float w, float h) {
  232. writeln(gen.formatDouble(x)
  233. + " " + gen.formatDouble(y)
  234. + " " + gen.formatDouble(w)
  235. + " " + gen.formatDouble(h)
  236. + " rectstroke");
  237. }
  238. /**
  239. * Clip an area.
  240. * Write a clipping operation given coordinates in the current
  241. * transform.
  242. * @param x the x coordinate
  243. * @param y the y coordinate
  244. * @param width the width of the area
  245. * @param height the height of the area
  246. */
  247. protected void clip(float x, float y, float width, float height) {
  248. writeln(x + " " + y + " " + width + " " + height + " rectclip");
  249. }
  250. /**
  251. * Changes the currently used font.
  252. * @param name name of the font
  253. * @param size font size
  254. */
  255. public void useFont(String name, int size) {
  256. if ((currentFontName != name) || (currentFontSize != size)) {
  257. writeln(name + " " + size + " F");
  258. currentFontName = name;
  259. currentFontSize = size;
  260. }
  261. }
  262. private void useColor(ColorType col) {
  263. useColor(col.getRed(), col.getGreen(), col.getBlue());
  264. }
  265. private void useColor(float red, float green, float blue) {
  266. if ((red != currRed) || (green != currGreen) || (blue != currBlue)) {
  267. writeln(gen.formatDouble(red)
  268. + " " + gen.formatDouble(green)
  269. + " " + gen.formatDouble(blue)
  270. + " setrgbcolor");
  271. currRed = red;
  272. currGreen = green;
  273. currBlue = blue;
  274. }
  275. }
  276. /**
  277. * @see org.apache.fop.render.Renderer#startRenderer(OutputStream)
  278. */
  279. public void startRenderer(OutputStream outputStream)
  280. throws IOException {
  281. getLogger().debug("rendering areas to PostScript");
  282. //Setup for PostScript generation
  283. this.gen = new PSGenerator(outputStream);
  284. this.currentPageNumber = 0;
  285. //PostScript Header
  286. writeln(DSCConstants.PS_ADOBE_30);
  287. gen.writeDSCComment(DSCConstants.CREATOR, new String[] { userAgent.getProducer() });
  288. gen.writeDSCComment(DSCConstants.CREATION_DATE, new Object[] {new java.util.Date()});
  289. gen.writeDSCComment(DSCConstants.LANGUAGE_LEVEL, new Integer(gen.getPSLevel()));
  290. gen.writeDSCComment(DSCConstants.PAGES, new Object[] {PSGenerator.ATEND});
  291. gen.writeDSCComment(DSCConstants.END_COMMENTS);
  292. //Defaults
  293. gen.writeDSCComment(DSCConstants.BEGIN_DEFAULTS);
  294. gen.writeDSCComment(DSCConstants.END_DEFAULTS);
  295. //Prolog
  296. gen.writeDSCComment(DSCConstants.BEGIN_PROLOG);
  297. gen.writeDSCComment(DSCConstants.END_PROLOG);
  298. //Setup
  299. gen.writeDSCComment(DSCConstants.BEGIN_SETUP);
  300. PSProcSets.writeFOPStdProcSet(gen);
  301. PSProcSets.writeFOPEPSProcSet(gen);
  302. PSProcSets.writeFontDict(gen, fontInfo);
  303. gen.writeln("FOPFonts begin");
  304. gen.writeDSCComment(DSCConstants.END_SETUP);
  305. }
  306. /**
  307. * @see org.apache.fop.render.Renderer#stopRenderer()
  308. */
  309. public void stopRenderer() throws IOException {
  310. gen.writeDSCComment(DSCConstants.TRAILER);
  311. gen.writeDSCComment(DSCConstants.PAGES, new Integer(this.currentPageNumber));
  312. gen.writeDSCComment(DSCConstants.EOF);
  313. gen.flush();
  314. }
  315. /**
  316. * @see org.apache.fop.render.Renderer#renderPage(PageViewport)
  317. */
  318. public void renderPage(PageViewport page)
  319. throws IOException, FOPException {
  320. getLogger().debug("renderPage(): " + page);
  321. this.currentPageNumber++;
  322. gen.writeDSCComment(DSCConstants.PAGE, new Object[]
  323. {page.getPageNumber(),
  324. new Integer(this.currentPageNumber)});
  325. final Integer zero = new Integer(0);
  326. final long pagewidth = Math.round(page.getViewArea().getWidth());
  327. final long pageheight = Math.round(page.getViewArea().getHeight());
  328. final double pspagewidth = pagewidth / 1000f;
  329. final double pspageheight = pageheight / 1000f;
  330. boolean rotate = false;
  331. if (this.autoRotateLandscape && (pageheight < pagewidth)) {
  332. rotate = true;
  333. gen.writeDSCComment(DSCConstants.PAGE_BBOX, new Object[]
  334. {zero,
  335. zero,
  336. new Long(Math.round(pspageheight)),
  337. new Long(Math.round(pspagewidth))});
  338. gen.writeDSCComment(DSCConstants.PAGE_HIRES_BBOX, new Object[]
  339. {zero,
  340. zero,
  341. new Double(pspageheight),
  342. new Double(pspagewidth)});
  343. gen.writeDSCComment(DSCConstants.PAGE_ORIENTATION, "Landscape");
  344. } else {
  345. gen.writeDSCComment(DSCConstants.PAGE_BBOX, new Object[]
  346. {zero,
  347. zero,
  348. new Long(Math.round(pspagewidth)),
  349. new Long(Math.round(pspageheight))});
  350. gen.writeDSCComment(DSCConstants.PAGE_HIRES_BBOX, new Object[]
  351. {zero,
  352. zero,
  353. new Double(pspagewidth),
  354. new Double(pspageheight)});
  355. if (this.autoRotateLandscape) {
  356. gen.writeDSCComment(DSCConstants.PAGE_ORIENTATION, "Portrait");
  357. }
  358. }
  359. gen.writeDSCComment(DSCConstants.BEGIN_PAGE_SETUP);
  360. if (rotate) {
  361. gen.writeln(Math.round(pspageheight) + " 0 translate");
  362. gen.writeln("90 rotate");
  363. }
  364. gen.writeln("0.001 0.001 scale");
  365. concatMatrix(1, 0, 0, -1, 0, pageheight);
  366. gen.writeDSCComment(DSCConstants.END_PAGE_SETUP);
  367. //Process page
  368. super.renderPage(page);
  369. writeln("showpage");
  370. gen.writeDSCComment(DSCConstants.PAGE_TRAILER);
  371. gen.writeDSCComment(DSCConstants.END_PAGE);
  372. }
  373. /**
  374. * Paints text.
  375. * @param rx X coordinate
  376. * @param bl Y coordinate
  377. * @param text Text to paint
  378. * @param font Font to use
  379. */
  380. protected void paintText(int rx, int bl, String text, Typeface font) {
  381. saveGraphicsState();
  382. writeln("1 0 0 -1 " + rx + " " + bl + " Tm");
  383. int initialSize = text.length();
  384. initialSize += initialSize / 2;
  385. StringBuffer sb = new StringBuffer(initialSize);
  386. sb.append("(");
  387. for (int i = 0; i < text.length(); i++) {
  388. final char c = text.charAt(i);
  389. final char mapped = font.mapChar(c);
  390. PSGenerator.escapeChar(mapped, sb);
  391. }
  392. sb.append(") t");
  393. writeln(sb.toString());
  394. restoreGraphicsState();
  395. }
  396. /**
  397. * @see org.apache.fop.render.Renderer#renderText(TextArea)
  398. */
  399. public void renderText(TextArea area) {
  400. String fontname = (String)area.getTrait(Trait.FONT_NAME);
  401. int fontsize = area.getTraitAsInteger(Trait.FONT_SIZE);
  402. // This assumes that *all* CIDFonts use a /ToUnicode mapping
  403. Typeface f = (Typeface) fontInfo.getFonts().get(fontname);
  404. //Determine position
  405. int rx = currentBlockIPPosition;
  406. int bl = currentBPPosition + area.getOffset();
  407. useFont(fontname, fontsize);
  408. ColorType ct = (ColorType)area.getTrait(Trait.COLOR);
  409. if (ct != null) {
  410. useColor(ct);
  411. }
  412. paintText(rx, bl, area.getTextArea(), f);
  413. /*
  414. String psString = null;
  415. if (area.getFontState().getLetterSpacing() > 0) {
  416. //float f = area.getFontState().getLetterSpacing()
  417. // * 1000 / this.currentFontSize;
  418. float f = area.getFontState().getLetterSpacing();
  419. psString = (new StringBuffer().append(f).append(" 0.0 (")
  420. .append(sb.toString()).append(") A")).toString();
  421. } else {
  422. psString = (new StringBuffer("(").append(sb.toString())
  423. .append(") t")).toString();
  424. }
  425. // System.out.println("["+s+"] --> ["+sb.toString()+"]");
  426. // comment("% --- InlineArea font-weight="+fontWeight+": " + sb.toString());
  427. useFont(fs.getFontName(), fs.getFontSize());
  428. useColor(area.getRed(), area.getGreen(), area.getBlue());
  429. if (area.getUnderlined() || area.getLineThrough()
  430. || area.getOverlined())
  431. write("ULS");
  432. write(psString);
  433. if (area.getUnderlined())
  434. write("ULE");
  435. if (area.getLineThrough())
  436. write("SOE");
  437. if (area.getOverlined())
  438. write("OLE");
  439. this.currentXPosition += area.getContentWidth();
  440. */
  441. super.renderText(area); //Updates IPD
  442. }
  443. /**
  444. * @see org.apache.fop.render.AbstractRenderer#renderBlockViewport(BlockViewport, List)
  445. */
  446. protected void renderBlockViewport(BlockViewport bv, List children) {
  447. // clip and position viewport if necessary
  448. // save positions
  449. int saveIP = currentIPPosition;
  450. int saveBP = currentBPPosition;
  451. String saveFontName = currentFontName;
  452. CTM ctm = bv.getCTM();
  453. if (bv.getPositioning() == Block.ABSOLUTE) {
  454. currentIPPosition = 0;
  455. currentBPPosition = 0;
  456. //closeText();
  457. endTextObject();
  458. if (bv.getClip()) {
  459. saveGraphicsState();
  460. int x = bv.getXOffset() + containingIPPosition;
  461. int y = bv.getYOffset() + containingBPPosition;
  462. int width = bv.getWidth();
  463. int height = bv.getHeight();
  464. clip(x, y, width, height);
  465. }
  466. CTM tempctm = new CTM(containingIPPosition, containingBPPosition);
  467. ctm = tempctm.multiply(ctm);
  468. startVParea(ctm);
  469. handleBlockTraits(bv);
  470. renderBlocks(bv, children);
  471. endVParea();
  472. if (bv.getClip()) {
  473. restoreGraphicsState();
  474. }
  475. beginTextObject();
  476. // clip if necessary
  477. currentIPPosition = saveIP;
  478. currentBPPosition = saveBP;
  479. } else {
  480. if (ctm != null) {
  481. currentIPPosition = 0;
  482. currentBPPosition = 0;
  483. //closeText();
  484. endTextObject();
  485. double[] vals = ctm.toArray();
  486. //boolean aclock = vals[2] == 1.0;
  487. if (vals[2] == 1.0) {
  488. ctm = ctm.translate(-saveBP - bv.getHeight(), -saveIP);
  489. } else if (vals[0] == -1.0) {
  490. ctm = ctm.translate(-saveIP - bv.getWidth(), -saveBP - bv.getHeight());
  491. } else {
  492. ctm = ctm.translate(saveBP, saveIP - bv.getWidth());
  493. }
  494. }
  495. // clip if necessary
  496. if (bv.getClip()) {
  497. if (ctm == null) {
  498. //closeText();
  499. endTextObject();
  500. }
  501. saveGraphicsState();
  502. int x = bv.getXOffset();
  503. int y = bv.getYOffset();
  504. int width = bv.getWidth();
  505. int height = bv.getHeight();
  506. clip(x, y, width, height);
  507. }
  508. if (ctm != null) {
  509. startVParea(ctm);
  510. }
  511. handleBlockTraits(bv);
  512. renderBlocks(bv, children);
  513. if (ctm != null) {
  514. endVParea();
  515. }
  516. if (bv.getClip()) {
  517. restoreGraphicsState();
  518. if (ctm == null) {
  519. beginTextObject();
  520. }
  521. }
  522. if (ctm != null) {
  523. beginTextObject();
  524. }
  525. currentIPPosition = saveIP;
  526. currentBPPosition = saveBP;
  527. currentBPPosition += (int)(bv.getHeight());
  528. }
  529. currentFontName = saveFontName;
  530. }
  531. /**
  532. * @see org.apache.fop.render.AbstractRenderer#startVParea(CTM)
  533. */
  534. protected void startVParea(CTM ctm) {
  535. // Set the given CTM in the graphics state
  536. //currentState.push();
  537. //currentState.setTransform(new AffineTransform(CTMHelper.toPDFArray(ctm)));
  538. saveGraphicsState();
  539. // multiply with current CTM
  540. //writeln(CTMHelper.toPDFString(ctm) + " cm\n");
  541. final double[] matrix = ctm.toArray();
  542. concatMatrix(matrix);
  543. // Set clip?
  544. beginTextObject();
  545. }
  546. /**
  547. * @see org.apache.fop.render.AbstractRenderer#endVParea()
  548. */
  549. protected void endVParea() {
  550. endTextObject();
  551. restoreGraphicsState();
  552. //currentState.pop();
  553. }
  554. /**
  555. * Handle the traits for a region
  556. * This is used to draw the traits for the given page region.
  557. * (See Sect. 6.4.1.2 of XSL-FO spec.)
  558. * @param region the RegionViewport whose region is to be drawn
  559. */
  560. protected void handleRegionTraits(RegionViewport region) {
  561. currentFontName = "";
  562. float startx = 0;
  563. float starty = 0;
  564. Rectangle2D viewArea = region.getViewArea();
  565. float width = (float)(viewArea.getWidth());
  566. float height = (float)(viewArea.getHeight());
  567. /*
  568. Trait.Background back;
  569. back = (Trait.Background)region.getTrait(Trait.BACKGROUND);
  570. */
  571. drawBackAndBorders(region, startx, starty, width, height);
  572. }
  573. /**
  574. * Handle block traits.
  575. * The block could be any sort of block with any positioning
  576. * so this should render the traits such as border and background
  577. * in its position.
  578. *
  579. * @param block the block to render the traits
  580. */
  581. protected void handleBlockTraits(Block block) {
  582. float startx = currentIPPosition;
  583. float starty = currentBPPosition;
  584. drawBackAndBorders(block, startx, starty,
  585. block.getWidth(), block.getHeight());
  586. }
  587. /**
  588. * Draw the background and borders.
  589. * This draws the background and border traits for an area given
  590. * the position.
  591. *
  592. * @param block the area to get the traits from
  593. * @param startx the start x position
  594. * @param starty the start y position
  595. * @param width the width of the area
  596. * @param height the height of the area
  597. */
  598. protected void drawBackAndBorders(Area block,
  599. float startx, float starty,
  600. float width, float height) {
  601. // draw background then border
  602. boolean started = false;
  603. Trait.Background back;
  604. back = (Trait.Background)block.getTrait(Trait.BACKGROUND);
  605. if (back != null) {
  606. started = true;
  607. // closeText();
  608. endTextObject();
  609. //saveGraphicsState();
  610. if (back.getColor() != null) {
  611. fillRect(startx, starty, width, height, back.getColor());
  612. }
  613. if (back.getURL() != null) {
  614. ImageFactory fact = ImageFactory.getInstance();
  615. FopImage fopimage = fact.getImage(back.getURL(), userAgent);
  616. if (fopimage != null && fopimage.load(FopImage.DIMENSIONS)) {
  617. if (back.getRepeat() == BackgroundRepeat.REPEAT) {
  618. // create a pattern for the image
  619. } else {
  620. // place once
  621. Rectangle2D pos;
  622. pos = new Rectangle2D.Float((startx + back.getHoriz()) * 1000,
  623. (starty + back.getVertical()) * 1000,
  624. fopimage.getWidth() * 1000,
  625. fopimage.getHeight() * 1000);
  626. // putImage(back.url, pos);
  627. }
  628. }
  629. }
  630. }
  631. BorderProps bps = (BorderProps)block.getTrait(Trait.BORDER_BEFORE);
  632. if (bps != null) {
  633. float endx = startx + width;
  634. if (!started) {
  635. started = true;
  636. // closeText();
  637. endTextObject();
  638. //saveGraphicsState();
  639. }
  640. float bwidth = bps.width;
  641. useColor(bps.color);
  642. writeln(bwidth + " setlinewidth");
  643. drawLine(startx, starty + bwidth / 2, endx, starty + bwidth / 2);
  644. }
  645. bps = (BorderProps)block.getTrait(Trait.BORDER_START);
  646. if (bps != null) {
  647. float endy = starty + height;
  648. if (!started) {
  649. started = true;
  650. // closeText();
  651. endTextObject();
  652. //saveGraphicsState();
  653. }
  654. float bwidth = bps.width;
  655. useColor(bps.color);
  656. writeln(bwidth + " setlinewidth");
  657. drawLine(startx + bwidth / 2, starty, startx + bwidth / 2, endy);
  658. }
  659. bps = (BorderProps)block.getTrait(Trait.BORDER_AFTER);
  660. if (bps != null) {
  661. float sy = starty + height;
  662. float endx = startx + width;
  663. if (!started) {
  664. started = true;
  665. // closeText();
  666. endTextObject();
  667. //saveGraphicsState();
  668. }
  669. float bwidth = bps.width;
  670. useColor(bps.color);
  671. writeln(bwidth + " setlinewidth");
  672. drawLine(startx, sy - bwidth / 2, endx, sy - bwidth / 2);
  673. }
  674. bps = (BorderProps)block.getTrait(Trait.BORDER_END);
  675. if (bps != null) {
  676. float sx = startx + width;
  677. float endy = starty + height;
  678. if (!started) {
  679. started = true;
  680. // closeText();
  681. endTextObject();
  682. //saveGraphicsState();
  683. }
  684. float bwidth = bps.width;
  685. useColor(bps.color);
  686. writeln(bwidth + " setlinewidth");
  687. drawLine(sx - bwidth / 2, starty, sx - bwidth / 2, endy);
  688. }
  689. if (started) {
  690. //restoreGraphicsState();
  691. beginTextObject();
  692. // font last set out of scope in text section
  693. currentFontName = "";
  694. }
  695. }
  696. /**
  697. * Draw a line.
  698. *
  699. * @param startx the start x position
  700. * @param starty the start y position
  701. * @param endx the x end position
  702. * @param endy the y end position
  703. */
  704. private void drawLine(float startx, float starty, float endx, float endy) {
  705. writeln(startx + " " + starty + " M ");
  706. writeln(endx + " " + endy + " lineto");
  707. }
  708. /**
  709. * @see org.apache.fop.render.AbstractRenderer#renderForeignObject(ForeignObject, Rectangle2D)
  710. */
  711. public void renderForeignObject(ForeignObject fo, Rectangle2D pos) {
  712. Document doc = fo.getDocument();
  713. String ns = fo.getNameSpace();
  714. renderDocument(doc, ns, pos);
  715. }
  716. /**
  717. * Renders an XML document (SVG for example).
  718. * @param doc DOM Document containing the XML document to be rendered
  719. * @param ns Namespace for the XML document
  720. * @param pos Position for the generated graphic/image
  721. */
  722. public void renderDocument(Document doc, String ns, Rectangle2D pos) {
  723. RendererContext context;
  724. context = new RendererContext(MIME_TYPE);
  725. context.setUserAgent(userAgent);
  726. context.setProperty(PSXMLHandler.PS_GENERATOR, this.gen);
  727. context.setProperty(PSXMLHandler.PS_FONT_INFO, fontInfo);
  728. context.setProperty(PSXMLHandler.PS_WIDTH,
  729. new Integer((int) pos.getWidth()));
  730. context.setProperty(PSXMLHandler.PS_HEIGHT,
  731. new Integer((int) pos.getHeight()));
  732. context.setProperty(PSXMLHandler.PS_XPOS,
  733. new Integer(currentBlockIPPosition + (int) pos.getX()));
  734. context.setProperty(PSXMLHandler.PS_YPOS,
  735. new Integer(currentBPPosition + (int) pos.getY()));
  736. //context.setProperty("strokeSVGText", options.get("strokeSVGText"));
  737. renderXML(userAgent, context, doc, ns);
  738. }
  739. }