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

Source Code of org.pentaho.reporting.engine.classic.core.layout.process.valign.VerticalAlignmentProcessor

/*
* 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 - 2009 Object Refinery Ltd, Pentaho Corporation and Contributors..  All rights reserved.
*/

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

import org.pentaho.reporting.engine.classic.core.ElementAlignment;
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.process.CacheBoxShifter;
import org.pentaho.reporting.engine.classic.core.layout.process.InfiniteMajorAxisLayoutStep;
import org.pentaho.reporting.engine.classic.core.layout.text.ExtendedBaselineInfo;
import org.pentaho.reporting.engine.classic.core.style.VerticalTextAlign;


/**
* There's only one alignment processor for the vertical layouting. The processor is non-iterative, it receives a single
* primary sequence (which represents a line) and processes that fully.
* <p/>
* As result, this processor generates a list of offsets and heights; the offset of the outermost element is always zero
* and the height is equal to the height of the whole line.
*
* @author Thomas Morgner
*/
public final class VerticalAlignmentProcessor
{
  //  private long lineHeight;
  private long minTopPos;
  private long maxBottomPos;
  private BoxAlignContext rootContext;
  private long sourcePosition;
  private InfiniteMajorAxisLayoutStep majorAxisLayoutStep;

  public VerticalAlignmentProcessor()
  {
  }

  private InfiniteMajorAxisLayoutStep getMajorAxisLayoutStep()
  {
    if (majorAxisLayoutStep == null)
    {
      majorAxisLayoutStep = new InfiniteMajorAxisLayoutStep();
    }
    return majorAxisLayoutStep;
  }

  // 7% of our time is spent here ..
  public void align(final BoxAlignContext alignStructure,
                    final long y1,
                    final long lineHeight)
  {
    this.minTopPos = Long.MAX_VALUE;
    this.maxBottomPos = Long.MIN_VALUE;
    //this.lineHeight = lineHeight;
    this.rootContext = alignStructure;
    this.sourcePosition = y1;

    performAlignment(alignStructure);
    if (alignStructure.isSimpleNode() == false)
    {
      performExtendedAlignment(alignStructure, alignStructure);
    }
    normalizeAlignment(alignStructure);

    alignStructure.setAfterEdge(Math.max(maxBottomPos, lineHeight));
    alignStructure.shift(-minTopPos + y1);
    apply(alignStructure);

    this.rootContext = null;
  }

  private void performAlignment(final BoxAlignContext box)
  {
    // We have a valid align structure here.
    AlignContext child = box.getFirstChild();
    while (child != null)
    {
      if (child instanceof InlineBlockAlignContext)
      {
        final InlineBlockAlignContext context = (InlineBlockAlignContext) child;
        final InfiniteMajorAxisLayoutStep majorAxisLayoutStep = getMajorAxisLayoutStep();
        majorAxisLayoutStep.continueComputation((RenderBox) context.getNode());

        // todo: Allow to select other than the first baseline ..
      }

      BoxAlignContext parent = box;
      final VerticalTextAlign verticalAlignment = child.getNode().getVerticalTextAlignment();
      if (VerticalTextAlign.TOP.equals(verticalAlignment) || VerticalTextAlign.BOTTOM.equals(verticalAlignment))
      {
        // Those alignments ignore the normal alignment rules and all boxes
        // align themself on the extended linebox.
        // I'm quite sure that the definition itself is unclean ..
        //continue;
        parent = rootContext;
      }


      // Now lets assume we have a valid structure...
      // All childs have been aligned. Now check how this box is positioned
      // in relation to its parent.
      final long shiftDistance = computeShift(child, parent);
      // The alignment baseline defines to which baseline of the parent we
      // will align this element
      final int alignmentBaseline = child.getDominantBaseline();

      // The alignment adjust defines, where the alignment point of this
      // child will be. The alignment adjust is relative to the child's
      // line-height. In the normal case, this will be zero to indicate, that
      // the alignment point is equal to the child's dominant baseline.
      final long childAlignmentPoint = computeAlignmentAdjust(child, alignmentBaseline);
      final long childAscent = child.getBaselineDistance(ExtendedBaselineInfo.BEFORE_EDGE);
      final long childPosition = (-childAscent + childAlignmentPoint) + child.getBeforeEdge();

      // If zero, the parent's alignment point is on the parent's dominant
      // baseline.
      final long parentAlignmentPoint = parent.getBaselineDistance(alignmentBaseline);
      final long parentAscent = parent.getBaselineDistance(ExtendedBaselineInfo.BEFORE_EDGE);

      final long parentPosition = (-parentAscent + parentAlignmentPoint) + parent.getBeforeEdge();

      final long alignment = parentPosition - childPosition;
      final long offset = shiftDistance + alignment;
      child.shift(offset);

      if (rootContext.getBeforeEdge() > child.getBeforeEdge())
      {
        rootContext.setBeforeEdge(child.getBeforeEdge());
      }

      if (rootContext.getAfterEdge() < child.getAfterEdge())
      {
        rootContext.setAfterEdge(child.getAfterEdge());
      }


      if (child instanceof BoxAlignContext)
      {
        performAlignment((BoxAlignContext) child);
      }

      child = child.getNext();
    }
  }


  /**
   * This simply searches the maximum shift that we have to do to normalize the element.
   *
   * @param box
   * @return
   */
  private void normalizeAlignment(final BoxAlignContext box)
  {
    minTopPos = Math.min(minTopPos, box.getBeforeEdge());
    maxBottomPos = Math.max(maxBottomPos, box.getAfterEdge());

    if (box.isSimpleNode())
    {
      return;
    }

    AlignContext child = box.getFirstChild();
    while (child != null)
    {
      if (child instanceof BoxAlignContext)
      {
        normalizeAlignment((BoxAlignContext) child);
      }
      child = child.getNext();
    }
  }

  private long computeShift(final AlignContext child, final BoxAlignContext box)
  {
    // for now, we do not perform any advanced layouting. Maybe later ..
    return 0;
  }

  private long computeAlignmentAdjust(final AlignContext context,
                                      final int defaultBaseLine)
  {
    // for now, we do not perform any advanced layouting. Maybe later ..
    return context.getBaselineDistance(defaultBaseLine);
  }


  private void apply(final BoxAlignContext box)
  {
    final RenderNode node = box.getNode();
    final long beforeEdge = box.getBeforeEdge();
    node.setCachedY(beforeEdge);
    node.setCachedHeight(box.getAfterEdge() - beforeEdge);

    if (box.isSimpleNode())
    {
      AlignContext child = box.getFirstChild();
      while (child != null)
      {
        if (child instanceof BoxAlignContext)
        {
          apply((BoxAlignContext) child);
        }
        else
        {
          final RenderNode childNode = child.getNode();
          final long childBeforeEdge = child.getBeforeEdge();
          childNode.setCachedY(childBeforeEdge);
          childNode.setCachedHeight(child.getAfterEdge() - childBeforeEdge);
        }
        child = child.getNext();
      }
    }
    else
    {
      AlignContext child = box.getFirstChild();
      while (child != null)
      {
        if (child instanceof BoxAlignContext)
        {
          apply((BoxAlignContext) child);
        }
        else if (child instanceof InlineBlockAlignContext)
        {
          // Luckily the layoutmodel does not yet specify inline-boxes. Need to be fixed in the flow-engine.
          // also shift all the childs.
          final long shift = child.getBeforeEdge() - sourcePosition;
          CacheBoxShifter.shiftBox(child.getNode(), shift);
        }
        else
        {
          final RenderNode childNode = child.getNode();
          final long childBeforeEdge = child.getBeforeEdge();
          childNode.setCachedY(childBeforeEdge);
          childNode.setCachedHeight(child.getAfterEdge() - childBeforeEdge);
        }

        child = child.getNext();
      }
    }
  }

//  protected static void print (final BoxAlignContext alignContext, final int level)
//  {
//    Log.debug ("Box: L:" + level + " Y1:" + alignContext.getBeforeEdge() +
//        " Y2:" + alignContext.getAfterEdge() +
//        " H:" + (alignContext.getAfterEdge() - alignContext.getBeforeEdge())
//    );
//    // We have a valid align structure here.
//    AlignContext child = alignContext.getFirstChild();
//    while (child != null)
//    {
//      if (child instanceof BoxAlignContext)
//      {
//        print((BoxAlignContext) child, level + 1);
//      }
//      else
//      {
//        Log.debug ("...: L:" + level + " Y1:" + child.getBeforeEdge() +
//            " Y2:" + (child.getAfterEdge()) +
//            " H:" + (child.getAfterEdge() - child.getBeforeEdge()));
//      }
//      child = child.getNext();
//    }
//  }
//

  /**
   * Verify all elements with alignment top or bottom. This step is required, as the extended linebox is allowed to
   * change its height during the ordinary alignment. Argh, I hate that specificiation.
   *
   * @param box
   */
  private void performExtendedAlignment(final BoxAlignContext box,
                                        final BoxAlignContext lineBox)
  {
    // Aligns elements with vertical-align TOP and vertical-align BOTTOM
    AlignContext child = box.getFirstChild();
    while (child != null)
    {
      final ElementAlignment verticalAlignment = child.getNode().getNodeLayoutProperties().getVerticalAlignment();
      if (ElementAlignment.TOP.equals(verticalAlignment))
      {
        final long childTopEdge = child.getBeforeEdge();
        final long parentTopEdge = lineBox.getBeforeEdge();
        child.shift(parentTopEdge - childTopEdge);
      }
      else if (ElementAlignment.BOTTOM.equals(verticalAlignment))
      {
        // Align the childs after-edge with the parent's after-edge
        final long childBottomEdge = child.getAfterEdge();
        final long parentBottomEdge = lineBox.getAfterEdge();
        child.shift(parentBottomEdge - childBottomEdge);
      }

      if (child instanceof BoxAlignContext)
      {
        performExtendedAlignment((BoxAlignContext) child, lineBox);
      }

      child = child.getNext();
    }
  }
}
TOP

Related Classes of org.pentaho.reporting.engine.classic.core.layout.process.valign.VerticalAlignmentProcessor

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.