/* * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * Copyright (c) 2006 - 2016 Pentaho Corporation.. All rights reserved. */ package org.pentaho.reporting.engine.classic.core.modules.output.fast.html; import java.awt.Shape; import java.io.IOException; import java.util.HashMap; import org.pentaho.reporting.engine.classic.core.AttributeNames; import org.pentaho.reporting.engine.classic.core.ImageContainer; import org.pentaho.reporting.engine.classic.core.ReportAttributeMap; import org.pentaho.reporting.engine.classic.core.ReportElement; import org.pentaho.reporting.engine.classic.core.Section; import org.pentaho.reporting.engine.classic.core.function.ExpressionRuntime; import org.pentaho.reporting.engine.classic.core.layout.model.context.BoxDefinition; import org.pentaho.reporting.engine.classic.core.layout.model.context.BoxDefinitionFactory; import org.pentaho.reporting.engine.classic.core.layout.output.ContentProcessingException; import org.pentaho.reporting.engine.classic.core.layout.output.OutputProcessorMetaData; import org.pentaho.reporting.engine.classic.core.layout.style.SimpleStyleSheet; import org.pentaho.reporting.engine.classic.core.modules.output.fast.template.FastTextExtractor; import org.pentaho.reporting.engine.classic.core.modules.output.table.html.HtmlContentGenerator; import org.pentaho.reporting.engine.classic.core.modules.output.table.html.helper.HtmlTagHelper; import org.pentaho.reporting.engine.classic.core.modules.output.table.html.helper.HtmlTextExtractorHelper; import org.pentaho.reporting.engine.classic.core.modules.output.table.html.helper.HtmlTextExtractorState; import org.pentaho.reporting.engine.classic.core.modules.output.table.html.helper.StyleBuilder; import org.pentaho.reporting.engine.classic.core.style.ElementStyleKeys; import org.pentaho.reporting.engine.classic.core.style.StyleSheet; import org.pentaho.reporting.engine.classic.core.util.InstanceID; import org.pentaho.reporting.engine.classic.core.util.RotatedTextDrawable; import org.pentaho.reporting.engine.classic.core.util.ShapeDrawable; import org.pentaho.reporting.libraries.repository.ContentIOException; import org.pentaho.reporting.libraries.resourceloader.factory.drawable.DrawableWrapper; import org.pentaho.reporting.libraries.xmlns.writer.CharacterEntityParser; import org.pentaho.reporting.libraries.xmlns.writer.HtmlCharacterEntities; import org.pentaho.reporting.libraries.xmlns.writer.XmlWriter; public class FastHtmlTextExtractor extends FastTextExtractor { private final CharacterEntityParser characterEntityParser; private final XmlWriter xmlWriter; private final StyleBuilder styleBuilder; private final HtmlTextExtractorHelper textExtractorHelper; private final BoxDefinitionFactory boxDefinitionFactory; private HashMap<InstanceID, FastHtmlImageBounds> recordedBounds; private boolean result; private HtmlTextExtractorState processStack; public FastHtmlTextExtractor( final OutputProcessorMetaData metaData, final XmlWriter xmlWriter, final HtmlContentGenerator contentGenerator, final HtmlTagHelper tagHelper ) { this.characterEntityParser = HtmlCharacterEntities.getEntityParser(); this.xmlWriter = xmlWriter; this.styleBuilder = tagHelper.getStyleBuilder(); this.textExtractorHelper = new HtmlTextExtractorHelper( tagHelper, xmlWriter, metaData, contentGenerator ); this.boxDefinitionFactory = new BoxDefinitionFactory(); } public boolean performOutput( final ReportElement content, final StyleBuilder.StyleCarrier[] cellStyle, final HashMap<InstanceID, FastHtmlImageBounds> recordedBounds, final ExpressionRuntime runtime ) throws IOException, ContentProcessingException { this.recordedBounds = recordedBounds; styleBuilder.clear(); clearText(); setRawResult( null ); result = false; processStack = new HtmlTextExtractorState( null, false, cellStyle ); textExtractorHelper.setFirstElement( content.getObjectID(), processStack ); try { setRuntime( runtime ); processInitialBox( content ); } finally { setRuntime( null ); processStack = null; } return result; } /** * Prints a paragraph cell. This is a special entry point used by the processContent method and is never called from * elsewhere. This method assumes that the attributes of the paragraph have been processed as part of the table-cell * processing. * * @param box * the paragraph box * @throws java.io.IOException * if an IO error occured. */ private void processInitialBox( final ReportElement box ) throws IOException, ContentProcessingException { if ( box.getComputedStyle().getBooleanStyleProperty( ElementStyleKeys.VISIBLE ) == false ) { return; } final StyleSheet styleSheet = box.getComputedStyle(); final String target = (String) styleSheet.getStyleProperty( ElementStyleKeys.HREF_TARGET ); if ( target != null ) { textExtractorHelper.handleLinkOnElement( styleSheet, target ); processStack = new HtmlTextExtractorState( processStack, true ); } else { processStack = new HtmlTextExtractorState( processStack, false ); } if ( Boolean.TRUE.equals( box.getAttributes().getAttribute( AttributeNames.Html.NAMESPACE, AttributeNames.Html.SUPPRESS_CONTENT ) ) == false ) { if ( box instanceof Section ) { traverseSection( (Section) box ); } else { inspectElement( box, true ); } } if ( processStack.isWrittenTag() ) { xmlWriter.writeCloseTag(); } processStack = processStack.getParent(); } protected boolean inspectStartSection( final ReportElement box, final boolean inlineSection ) { BoxDefinition boxDefinition = boxDefinitionFactory.getBoxDefinition( box.getComputedStyle() ); if ( inlineSection == false ) { return textExtractorHelper.startBox( box.getObjectID(), box.getAttributes(), box.getComputedStyle(), boxDefinition, true ); } else { return textExtractorHelper.startInlineBox( box.getObjectID(), box.getAttributes(), box.getComputedStyle(), boxDefinition ); } } protected void inspectEndSection( final ReportElement section, final boolean inlineSection ) { textExtractorHelper.finishBox( section.getObjectID(), section.getAttributes() ); } @Override protected void handleValueContent( final ReportElement element, final Object value, final boolean inlineSection ) throws ContentProcessingException { super.handleValueContent( element, value, inlineSection ); if ( value instanceof Shape ) { handleShape( element, (Shape) value ); } else if ( value instanceof ImageContainer || value instanceof DrawableWrapper || value instanceof RotatedTextDrawable ) { handleImage( element, value ); } else { handleText( element, String.valueOf( value ) ); } } private void handleText( final ReportElement element, final String text ) throws ContentProcessingException { try { xmlWriter.writeText( characterEntityParser.encodeEntities( text ) ); if ( text.trim().length() > 0 ) { result = true; } } catch ( IOException e ) { throw new ContentProcessingException( e ); } } protected void handleImage( final ReportElement element, Object rawObject ) throws ContentProcessingException { try { FastHtmlImageBounds cb = recordedBounds.get( element.getObjectID() ); if ( cb == null ) { return; } ReportAttributeMap<Object> attributes = element.getAttributes(); SimpleStyleSheet computedStyle = element.getComputedStyle(); long width = cb.getWidth(); long height = cb.getHeight(); if ( textExtractorHelper.processRenderableReplacedContent( attributes, computedStyle, width, height, cb .getContentWidth(), cb.getContentHeight(), rawObject ) ) { result = true; } } catch ( ContentIOException e ) { throw new ContentProcessingException( e ); } catch ( IOException e ) { throw new ContentProcessingException( e ); } } protected void handleShape( final ReportElement element, Shape image ) throws ContentProcessingException { boolean keepAr = element.getComputedStyle().getBooleanStyleProperty( ElementStyleKeys.KEEP_ASPECT_RATIO ); handleImage( element, new ShapeDrawable( image, keepAr ) ); } }