/* * 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) 2001 - 2013 Object Refinery Ltd, Pentaho Corporation and Contributors.. All rights reserved. */ package org.pentaho.reporting.engine.classic.core.layout.process.util; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Shape; import java.awt.Stroke; import java.awt.geom.Ellipse2D; import java.awt.geom.Line2D; import java.awt.geom.Rectangle2D; import java.awt.geom.RoundRectangle2D; import org.pentaho.reporting.engine.classic.core.layout.model.BorderEdge; import org.pentaho.reporting.engine.classic.core.layout.model.LayoutNodeTypes; import org.pentaho.reporting.engine.classic.core.layout.model.LogicalPageBox; import org.pentaho.reporting.engine.classic.core.layout.model.PageAreaBox; import org.pentaho.reporting.engine.classic.core.layout.model.RenderBox; import org.pentaho.reporting.engine.classic.core.layout.model.RenderLength; import org.pentaho.reporting.engine.classic.core.layout.model.RenderNode; import org.pentaho.reporting.engine.classic.core.layout.model.RenderableReplacedContent; import org.pentaho.reporting.engine.classic.core.layout.model.RenderableReplacedContentBox; import org.pentaho.reporting.engine.classic.core.layout.model.context.BoxDefinition; import org.pentaho.reporting.engine.classic.core.layout.process.ComputeStaticPropertiesProcessStep; import org.pentaho.reporting.engine.classic.core.style.BorderStyle; 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.ShapeDrawable; import org.pentaho.reporting.engine.classic.core.util.StrokeUtility; import org.pentaho.reporting.engine.classic.core.util.geom.StrictGeomUtility; import org.pentaho.reporting.libraries.resourceloader.factory.drawable.DrawableWrapper; /** * Creation-Date: 16.07.2007, 13:42:43 * * @author Thomas Morgner */ public class ProcessUtility { private ProcessUtility() { } /** * Returns the computed block-context width. This width is a content-size width - so it excludes paddings and borders. * (See CSS3-BOX 4.2; http://www.w3.org/TR/css3-box/#containing) * * @param box * the box for which the block-context width should be computed. * @return the block context width. */ public static long computeBlockContextWidth( final RenderNode box ) { final RenderBox parentBlockContext = box.getParent(); if ( parentBlockContext == null ) { // page cannot have borders ... final int type = box.getNodeType(); if ( ( type & LayoutNodeTypes.MASK_BOX_PAGEAREA ) == LayoutNodeTypes.MASK_BOX_PAGEAREA ) { final PageAreaBox pageAreaBox = (PageAreaBox) box; final LogicalPageBox pageBox = pageAreaBox.getLogicalPage(); if ( pageBox == null ) { return 0; } return pageBox.getPageWidth(); } if ( ( type & LayoutNodeTypes.TYPE_BOX_LOGICALPAGE ) == LayoutNodeTypes.TYPE_BOX_LOGICALPAGE ) { final LogicalPageBox logicalPage = (LogicalPageBox) box; return logicalPage.getPageWidth(); } return 0; } // A row or inline-box never establishes a context on its own; it always transfers the parent's block-render // context. // The parent's computed width is used as block context .. return parentBlockContext.getCachedWidth(); } public static boolean isContent( final RenderBox element, final boolean ellipseAsBackground, final boolean shapesAsContent ) { // For legacy reasons: A single ReplacedContent in a paragraph means, we may have a old-style border and // background definition. if ( element.getNodeType() == LayoutNodeTypes.TYPE_BOX_CONTENT ) { final RenderableReplacedContentBox contentBox = (RenderableReplacedContentBox) element; final RenderableReplacedContent rpc = contentBox.getContent(); final Object rawContentObject = rpc.getRawObject(); if ( rawContentObject instanceof DrawableWrapper == false ) { return true; } final DrawableWrapper wrapper = (DrawableWrapper) rawContentObject; final Object rawbackend = wrapper.getBackend(); if ( rawbackend instanceof ShapeDrawable == false ) { return true; } final ShapeDrawable drawable = (ShapeDrawable) rawbackend; final Shape rawObject = drawable.getShape(); final StyleSheet styleSheet = element.getStyleSheet(); if ( shapesAsContent == false ) { return false; } if ( rawObject instanceof Line2D ) { if ( hasBorderEdge( styleSheet ) ) { final Line2D line = (Line2D) rawObject; if ( line.getY1() == line.getY2() ) { return false; } else if ( line.getX1() == line.getX2() ) { return false; } } } else if ( rawObject instanceof Rectangle2D ) { return false; } else if ( ellipseAsBackground && rawObject instanceof Ellipse2D ) { return false; } else if ( rawObject instanceof RoundRectangle2D ) { return false; } return true; } RenderNode child = element.getFirstChild(); while ( child != null ) { final int type = child.getNodeType(); if ( ( type & LayoutNodeTypes.MASK_BOX_INLINE ) == LayoutNodeTypes.MASK_BOX_INLINE ) { return true; } if ( type == LayoutNodeTypes.TYPE_NODE_TEXT ) { return true; } child = child.getNext(); } return false; } public static boolean hasBorderEdge( final StyleSheet style ) { final Stroke s = (Stroke) style.getStyleProperty( ElementStyleKeys.STROKE ); if ( s instanceof BasicStroke == false ) { return false; } final BorderStyle borderStyle = StrokeUtility.translateStrokeStyle( s ); if ( BorderStyle.NONE.equals( borderStyle ) ) { return false; } return true; } public static BorderEdge produceBorderEdge( final StyleSheet style ) { final Stroke s = (Stroke) style.getStyleProperty( ElementStyleKeys.STROKE ); if ( s instanceof BasicStroke == false ) { return null; } final BasicStroke bs = (BasicStroke) s; final BorderStyle borderStyle = StrokeUtility.translateStrokeStyle( s ); if ( BorderStyle.NONE.equals( borderStyle ) ) { return null; } final Color c = (Color) style.getStyleProperty( ElementStyleKeys.PAINT ); return new BorderEdge( borderStyle, c, StrictGeomUtility.toInternalValue( bs.getLineWidth() ) ); } public static long computeLength( final long min, final long max, final long pref ) { if ( pref > max ) { if ( max < min ) { return min; } return max; } if ( pref < min ) { if ( max < min ) { return max; } return min; } if ( max < pref ) { return max; } return pref; } public static long resolveComputedWidth( final RenderBox box ) { final long bcw = ProcessUtility.computeBlockContextWidth( box ); final BoxDefinition boxDef = box.getBoxDefinition(); final RenderLength minLength = boxDef.getMinimumWidth(); final RenderLength prefLength = boxDef.getPreferredWidth(); final RenderLength maxLength = boxDef.getMaximumWidth(); final long min = minLength.resolve( bcw, 0 ); final long pref = prefLength.resolve( bcw, 0 ); final long max = maxLength.resolve( bcw, ComputeStaticPropertiesProcessStep.MAX_AUTO ); return ProcessUtility.computeLength( min, max, pref ); } }