001: /**
002: * ===========================================
003: * JFreeReport : a free Java reporting library
004: * ===========================================
005: *
006: * Project Info: http://reporting.pentaho.org/
007: *
008: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
009: *
010: * This library is free software; you can redistribute it and/or modify it under the terms
011: * of the GNU Lesser General Public License as published by the Free Software Foundation;
012: * either version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
015: * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016: * See the GNU Lesser General Public License for more details.
017: *
018: * You should have received a copy of the GNU Lesser General Public License along with this
019: * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020: * Boston, MA 02111-1307, USA.
021: *
022: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
023: * in the United States and other countries.]
024: *
025: * ------------
026: * HtmlTextExtractor.java
027: * ------------
028: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
029: */package org.jfree.report.modules.output.table.html;
030:
031: import java.io.IOException;
032: import java.text.NumberFormat;
033: import java.awt.Image;
034:
035: import org.jfree.report.ImageContainer;
036: import org.jfree.report.InvalidReportStateException;
037: import org.jfree.report.layout.model.BlockRenderBox;
038: import org.jfree.report.layout.model.CanvasRenderBox;
039: import org.jfree.report.layout.model.InlineRenderBox;
040: import org.jfree.report.layout.model.ParagraphRenderBox;
041: import org.jfree.report.layout.model.RenderBox;
042: import org.jfree.report.layout.model.RenderNode;
043: import org.jfree.report.layout.model.RenderableReplacedContent;
044: import org.jfree.report.layout.model.RenderableText;
045: import org.jfree.report.layout.model.SpacerRenderNode;
046: import org.jfree.report.layout.output.OutputProcessorMetaData;
047: import org.jfree.report.layout.output.RenderUtility;
048: import org.jfree.report.modules.output.table.base.DefaultTextExtractor;
049: import org.jfree.report.modules.output.table.html.helper.HtmlOutputProcessingException;
050: import org.jfree.report.modules.output.table.html.helper.StyleBuilder;
051: import org.jfree.report.modules.output.table.html.helper.StyleManager;
052: import org.jfree.report.style.ElementStyleKeys;
053: import org.jfree.report.style.StyleSheet;
054: import org.jfree.report.util.geom.StrictBounds;
055: import org.jfree.report.util.geom.StrictGeomUtility;
056: import org.jfree.repository.ContentIOException;
057: import org.jfree.resourceloader.ResourceKey;
058: import org.jfree.ui.Drawable;
059: import org.jfree.util.StackableRuntimeException;
060: import org.jfree.xmlns.common.AttributeList;
061: import org.jfree.xmlns.writer.CharacterEntityParser;
062: import org.jfree.xmlns.writer.HtmlCharacterEntities;
063: import org.jfree.xmlns.writer.XmlWriter;
064: import org.jfree.xmlns.writer.XmlWriterSupport;
065:
066: /**
067: * Creation-Date: 02.11.2007, 15:58:29
068: *
069: * @author Thomas Morgner
070: */
071: public class HtmlTextExtractor extends DefaultTextExtractor {
072: private OutputProcessorMetaData metaData;
073: private XmlWriter xmlWriter;
074: private StyleManager styleManager;
075: private StyleBuilder styleBuilder;
076: private HtmlContentGenerator contentGenerator;
077: private CharacterEntityParser characterEntityParser;
078:
079: public HtmlTextExtractor(final OutputProcessorMetaData metaData,
080: final XmlWriter xmlWriter, final StyleManager styleManager,
081: final HtmlContentGenerator contentGenerator) {
082: super (metaData);
083: this .contentGenerator = contentGenerator;
084:
085: this .metaData = metaData;
086: this .xmlWriter = xmlWriter;
087: this .styleManager = styleManager;
088: this .styleBuilder = new StyleBuilder();
089: this .characterEntityParser = HtmlCharacterEntities
090: .getEntityParser();
091: }
092:
093: public void performOutput(final RenderBox content)
094: throws IOException {
095: styleBuilder.clear();
096: clearText();
097: setRawResult(null);
098:
099: if (content instanceof ParagraphRenderBox) {
100: processParagraphCell((ParagraphRenderBox) content);
101: } else {
102: processBoxChilds(content);
103: }
104: }
105:
106: public boolean startCanvasBox(final CanvasRenderBox box) {
107: try {
108: final StyleSheet styleSheet = box.getStyleSheet();
109: final String target = (String) styleSheet
110: .getStyleProperty(ElementStyleKeys.HREF_TARGET);
111: if (target != null) {
112: final String window = (String) styleSheet
113: .getStyleProperty(ElementStyleKeys.HREF_WINDOW);
114: final AttributeList linkAttr = new AttributeList();
115: linkAttr.setAttribute(HtmlPrinter.XHTML_NAMESPACE,
116: "href", target);
117: if (window != null) {
118: linkAttr.setAttribute(HtmlPrinter.XHTML_NAMESPACE,
119: "target", window);
120: }
121: final String title = (String) styleSheet
122: .getStyleProperty(ElementStyleKeys.HREF_TITLE);
123: if (title != null) {
124: linkAttr.setAttribute(HtmlPrinter.XHTML_NAMESPACE,
125: "title", HtmlPrinter.normalize(title,
126: xmlWriter));
127: }
128: xmlWriter.writeTag(HtmlPrinter.XHTML_NAMESPACE, "a",
129: linkAttr, XmlWriterSupport.OPEN);
130: }
131: return true;
132: } catch (IOException e) {
133: throw new HtmlOutputProcessingException(
134: "Failed to perform IO", e);
135: }
136: }
137:
138: public void finishCanvasBox(final CanvasRenderBox box) {
139: try {
140: final StyleSheet styleSheet = box.getStyleSheet();
141: final String target = (String) styleSheet
142: .getStyleProperty(ElementStyleKeys.HREF_TARGET);
143: if (target != null) {
144: xmlWriter.writeCloseTag();
145: }
146: } catch (IOException e) {
147: throw new HtmlOutputProcessingException(
148: "Failed to perform IO", e);
149: }
150: }
151:
152: protected void processParagraphCell(final ParagraphRenderBox box)
153: throws IOException {
154: final StyleSheet styleSheet = box.getStyleSheet();
155: final String target = (String) styleSheet
156: .getStyleProperty(ElementStyleKeys.HREF_TARGET);
157: if (target != null) {
158: final String window = (String) styleSheet
159: .getStyleProperty(ElementStyleKeys.HREF_WINDOW);
160: final AttributeList linkAttr = new AttributeList();
161: linkAttr.setAttribute(HtmlPrinter.XHTML_NAMESPACE, "href",
162: HtmlPrinter.normalize(target, xmlWriter));
163: if (window != null) {
164: linkAttr.setAttribute(HtmlPrinter.XHTML_NAMESPACE,
165: "target", HtmlPrinter.normalize(window,
166: xmlWriter));
167: }
168: final String title = (String) styleSheet
169: .getStyleProperty(ElementStyleKeys.HREF_TITLE);
170: if (title != null) {
171: linkAttr.setAttribute(HtmlPrinter.XHTML_NAMESPACE,
172: "title", HtmlPrinter
173: .normalize(title, xmlWriter));
174: }
175: xmlWriter.writeTag(HtmlPrinter.XHTML_NAMESPACE, "a",
176: linkAttr, XmlWriterSupport.OPEN);
177:
178: final AttributeList attrList = new AttributeList();
179: styleManager.updateStyle(HtmlPrinter.produceTextStyle(
180: styleBuilder, box, false, false), attrList);
181: xmlWriter.writeTag(HtmlPrinter.XHTML_NAMESPACE, "span",
182: attrList, XmlWriterSupport.OPEN);
183: }
184:
185: processParagraphChilds(box);
186:
187: if (target != null) {
188: xmlWriter.writeCloseTag(); // closing the span ..
189: xmlWriter.writeCloseTag();
190: }
191:
192: }
193:
194: protected void addEmptyBreak() {
195: try {
196: xmlWriter.writeText(" ");
197: } catch (IOException e) {
198: throw new HtmlOutputProcessingException(
199: "Failed to perform IO", e);
200: }
201: }
202:
203: protected void addSoftBreak() {
204: try {
205: xmlWriter.writeText(" ");
206: } catch (IOException e) {
207: throw new HtmlOutputProcessingException(
208: "Failed to perform IO", e);
209: }
210: }
211:
212: protected void addLinebreak() {
213: try {
214: xmlWriter.writeTag(HtmlPrinter.XHTML_NAMESPACE, "br",
215: XmlWriter.CLOSE);
216: } catch (IOException e) {
217: throw new HtmlOutputProcessingException(
218: "Failed to perform IO", e);
219: }
220: }
221:
222: protected boolean startBlockBox(final BlockRenderBox box) {
223: try {
224: final AttributeList attrList = new AttributeList();
225: styleManager.updateStyle(HtmlPrinter.produceTextStyle(
226: styleBuilder, box, true, false), attrList);
227:
228: xmlWriter.writeTag(HtmlPrinter.XHTML_NAMESPACE, "div",
229: attrList, XmlWriterSupport.OPEN);
230: final StyleSheet styleSheet = box.getStyleSheet();
231: final String anchor = (String) styleSheet
232: .getStyleProperty(ElementStyleKeys.ANCHOR_NAME);
233: if (anchor != null) {
234: xmlWriter.writeTag(HtmlPrinter.XHTML_NAMESPACE, "a",
235: "name", anchor, XmlWriterSupport.CLOSE);
236: }
237:
238: final String target = (String) styleSheet
239: .getStyleProperty(ElementStyleKeys.HREF_TARGET);
240: if (target != null) {
241: final String window = (String) styleSheet
242: .getStyleProperty(ElementStyleKeys.HREF_WINDOW);
243: final AttributeList linkAttr = new AttributeList();
244: linkAttr.setAttribute(HtmlPrinter.XHTML_NAMESPACE,
245: "href", HtmlPrinter
246: .normalize(target, xmlWriter));
247: if (window != null) {
248: linkAttr.setAttribute(HtmlPrinter.XHTML_NAMESPACE,
249: "target", HtmlPrinter.normalize(window,
250: xmlWriter));
251: }
252: final String title = (String) styleSheet
253: .getStyleProperty(ElementStyleKeys.HREF_TITLE);
254: if (title != null) {
255: linkAttr.setAttribute(HtmlPrinter.XHTML_NAMESPACE,
256: "title", HtmlPrinter.normalize(title,
257: xmlWriter));
258: }
259: xmlWriter.writeTag(HtmlPrinter.XHTML_NAMESPACE, "a",
260: linkAttr, XmlWriterSupport.OPEN);
261: }
262:
263: return true;
264: } catch (IOException e) {
265: throw new HtmlOutputProcessingException(
266: "Failed to perform IO", e);
267: }
268: }
269:
270: protected void finishBlockBox(final BlockRenderBox box) {
271: try {
272: final StyleSheet styleSheet = box.getStyleSheet();
273: final String target = (String) styleSheet
274: .getStyleProperty(ElementStyleKeys.HREF_TARGET);
275: if (target != null) {
276: // close anchor tag
277: xmlWriter.writeCloseTag();
278: }
279:
280: xmlWriter.writeCloseTag();
281: } catch (IOException e) {
282: throw new HtmlOutputProcessingException(
283: "Failed to perform IO", e);
284: }
285: }
286:
287: private boolean isBoxEmpty(final InlineRenderBox box) {
288: final RenderNode visibleFirst = box.getVisibleFirst();
289: if (visibleFirst == null) {
290: return true;
291: }
292: if (visibleFirst instanceof RenderableText) {
293: final RenderableText text = (RenderableText) visibleFirst;
294: if (text.getLength() == 0) {
295: return true;
296: }
297: }
298: return false;
299: }
300:
301: protected boolean startInlineBox(final InlineRenderBox box) {
302: if (isBoxEmpty(box)) {
303: return true;
304: }
305:
306: try {
307: final AttributeList attrList = new AttributeList();
308: styleManager.updateStyle(HtmlPrinter.produceTextStyle(
309: styleBuilder, box, true, true), attrList);
310: xmlWriter.writeTag(HtmlPrinter.XHTML_NAMESPACE, "span",
311: attrList, XmlWriterSupport.OPEN);
312: final StyleSheet styleSheet = box.getStyleSheet();
313: final String anchor = (String) styleSheet
314: .getStyleProperty(ElementStyleKeys.ANCHOR_NAME);
315: if (anchor != null) {
316: xmlWriter.writeTag(HtmlPrinter.XHTML_NAMESPACE, "a",
317: "name", HtmlPrinter
318: .normalize(anchor, xmlWriter),
319: XmlWriterSupport.CLOSE);
320: }
321:
322: final String target = (String) styleSheet
323: .getStyleProperty(ElementStyleKeys.HREF_TARGET);
324: if (target != null) {
325: final String window = (String) styleSheet
326: .getStyleProperty(ElementStyleKeys.HREF_WINDOW);
327: final AttributeList linkAttr = new AttributeList();
328: linkAttr.setAttribute(HtmlPrinter.XHTML_NAMESPACE,
329: "href", HtmlPrinter
330: .normalize(target, xmlWriter));
331: if (window != null) {
332: linkAttr.setAttribute(HtmlPrinter.XHTML_NAMESPACE,
333: "target", HtmlPrinter.normalize(window,
334: xmlWriter));
335: }
336: final String title = (String) styleSheet
337: .getStyleProperty(ElementStyleKeys.HREF_TITLE);
338: if (title != null) {
339: linkAttr.setAttribute(HtmlPrinter.XHTML_NAMESPACE,
340: "title", HtmlPrinter.normalize(title,
341: xmlWriter));
342: }
343: xmlWriter.writeTag(HtmlPrinter.XHTML_NAMESPACE, "a",
344: linkAttr, XmlWriterSupport.OPEN);
345: }
346: return true;
347: } catch (IOException e) {
348: throw new HtmlOutputProcessingException(
349: "Failed to perform IO", e);
350: }
351: }
352:
353: protected void finishInlineBox(final InlineRenderBox box) {
354: if (isBoxEmpty(box)) {
355: return;
356: }
357:
358: try {
359: final StyleSheet styleSheet = box.getStyleSheet();
360: final String target = (String) styleSheet
361: .getStyleProperty(ElementStyleKeys.HREF_TARGET);
362: if (target != null) {
363: // close anchor tag
364: xmlWriter.writeCloseTag();
365: }
366:
367: xmlWriter.writeCloseTag();
368: } catch (IOException e) {
369: throw new HtmlOutputProcessingException(
370: "Failed to perform IO", e);
371: }
372: }
373:
374: protected void processOtherNode(final RenderNode node) {
375: try {
376: if (node instanceof RenderableText) {
377: super .processOtherNode(node);
378: return;
379: }
380:
381: if (node.isVirtualNode()) {
382: return;
383: }
384:
385: if (node instanceof SpacerRenderNode) {
386: final SpacerRenderNode spacer = (SpacerRenderNode) node;
387: final int count = Math.max(1, spacer.getSpaceCount());
388: for (int i = 0; i < count; i++) {
389: xmlWriter.writeText(" ");
390: }
391: } else if (node instanceof RenderableReplacedContent) {
392: final StyleSheet styleSheet = node.getStyleSheet();
393: final String anchor = (String) styleSheet
394: .getStyleProperty(ElementStyleKeys.ANCHOR_NAME);
395: if (anchor != null) {
396: xmlWriter.writeTag(HtmlPrinter.XHTML_NAMESPACE,
397: "a", "name", HtmlPrinter.normalize(anchor,
398: xmlWriter), XmlWriterSupport.CLOSE);
399: }
400:
401: final String target = (String) styleSheet
402: .getStyleProperty(ElementStyleKeys.HREF_TARGET);
403: if (target != null) {
404: final String window = (String) styleSheet
405: .getStyleProperty(ElementStyleKeys.HREF_WINDOW);
406: final AttributeList linkAttr = new AttributeList();
407: linkAttr.setAttribute(HtmlPrinter.XHTML_NAMESPACE,
408: "href", HtmlPrinter.normalize(target,
409: xmlWriter));
410: if (window != null) {
411: linkAttr.setAttribute(
412: HtmlPrinter.XHTML_NAMESPACE, "target",
413: HtmlPrinter
414: .normalize(window, xmlWriter));
415: }
416: final String title = (String) styleSheet
417: .getStyleProperty(ElementStyleKeys.HREF_TITLE);
418: if (title != null) {
419: linkAttr
420: .setAttribute(
421: HtmlPrinter.XHTML_NAMESPACE,
422: "title", HtmlPrinter.normalize(
423: title, xmlWriter));
424: }
425: xmlWriter.writeTag(HtmlPrinter.XHTML_NAMESPACE,
426: "a", linkAttr, XmlWriterSupport.OPEN);
427: }
428:
429: processReplacedContent(node);
430:
431: if (target != null) {
432: xmlWriter.writeCloseTag();
433: }
434:
435: }
436: } catch (IOException e) {
437: throw new StackableRuntimeException("Failed", e);
438: } catch (ContentIOException e) {
439: throw new StackableRuntimeException("Failed", e);
440: }
441: }
442:
443: private void processReplacedContent(final RenderNode node)
444: throws IOException, ContentIOException {
445:
446: final RenderableReplacedContent rc = (RenderableReplacedContent) node;
447: final ResourceKey source = rc.getSource();
448: final Object rawObject = rc.getRawObject();
449: // We have to do three things here. First, w have to check what kind
450: // of content we deal with.
451: // todo: Check whether the raw-object would be understood by the browser
452: if (source != null && (rawObject instanceof ImageContainer)) {
453: // Cool, we have access to the raw-data. Thats always nice as we
454: // dont have to recode the whole thing. We can only recode images, not drawables.
455: if (contentGenerator.isRegistered(source) == false) {
456: // Write image reference; return the name of the reference. This method will
457: // return null, if the image is not recognized (it is no JPG, PNG or GIF image)
458: final String name = contentGenerator.writeRaw(source);
459: if (name != null) {
460: // Write image reference ..
461: final AttributeList attrList = new AttributeList();
462: attrList.setAttribute(HtmlPrinter.XHTML_NAMESPACE,
463: "src", name);
464: // width and height and scaling and so on ..
465: final StyleBuilder imgStyle = produceImageStyle(rc);
466: if (imgStyle == null) {
467: final AttributeList clipAttrList = new AttributeList();
468: final StyleBuilder divStyle = procudeClipStyle(rc);
469: styleManager
470: .updateStyle(divStyle, clipAttrList);
471:
472: xmlWriter.writeTag(HtmlPrinter.XHTML_NAMESPACE,
473: "div", clipAttrList, XmlWriter.OPEN);
474: xmlWriter.writeTag(HtmlPrinter.XHTML_NAMESPACE,
475: "img", attrList, XmlWriter.CLOSE);
476: xmlWriter.writeCloseTag();
477: } else {
478: styleManager.updateStyle(imgStyle, attrList);
479: xmlWriter.writeTag(HtmlPrinter.XHTML_NAMESPACE,
480: "img", attrList, XmlWriter.CLOSE);
481: }
482:
483: contentGenerator.registerContent(source, name);
484: return;
485: } else {
486: // Mark this object as non-readable. This way we dont retry the failed operation
487: // over and over again.
488: contentGenerator.registerFailure(source);
489: }
490: } else {
491: final String cachedName = contentGenerator
492: .getRegisteredName(source);
493: if (cachedName != null) {
494: final AttributeList attrList = new AttributeList();
495: attrList.setAttribute(HtmlPrinter.XHTML_NAMESPACE,
496: "src", cachedName);
497: // width and height and scaling and so on ..
498: final StyleBuilder imgStyle = produceImageStyle(rc);
499: if (imgStyle == null) {
500: final AttributeList clipAttrList = new AttributeList();
501: final StyleBuilder divStyle = procudeClipStyle(rc);
502: styleManager
503: .updateStyle(divStyle, clipAttrList);
504:
505: xmlWriter.writeTag(HtmlPrinter.XHTML_NAMESPACE,
506: "div", clipAttrList, XmlWriter.OPEN);
507: xmlWriter.writeTag(HtmlPrinter.XHTML_NAMESPACE,
508: "img", attrList, XmlWriter.CLOSE);
509: xmlWriter.writeCloseTag();
510: } else {
511: styleManager.updateStyle(imgStyle, attrList);
512: xmlWriter.writeTag(HtmlPrinter.XHTML_NAMESPACE,
513: "img", attrList, XmlWriter.CLOSE);
514: }
515: return;
516: }
517: }
518: }
519:
520: // Fallback: (At the moment, we only support drawables and images.)
521: if (rawObject instanceof ImageContainer) {
522: // Make it a PNG file ..
523: //xmlWriter.writeComment("Image content source:" + source);
524: final String name = contentGenerator
525: .writeImage((ImageContainer) rawObject);
526: if (name != null) {
527: // Write image reference ..
528: final AttributeList attrList = new AttributeList();
529: attrList.setAttribute(HtmlPrinter.XHTML_NAMESPACE,
530: "src", name);
531: // width and height and scaling and so on ..
532: final StyleBuilder imgStyle = produceImageStyle(rc);
533: if (imgStyle == null) {
534: final AttributeList clipAttrList = new AttributeList();
535: final StyleBuilder divStyle = procudeClipStyle(rc);
536: styleManager.updateStyle(divStyle, clipAttrList);
537:
538: xmlWriter.writeTag(HtmlPrinter.XHTML_NAMESPACE,
539: "div", clipAttrList, XmlWriter.OPEN);
540: xmlWriter.writeTag(HtmlPrinter.XHTML_NAMESPACE,
541: "img", attrList, XmlWriter.CLOSE);
542: xmlWriter.writeCloseTag();
543: } else {
544: styleManager.updateStyle(imgStyle, attrList);
545: xmlWriter.writeTag(HtmlPrinter.XHTML_NAMESPACE,
546: "img", attrList, XmlWriter.CLOSE);
547: }
548: }
549:
550: return;
551: }
552:
553: if (rawObject instanceof Drawable) {
554: // render it into an Buffered image and make it a PNG file.
555: final StrictBounds cb = new StrictBounds(node.getX(), node
556: .getY(), node.getWidth(), node.getHeight());
557: final ImageContainer image = RenderUtility
558: .createImageFromDrawable((Drawable) rawObject, cb,
559: node, metaData);
560: if (image == null) {
561: //xmlWriter.writeComment("Drawable content [No image generated]:" + source);
562: return;
563: }
564:
565: final String name = contentGenerator.writeImage(image);
566: if (name == null) {
567: //xmlWriter.writeComment("Drawable content [No image written]:" + source);
568: return;
569: }
570:
571: //xmlWriter.writeComment("Drawable content:" + source);
572: // Write image reference ..
573: final AttributeList attrList = new AttributeList();
574: attrList.setAttribute(HtmlPrinter.XHTML_NAMESPACE, "src",
575: name);
576: // width and height and scaling and so on ..
577: final StyleBuilder imgStyle = produceImageStyle(rc);
578: if (imgStyle == null) {
579: final AttributeList clipAttrList = new AttributeList();
580: final StyleBuilder divStyle = procudeClipStyle(rc);
581: styleManager.updateStyle(divStyle, clipAttrList);
582:
583: xmlWriter.writeTag(HtmlPrinter.XHTML_NAMESPACE, "div",
584: clipAttrList, XmlWriter.OPEN);
585: xmlWriter.writeTag(HtmlPrinter.XHTML_NAMESPACE, "img",
586: attrList, XmlWriter.CLOSE);
587: xmlWriter.writeCloseTag();
588: } else {
589: styleManager.updateStyle(imgStyle, attrList);
590: xmlWriter.writeTag(HtmlPrinter.XHTML_NAMESPACE, "img",
591: attrList, XmlWriter.CLOSE);
592: }
593: }
594: }
595:
596: private StyleBuilder procudeClipStyle(
597: final RenderableReplacedContent rc) {
598: styleBuilder.clear(); // cuts down on object creation
599:
600: final long nodeWidth = rc.getWidth();
601: final long nodeHeight = rc.getHeight();
602: final NumberFormat pointConverter = styleBuilder
603: .getPointConverter();
604: styleBuilder.append("overflow", "hidden");
605: styleBuilder.append("width", pointConverter
606: .format(StrictGeomUtility.toExternalValue(nodeWidth)),
607: "pt");
608: styleBuilder.append("height", pointConverter
609: .format(StrictGeomUtility.toExternalValue(nodeHeight)),
610: "pt");
611: return styleBuilder;
612: }
613:
614: /**
615: * Populates the style builder with the style information for the image based on the RenderableReplacedContent
616: *
617: * @param rc th renderable content node.
618: * @return the style-builder with the image style or null, if the image must be clipped.
619: */
620: private StyleBuilder produceImageStyle(
621: final RenderableReplacedContent rc) {
622: styleBuilder.clear(); // cuts down on object creation
623:
624: final Object o = rc.getRawObject();
625:
626: final NumberFormat pointConverter = styleBuilder
627: .getPointConverter();
628:
629: final long contentWidth = rc.getContentWidth();
630: final long nodeWidth = rc.getWidth();
631: final long contentHeight = rc.getContentHeight();
632: final long nodeHeight = rc.getHeight();
633:
634: final StyleSheet styleSheet = rc.getStyleSheet();
635: if (styleSheet.getBooleanStyleProperty(ElementStyleKeys.SCALE)) {
636: if (styleSheet
637: .getBooleanStyleProperty(ElementStyleKeys.KEEP_ASPECT_RATIO)
638: && (contentWidth > 0 && contentHeight > 0)) {
639: final double scaleFactor = Math.min(nodeWidth
640: / (double) contentWidth, nodeHeight
641: / (double) contentHeight);
642:
643: styleBuilder
644: .append(
645: "width",
646: pointConverter
647: .format(StrictGeomUtility
648: .toExternalValue((long) (contentWidth * scaleFactor))),
649: "pt");
650: styleBuilder
651: .append(
652: "height",
653: pointConverter
654: .format(StrictGeomUtility
655: .toExternalValue((long) (contentHeight * scaleFactor))),
656: "pt");
657: } else {
658: styleBuilder.append("width", pointConverter
659: .format(StrictGeomUtility
660: .toExternalValue(nodeWidth)), "pt");
661: styleBuilder.append("height", pointConverter
662: .format(StrictGeomUtility
663: .toExternalValue(nodeHeight)), "pt");
664: }
665: } else {
666: // for plain drawable content, there is no intrinsic-width or height, so we have to use the computed
667: // width and height instead.
668: if (contentWidth > nodeWidth || contentHeight > nodeHeight) {
669: // There is clipping involved. The img-element does *not* receive a width or height property.
670: // the width and height is applied to an external DIV element instead.
671: return null;
672: }
673:
674: if (contentWidth == 0 && contentHeight == 0) {
675: // Drawable content has no intrinsic height or width, therefore we must not use the content size at all.
676: styleBuilder.append("width", pointConverter
677: .format(StrictGeomUtility
678: .toExternalValue(nodeWidth)), "pt");
679: styleBuilder.append("height", pointConverter
680: .format(StrictGeomUtility
681: .toExternalValue(nodeHeight)), "pt");
682: } else {
683: final long width = Math.min(nodeWidth, contentWidth);
684: final long height = Math.min(nodeHeight, contentHeight);
685: styleBuilder.append("width", pointConverter
686: .format(StrictGeomUtility
687: .toExternalValue(width)), "pt");
688: styleBuilder.append("height", pointConverter
689: .format(StrictGeomUtility
690: .toExternalValue(height)), "pt");
691: }
692: }
693: return styleBuilder;
694: }
695:
696: protected void drawText(final RenderableText renderableText,
697: final long contentX2) {
698: try {
699: super .drawText(renderableText, contentX2);
700: if (getTextLength() > 0) {
701: final String text = getText();
702: xmlWriter.writeText(characterEntityParser
703: .encodeEntities(text));
704: clearText();
705: }
706: // if (renderableText.isForceLinebreak())
707: // {
708: // xmlWriter.writeTag(HtmlPrinter.XHTML_NAMESPACE, "br", XmlWriter.CLOSE);
709: // }
710: } catch (IOException ioe) {
711: throw new InvalidReportStateException(
712: "Failed to write text", ioe);
713: }
714:
715: }
716: }
|