Package org.pentaho.reporting.engine.classic.core.layout.process.text

Source Code of org.pentaho.reporting.engine.classic.core.layout.process.text.ComplexTextMinorAxisLayoutStep

/*
* 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 - 2013 Pentaho Corporation..  All rights reserved.
*/

package org.pentaho.reporting.engine.classic.core.layout.process.text;

import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.text.AttributedCharacterIterator;
import java.util.ArrayList;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.reporting.engine.classic.core.layout.model.LayoutNodeTypes;
import org.pentaho.reporting.engine.classic.core.layout.model.PageGrid;
import org.pentaho.reporting.engine.classic.core.layout.model.ParagraphPoolBox;
import org.pentaho.reporting.engine.classic.core.layout.model.ParagraphRenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.RenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.RenderNode;
import org.pentaho.reporting.engine.classic.core.layout.model.RenderableComplexText;
import org.pentaho.reporting.engine.classic.core.layout.output.OutputProcessorFeature;
import org.pentaho.reporting.engine.classic.core.layout.output.OutputProcessorMetaData;
import org.pentaho.reporting.engine.classic.core.layout.output.RenderUtility;
import org.pentaho.reporting.engine.classic.core.layout.process.AbstractMinorAxisLayoutStep;
import org.pentaho.reporting.engine.classic.core.layout.process.IterateSimpleStructureProcessStep;
import org.pentaho.reporting.engine.classic.core.layout.process.util.MinorAxisNodeContext;
import org.pentaho.reporting.engine.classic.core.style.StyleSheet;
import org.pentaho.reporting.engine.classic.core.style.TextStyleKeys;
import org.pentaho.reporting.engine.classic.core.style.TextWrap;
import org.pentaho.reporting.engine.classic.core.util.geom.StrictGeomUtility;
import org.pentaho.reporting.libraries.base.util.ArgumentNullException;
import org.pentaho.reporting.libraries.resourceloader.ResourceManager;

public class ComplexTextMinorAxisLayoutStep extends IterateSimpleStructureProcessStep
    implements TextMinorAxisLayoutStep
{

  private static final Log logger = LogFactory.getLog(ComplexTextMinorAxisLayoutStep.class);
  private final boolean strictCompatibility;
  private final OutputProcessorMetaData metaData;
  private final ResourceManager resourceManager;

  private MinorAxisNodeContext nodeContext;

  public ComplexTextMinorAxisLayoutStep(final OutputProcessorMetaData metaData,
                                        final ResourceManager resourceManager)
  {
    this.resourceManager = resourceManager;
    ArgumentNullException.validate("metaData", metaData);

    this.metaData = metaData;
    this.strictCompatibility = getMetaData().isFeatureSupported(OutputProcessorFeature.STRICT_COMPATIBILITY);
  }

  public void process(final ParagraphRenderBox box, final MinorAxisNodeContext nodeContext, final PageGrid pageGrid)
  {
    this.nodeContext = nodeContext;
    processParagraphChildsComplex(box);
  }

  public MinorAxisNodeContext getNodeContext()
  {
    return nodeContext;
  }

  public OutputProcessorMetaData getMetaData()
  {
    return metaData;
  }

  protected void processParagraphChildsComplex(final ParagraphRenderBox box)
  {
    // Clear the paragraph to throw away previously layouted nodes. This leaves the
    // paragraph's pool (where your original text is stored) untouched.
    box.clearLayout();

    if (box.isComplexParagraph())
    {
      final RenderBox lineBoxContainer = box.getLineboxContainer();
      final StyleSheet layoutContext = box.getStyleSheet();

      RenderNode paragraphContainer = lineBoxContainer.getFirstChild();
      while (paragraphContainer != null)
      {
        if (paragraphContainer.getNodeType() != LayoutNodeTypes.TYPE_BOX_LINEBOX)
        {
          throw new IllegalStateException("Expected ParagraphPoolBox elements.");
        }

        final ParagraphPoolBox paragraph = (ParagraphPoolBox) paragraphContainer;
        addGeneratedComplexTextLines(box, paragraph, layoutContext);

        paragraphContainer = paragraphContainer.getNext();
      }
    }
    else
    {
      final ParagraphPoolBox lineBoxContainer = (ParagraphPoolBox) box.getEffectiveLineboxContainer();
      final StyleSheet layoutContext = box.getStyleSheet();

      addGeneratedComplexTextLines(box, lineBoxContainer, layoutContext);
    }
  }

  private FontRenderContext createFontRenderContext(final StyleSheet layoutContext)
  {
    final boolean antiAliasing = RenderUtility.isFontSmooth(layoutContext, getMetaData());
    return new FontRenderContext(null, antiAliasing, true);
  }

  private void addGeneratedComplexTextLines(final ParagraphRenderBox box,
                                            final ParagraphPoolBox lineBoxContainer,
                                            final StyleSheet layoutContext)
  {
    updateNodeContextWidth(box);

    // Determine if anti-aliasing is required or not
    if (TextWrap.NONE.equals(box.getStyleSheet().getStyleProperty(TextStyleKeys.TEXT_WRAP)))
    {
      addCompleteLine(box, lineBoxContainer, layoutContext);
      return;
    }

    // Create a LineBreakMeasurer to break down that string into lines.
    final RichTextSpec richText = RichTextSpecProducer.compute(lineBoxContainer, metaData, resourceManager);
    final LineBreakIterator lineIterator = createLineBreakIterator(box, layoutContext, richText);

    ArrayList<RenderableComplexText> lines = new ArrayList<RenderableComplexText>();
    ParagraphFontMetricsImpl metrics = new ParagraphFontMetricsImpl();
    while (lineIterator.hasNext())
    {
      final LineBreakIteratorState state = lineIterator.next();

      final RenderableComplexText text = richText.create(lineBoxContainer, state.getStart(), state.getEnd());
      text.setTextLayout(state.getTextLayout());
      metrics.update(state.getTextLayout());
      // and finally add the line to the paragraph
      lines.add(text);
    }

    final double height = metrics.getLineHeight();
    for (RenderableComplexText text : lines)
    {
      final RenderBox line = generateLine(box, lineBoxContainer, text, height, metrics);
      box.addGeneratedChild(line);
    }
  }

  private LineBreakIterator createLineBreakIterator(final ParagraphRenderBox box,
                                                    final StyleSheet layoutContext,
                                                    final RichTextSpec richText)
  {
    final AttributedCharacterIterator ci = richText.createAttributedCharacterIterator();
    final FontRenderContext fontRenderContext = createFontRenderContext(layoutContext);
    final boolean breakOnWordBoundary = strictCompatibility ||
        layoutContext.getBooleanStyleProperty(TextStyleKeys.WORDBREAK);

    if (breakOnWordBoundary)
    {
      return new WordBreakingLineIterator(box, fontRenderContext, ci, richText.getText());
    }
    else
    {
      return new LineBreakIterator(box, fontRenderContext, ci);
    }
  }

  private void addCompleteLine(final ParagraphRenderBox box,
                               final ParagraphPoolBox lineBoxContainer,
                               final StyleSheet layoutContext)
  {
    RichTextSpec richText = RichTextSpecProducer.compute(lineBoxContainer, metaData, resourceManager);

    final FontRenderContext fontRenderContext = createFontRenderContext(layoutContext);
    final TextLayout textLayout = new TextLayout(richText.createAttributedCharacterIterator(), fontRenderContext);
    double height = textLayout.getAscent() + textLayout.getDescent() + textLayout.getLeading();

    final RenderableComplexText text = richText.create(lineBoxContainer);
    text.setTextLayout(textLayout);
    ParagraphFontMetricsImpl metrics = new ParagraphFontMetricsImpl();
    metrics.update(textLayout);
    final RenderBox line = generateLine(box, lineBoxContainer, text, height, metrics);
    // and finally add the line to the paragraph
    getNodeContext().updateX2(line.getCachedX2());
    box.addGeneratedChild(line);
  }

  private RenderBox generateLine(final ParagraphRenderBox paragraph,
                                 final ParagraphPoolBox lineBoxContainer,
                                 final RenderableComplexText text,
                                 final double height,
                                 final ParagraphFontMetricsImpl metrics)
  {
    //derive a new RenderableComplexText object representing the line, that holds on to the TextLayout class.
    TextLayout textLayout = text.getTextLayout();

    // Store the height and width, so that the other parts of the layouter have access to the information
//        text.setCachedHeight();
    text.setCachedHeight(Math.max(StrictGeomUtility.toInternalValue(height), lineBoxContainer.getLineHeight()));
    text.setCachedWidth(StrictGeomUtility.toInternalValue(textLayout.getAdvance()));
    text.setParagraphFontMetrics(metrics);


    MinorAxisNodeContext nodeContext = getNodeContext();
    final long alignmentX = RenderUtility.computeHorizontalAlignment(paragraph.getTextAlignment(),
        nodeContext.getContentAreaWidth(), StrictGeomUtility.toInternalValue(textLayout.getAdvance()));
    text.setCachedX(alignmentX + nodeContext.getX());

    // Create a shallow copy of the paragraph-pool to act as a line container.
    final RenderBox line = (RenderBox) paragraph.getPool().deriveFrozen(false);
    line.addGeneratedChild(text);

    // Align the line inside the paragraph. (Adjust the cachedX position depending on whether the line is left, centred or right aligned)
    line.setCachedX(alignmentX + nodeContext.getX());
    line.setCachedWidth(nodeContext.getContentAreaWidth());
    return line;
  }

  private void updateNodeContextWidth(final ParagraphRenderBox paragraph)
  {
    MinorAxisNodeContext nodeContext = getNodeContext();
    final long lineEnd;
    final boolean overflowX = paragraph.getStaticBoxLayoutProperties().isOverflowX();
    if (overflowX)
    {
      lineEnd = nodeContext.getX1() + AbstractMinorAxisLayoutStep.OVERFLOW_DUMMY_WIDTH;
    }
    else
    {
      lineEnd = nodeContext.getX2();
    }

    long firstLineIndent = 0; // todo
    long lineStart = Math.min(lineEnd, nodeContext.getX1() + firstLineIndent);
    if (lineEnd - lineStart <= 0)
    {
      final long minimumChunkWidth = paragraph.getPool().getMinimumChunkWidth();
      nodeContext.updateX2(lineStart + minimumChunkWidth);
      logger.warn("Auto-Corrected zero-width first-line on paragraph - " + paragraph.getName());
    }
    else
    {
      if (overflowX == false)
      {
        nodeContext.updateX2(lineEnd);
      }
    }
  }

}
TOP

Related Classes of org.pentaho.reporting.engine.classic.core.layout.process.text.ComplexTextMinorAxisLayoutStep

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.