public void processContent( final ReportElement element, final Object computedValue, final Object rawValue) { if (computedValue == null) { final StyleSheet resolvedStyle = element.getComputedStyle(); final RenderBox parentRenderBox = this.context.getRenderBox(); if (parentRenderBox.isEmptyNodesHaveSignificance() || metaData.isExtraContentElement(resolvedStyle, element.getAttributes())) { ensureEmptyChildIsAdded(parentRenderBox, element); this.context.setEmpty(false); } return; } if (String.class.equals(computedValue.getClass())) { processText(element, (String) computedValue, rawValue); } else if (computedValue instanceof Shape) { final StyleSheet resolvedStyle = element.getComputedStyle(); final Shape shape = (Shape) computedValue; final ReportDrawable reportDrawable = new ShapeDrawable( shape, resolvedStyle.getBooleanStyleProperty(ElementStyleKeys.KEEP_ASPECT_RATIO)); processReportDrawable(element, reportDrawable, rawValue); } else if (computedValue instanceof ReportDrawable) { processReportDrawable(element, (ReportDrawable) computedValue, rawValue); } else if (computedValue instanceof ImageContainer || computedValue instanceof DrawableWrapper) { processReplacedContent(element, computedValue, rawValue); } else if (DrawableWrapper.isDrawable(computedValue)) { processReplacedContent(element, new DrawableWrapper(computedValue), rawValue); } else { processText(element, String.valueOf(computedValue), rawValue); } }
protected void processInlineLevelNode(final RenderNode node) { if (lineBreakState.isInsideParagraph() == false) { throw new InvalidReportStateException( "A inline-level box outside of a paragraph box is not allowed."); } final int nodeType = node.getNodeType(); if (nodeType == LayoutNodeTypes.TYPE_NODE_FINISHEDNODE) { final FinishedRenderNode finNode = (FinishedRenderNode) node; node.setCachedWidth(finNode.getLayoutedWidth()); return; } if (nodeType == LayoutNodeTypes.TYPE_NODE_TEXT) { lineBreakState.add(TextSequenceElement.INSTANCE, node); } else if (nodeType == LayoutNodeTypes.TYPE_NODE_SPACER) { final StyleSheet styleSheet = node.getStyleSheet(); if (WhitespaceCollapse.PRESERVE.equals( styleSheet.getStyleProperty(TextStyleKeys.WHITE_SPACE_COLLAPSE)) && styleSheet.getBooleanStyleProperty(TextStyleKeys.TRIM_TEXT_CONTENT) == false) { // bug-alert: This condition could indicate a workaround for a logic-flaw in the // text-processor lineBreakState.add(SpacerSequenceElement.INSTANCE, node); } else if (lineBreakState.isContainsContent()) { lineBreakState.add(SpacerSequenceElement.INSTANCE, node); } } else { lineBreakState.add(InlineNodeSequenceElement.INSTANCE, node); } }
public void startSubFlow(final ReportElement element) { final StyleSheet resolverStyleSheet = element.getComputedStyle(); final RenderBox box; if (metaData.isFeatureSupported(OutputProcessorFeature.STRICT_COMPATIBILITY)) { final StyleSheet styleSheet = new SubReportStyleSheet( resolverStyleSheet.getBooleanStyleProperty(BandStyleKeys.PAGEBREAK_BEFORE), (resolverStyleSheet.getBooleanStyleProperty(BandStyleKeys.PAGEBREAK_AFTER))); final SimpleStyleSheet reportStyle = new SimpleStyleSheet(styleSheet); final BoxDefinition boxDefinition = renderNodeFactory.getBoxDefinition(reportStyle); box = new BlockRenderBox( reportStyle, element.getObjectID(), boxDefinition, SubReportType.INSTANCE, element.getAttributes(), null); } else { box = renderNodeFactory.produceRenderBox( element, resolverStyleSheet, BandStyleKeys.LAYOUT_BLOCK, stateKey); } box.getStaticBoxLayoutProperties() .setPlaceholderBox(StaticBoxLayoutProperties.PlaceholderType.SECTION); if (element.getName() != null) { box.setName("Banded-SubReport-Section" + ": name=" + element.getName()); } else { box.setName("Banded-SubReport-Section"); } pushBoxToContext(box, false); }
public RenderBox next() { cleanFirstSpacers(); Arrays.fill(elementDimensions, 0); Arrays.fill(elementPositions, 0); int lastPosition = iterate(sequenceElements, sequenceFill); if (lastPosition == 0) { // This could evolve into an infinite loop. Thats evil. // We have two choices to prevent that: // (1) Try to break the element. // if (getBreakableIndex() >= 0) // { // // Todo: Breaking is not yet implemented .. // } if (getSkipIndex() >= 0) { // This causes an overflow .. performSkipAlignment(getSkipIndex()); lastPosition = getSkipIndex(); } else { // Skip the complete line. Oh, thats not good, really! lastPosition = sequenceFill; } } // now, build the line and update the array .. pendingElements.clear(); contexts.clear(); RenderBox firstBox = null; RenderBox box = null; for (int i = 0; i < lastPosition; i++) { final RenderNode node = nodes[i]; final InlineSequenceElement element = sequenceElements[i]; if (element instanceof EndSequenceElement) { contexts.pop(); final long boxX2 = (elementPositions[i] + elementDimensions[i]); box.setCachedWidth(boxX2 - box.getCachedX()); if (contexts.isEmpty()) { box = null; } else { final RenderNode tmpnode = box; box = contexts.peek(); box.addGeneratedChild(tmpnode); } continue; } if (element instanceof StartSequenceElement) { box = (RenderBox) node.derive(false); box.setCachedX(elementPositions[i]); contexts.push(box); if (firstBox == null) { firstBox = box; } continue; } if (box == null) { throw new IllegalStateException( "Invalid sequence: " + "Cannot have elements before we open the box context."); } // Content element: Perform a deep-deriveForAdvance, so that we preserve the // possibly existing sub-nodes. final RenderNode child = node.derive(true); child.setCachedX(elementPositions[i]); child.setCachedWidth(elementDimensions[i]); if (box.getStaticBoxLayoutProperties().isPreserveSpace() && box.getStyleSheet().getBooleanStyleProperty(TextStyleKeys.TRIM_TEXT_CONTENT) == false) { // Take a shortcut as we know that we will never have any pending elements if preserve is // true and // trim-content is false. box.addGeneratedChild(child); continue; } if (child.isIgnorableForRendering()) { pendingElements.add(child); } else { for (int j = 0; j < pendingElements.size(); j++) { final RenderNode pendingNode = pendingElements.get(j); box.addGeneratedChild(pendingNode); } pendingElements.clear(); box.addGeneratedChild(child); } } // Remove all spacers and other non printable content that might // look ugly at the beginning of a new line .. for (; lastPosition < sequenceFill; lastPosition++) { final RenderNode node = nodes[lastPosition]; final StyleSheet styleSheet = node.getStyleSheet(); if (WhitespaceCollapse.PRESERVE.equals( styleSheet.getStyleProperty(TextStyleKeys.WHITE_SPACE_COLLAPSE)) && styleSheet.getBooleanStyleProperty(TextStyleKeys.TRIM_TEXT_CONTENT) == false) { break; } if (node.isIgnorableForRendering() == false) { break; } } // If there are open contexts, then add the split-result to the new line // and update the width of the current line RenderBox previousContext = null; final int openContexts = contexts.size(); for (int i = 0; i < openContexts; i++) { final RenderBox renderBox = contexts.get(i); final long cachedWidth = getEndOfLine() - renderBox.getCachedX(); renderBox.setCachedWidth(cachedWidth); final InlineRenderBox rightBox = (InlineRenderBox) renderBox.split(RenderNode.HORIZONTAL_AXIS); sequenceElements[i] = StartSequenceElement.INSTANCE; nodes[i] = rightBox; if (previousContext != null) { previousContext.addGeneratedChild(renderBox); } previousContext = renderBox; } final int length = sequenceFill - lastPosition; System.arraycopy(sequenceElements, lastPosition, sequenceElements, openContexts, length); System.arraycopy(nodes, lastPosition, nodes, openContexts, length); sequenceFill = openContexts + length; Arrays.fill(sequenceElements, sequenceFill, sequenceElements.length, null); Arrays.fill(nodes, sequenceFill, nodes.length, null); return firstBox; }
protected boolean drawImage( final RenderableReplacedContentBox content, final Image image, final com.lowagie.text.Image itextImage) { final StyleSheet layoutContext = content.getStyleSheet(); final boolean shouldScale = layoutContext.getBooleanStyleProperty(ElementStyleKeys.SCALE); final int x = (int) StrictGeomUtility.toExternalValue(content.getX()); final int y = (int) StrictGeomUtility.toExternalValue(content.getY()); final int width = (int) StrictGeomUtility.toExternalValue(content.getWidth()); final int height = (int) StrictGeomUtility.toExternalValue(content.getHeight()); if (width == 0 || height == 0) { PdfLogicalPageDrawable.logger.debug("Error: Image area is empty: " + content); return false; } final WaitingImageObserver obs = new WaitingImageObserver(image); obs.waitImageLoaded(); final int imageWidth = image.getWidth(obs); final int imageHeight = image.getHeight(obs); if (imageWidth < 1 || imageHeight < 1) { return false; } final Rectangle2D.Double drawAreaBounds = new Rectangle2D.Double(x, y, width, height); final AffineTransform scaleTransform; final Graphics2D g2; if (shouldScale == false) { double deviceScaleFactor = 1; final double devResolution = getMetaData().getNumericFeatureValue(OutputProcessorFeature.DEVICE_RESOLUTION); if (getMetaData().isFeatureSupported(OutputProcessorFeature.IMAGE_RESOLUTION_MAPPING)) { if (devResolution != 72.0 && devResolution > 0) { // Need to scale the device to its native resolution before attempting to draw the image.. deviceScaleFactor = (72.0 / devResolution); } } final int clipWidth = Math.min(width, (int) Math.ceil(deviceScaleFactor * imageWidth)); final int clipHeight = Math.min(height, (int) Math.ceil(deviceScaleFactor * imageHeight)); final ElementAlignment horizontalAlignment = (ElementAlignment) layoutContext.getStyleProperty(ElementStyleKeys.ALIGNMENT); final ElementAlignment verticalAlignment = (ElementAlignment) layoutContext.getStyleProperty(ElementStyleKeys.VALIGNMENT); final int alignmentX = (int) RenderUtility.computeHorizontalAlignment(horizontalAlignment, width, clipWidth); final int alignmentY = (int) RenderUtility.computeVerticalAlignment(verticalAlignment, height, clipHeight); g2 = (Graphics2D) getGraphics().create(); g2.clip(drawAreaBounds); g2.translate(x, y); g2.translate(alignmentX, alignmentY); g2.clip(new Rectangle2D.Float(0, 0, clipWidth, clipHeight)); g2.scale(deviceScaleFactor, deviceScaleFactor); scaleTransform = null; } else { g2 = (Graphics2D) getGraphics().create(); g2.clip(drawAreaBounds); g2.translate(x, y); g2.clip(new Rectangle2D.Float(0, 0, width, height)); final double scaleX; final double scaleY; final boolean keepAspectRatio = layoutContext.getBooleanStyleProperty(ElementStyleKeys.KEEP_ASPECT_RATIO); if (keepAspectRatio) { final double scaleFactor = Math.min(width / (double) imageWidth, height / (double) imageHeight); scaleX = scaleFactor; scaleY = scaleFactor; } else { scaleX = width / (double) imageWidth; scaleY = height / (double) imageHeight; } final int clipWidth = (int) (scaleX * imageWidth); final int clipHeight = (int) (scaleY * imageHeight); final ElementAlignment horizontalAlignment = (ElementAlignment) layoutContext.getStyleProperty(ElementStyleKeys.ALIGNMENT); final ElementAlignment verticalAlignment = (ElementAlignment) layoutContext.getStyleProperty(ElementStyleKeys.VALIGNMENT); final int alignmentX = (int) RenderUtility.computeHorizontalAlignment(horizontalAlignment, width, clipWidth); final int alignmentY = (int) RenderUtility.computeVerticalAlignment(verticalAlignment, height, clipHeight); g2.translate(alignmentX, alignmentY); scaleTransform = AffineTransform.getScaleInstance(scaleX, scaleY); } final PdfGraphics2D pdfGraphics2D = (PdfGraphics2D) g2; pdfGraphics2D.drawPdfImage(itextImage, image, scaleTransform, null); g2.dispose(); return true; }
protected void drawText(final RenderableText renderableText, final long contentX2) { if (renderableText.getLength() == 0) { return; } final long posX = renderableText.getX(); final long posY = renderableText.getY(); final float x1 = (float) (StrictGeomUtility.toExternalValue(posX)); final PdfContentByte cb; PdfTextSpec textSpec = (PdfTextSpec) getTextSpec(); if (textSpec == null) { final StyleSheet layoutContext = renderableText.getStyleSheet(); // The code below may be weird, but at least it is predictable weird. final String fontName = getMetaData() .getNormalizedFontFamilyName( (String) layoutContext.getStyleProperty(TextStyleKeys.FONT)); final String encoding = (String) layoutContext.getStyleProperty(TextStyleKeys.FONTENCODING); final float fontSize = (float) layoutContext.getDoubleStyleProperty(TextStyleKeys.FONTSIZE, 10); final boolean embed = globalEmbed || layoutContext.getBooleanStyleProperty(TextStyleKeys.EMBEDDED_FONT); final boolean bold = layoutContext.getBooleanStyleProperty(TextStyleKeys.BOLD); final boolean italics = layoutContext.getBooleanStyleProperty(TextStyleKeys.ITALIC); final BaseFontFontMetrics fontMetrics = getMetaData() .getBaseFontFontMetrics(fontName, fontSize, bold, italics, encoding, embed, false); final PdfGraphics2D g2 = (PdfGraphics2D) getGraphics(); final Color cssColor = (Color) layoutContext.getStyleProperty(ElementStyleKeys.PAINT); g2.setPaint(cssColor); g2.setFillPaint(); g2.setStrokePaint(); // final float translateY = (float) affineTransform.getTranslateY(); cb = g2.getRawContentByte(); textSpec = new PdfTextSpec(layoutContext, getMetaData(), g2, fontMetrics, cb); setTextSpec(textSpec); cb.beginText(); cb.setFontAndSize(fontMetrics.getBaseFont(), fontSize); } else { cb = textSpec.getContentByte(); } final BaseFontFontMetrics baseFontRecord = textSpec.getFontMetrics(); final BaseFont baseFont = baseFontRecord.getBaseFont(); final float ascent = baseFont.getFontDescriptor(BaseFont.BBOXURY, textSpec.getFontSize()); final float y2 = (float) (StrictGeomUtility.toExternalValue(posY) + ascent); final float y = globalHeight - y2; final AffineTransform affineTransform = textSpec.getGraphics().getTransform(); final float translateX = (float) affineTransform.getTranslateX(); final FontNativeContext nativeContext = baseFontRecord.getNativeContext(); if (baseFontRecord.isTrueTypeFont() && textSpec.isBold() && nativeContext.isNativeBold() == false) { final float strokeWidth = textSpec.getFontSize() / 30.0f; // right from iText ... if (strokeWidth == 1) { cb.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL); } else { cb.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE); cb.setLineWidth(strokeWidth); } } else { cb.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL); } // if the font does not declare to be italics already, emulate it .. if (baseFontRecord.isTrueTypeFont() && textSpec.isItalics() && nativeContext.isNativeItalics() == false) { final float italicAngle = baseFont.getFontDescriptor(BaseFont.ITALICANGLE, textSpec.getFontSize()); if (italicAngle == 0) { // italics requested, but the font itself does not supply italics gylphs. cb.setTextMatrix(1, 0, PdfLogicalPageDrawable.ITALIC_ANGLE, 1, x1 + translateX, y); } else { cb.setTextMatrix(x1 + translateX, y); } } else { cb.setTextMatrix(x1 + translateX, y); } final OutputProcessorMetaData metaData = getMetaData(); final GlyphList gs = renderableText.getGlyphs(); final int offset = renderableText.getOffset(); final CodePointBuffer codePointBuffer = getCodePointBuffer(); if (metaData.isFeatureSupported(OutputProcessorFeature.FAST_FONTRENDERING) && isNormalTextSpacing(renderableText)) { final int maxLength = renderableText.computeMaximumTextSize(contentX2); final String text = gs.getText(renderableText.getOffset(), maxLength, codePointBuffer); cb.showText(text); } else { final PdfTextArray textArray = new PdfTextArray(); final StringBuilder buffer = new StringBuilder(gs.getSize()); final int maxPos = offset + renderableText.computeMaximumTextSize(contentX2); for (int i = offset; i < maxPos; i++) { final Glyph g = gs.getGlyph(i); final Spacing spacing = g.getSpacing(); if (i != offset) { final float optimum = (float) StrictGeomUtility.toFontMetricsValue(spacing.getMinimum()); if (optimum != 0) { textArray.add(buffer.toString()); textArray.add(-optimum / textSpec.getFontSize()); buffer.setLength(0); } } final String text = gs.getGlyphAsString(i, codePointBuffer); buffer.append(text); } if (buffer.length() > 0) { textArray.add(buffer.toString()); } cb.showText(textArray); } }
public void draw(final Graphics2D graphics2D, final Rectangle2D bounds) { Graphics2D g = (Graphics2D) graphics2D.create(); g.setColor((Color) styleSheet.getStyleProperty(ElementStyleKeys.PAINT, Color.BLACK)); if (styleSheet.getBooleanStyleProperty(ElementStyleKeys.DRAW_SHAPE)) { g.draw(bounds); } if (styleSheet.getBooleanStyleProperty(ElementStyleKeys.FILL_SHAPE)) { Graphics2D g2 = (Graphics2D) g.create(); Color fillColor = (Color) styleSheet.getStyleProperty(ElementStyleKeys.FILL_COLOR, Color.WHITE); g2.setColor(fillColor); g2.fill(bounds); g2.dispose(); } if (vectorImageBackground != null) { Graphics2D g2 = (Graphics2D) g.create(); vectorImageBackground.draw(g2, bounds); g2.dispose(); } if (rasterImageBackground != null) { Graphics2D g2 = (Graphics2D) g.create(); Image image = rasterImageBackground.getImage(); WaitingImageObserver obs = new WaitingImageObserver(image); obs.waitImageLoaded(); g.setColor(Color.WHITE); g.setBackground(Color.WHITE); while (g2.drawImage( image, (int) bounds.getX(), (int) bounds.getY(), (int) bounds.getWidth(), (int) bounds.getHeight(), null) == false) { obs.waitImageLoaded(); if (obs.isError()) { logger.warn("Error while loading the image during the rendering."); break; } } g2.dispose(); } if (StringUtils.isEmpty(textToPrint) == false) { AttributedCharacterIterator paragraph = new AttributedString(textToPrint).getIterator(); int paragraphStart = paragraph.getBeginIndex(); int paragraphEnd = paragraph.getEndIndex(); FontRenderContext frc = g.getFontRenderContext(); LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(paragraph, frc); float breakWidth = (float) bounds.getWidth(); float drawPosY = 0; // Set position to the index of the first character in the paragraph. lineMeasurer.setPosition(paragraphStart); while (lineMeasurer.getPosition() < paragraphEnd) { TextLayout layout = lineMeasurer.nextLayout(breakWidth).getJustifiedLayout(breakWidth); float drawPosX = layout.isLeftToRight() ? 0 : breakWidth - layout.getAdvance(); drawPosY += layout.getAscent(); layout.draw(g, drawPosX, drawPosY); drawPosY += layout.getDescent() + layout.getLeading(); } } }