All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.adobe.xfa.layout.BoxModelLayout Maven / Gradle / Ivy

There is a newer version: 2024.11.18751.20241128T090041Z-241100
Show newest version
/*
 * ADOBE CONFIDENTIAL
 *
 * Copyright 2007 Adobe Systems Incorporated All Rights Reserved.
 *
 * NOTICE: All information contained herein is, and remains the property of
 * Adobe Systems Incorporated and its suppliers, if any. The intellectual and
 * technical concepts contained herein are proprietary to Adobe Systems
 * Incorporated and its suppliers and may be covered by U.S. and Foreign
 * Patents, patents in process, and are protected by trade secret or copyright
 * law. Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained from
 * Adobe Systems Incorporated.
 */
package com.adobe.xfa.layout;


import com.adobe.xfa.Element;
import com.adobe.xfa.EnumAttr;
import com.adobe.xfa.Measurement;
import com.adobe.xfa.Node;
import com.adobe.xfa.XFA;
import com.adobe.xfa.content.Content;
import com.adobe.xfa.template.TemplateResolver;
import com.adobe.xfa.template.containers.AreaContainer;
import com.adobe.xfa.template.containers.Container;
import com.adobe.xfa.template.containers.ContentArea;
import com.adobe.xfa.template.containers.Draw;
import com.adobe.xfa.template.containers.ExclGroup;
import com.adobe.xfa.template.containers.Field;
import com.adobe.xfa.template.containers.PageArea;
import com.adobe.xfa.template.containers.Rotate;
import com.adobe.xfa.template.containers.Subform;
import com.adobe.xfa.template.formatting.Margin;
import com.adobe.xfa.template.ui.UI;
import com.adobe.xfa.ut.Angle;
import com.adobe.xfa.ut.CoordPair;
import com.adobe.xfa.ut.ExFull;
import com.adobe.xfa.ut.Margins;
import com.adobe.xfa.ut.ObjectHolder;
import com.adobe.xfa.ut.Rect;
import com.adobe.xfa.ut.ResId;
import com.adobe.xfa.ut.UnitSpan;

import java.util.List;

/**
 * A class to access and manipulate 
 * the axis-aligned rectangular layout of form objects. 
 * Form objects that subscribe to this box model paradigm are
 * <draw>,  <field>, <subform>, <contentArea>,
 * <area> and <pageArea>.
 * 

* A box model defines a number of rectangular regions. * All regions are relative to an offset from the local coordinate * space, which has its origin at the top left corner of the * nominal extent; this is the local box model origin. *

* All regions have a set of margins. A region may also have * an optional border that may be inset from its extents. *

* A box model is characterized by the following: *

    *
  • a nominal extent region corresponding to the bounding rectangle of * the form object. *
  • an (optional) interior caption region for the presentation of the * caption. Caption regions do not have borders. *
  • an interior content region for the presentation of content * objects. This is the remainder of the nominal extent not occupied * by either margins or caption. *
  • a rotation angle -- in multiples of 90°. *
*

* The nominal extent is used for graphical placement. However, the * actual rendering of the form object may include graphic elements * that draw outside of the nominal extent; this is the visual * extent. *

* Box model instances should be created using the static * {@link #newBoxModel(Element, LayoutEnv, boolean) BoxModelLayout.newBoxModel(...)} * function. */ public class BoxModelLayout /* extends Obj */ { /** * Nominal extent data. * @exclude from published api. */ protected Rect m_oNE = Rect.ZERO; /** * @exclude from published api. */ protected boolean m_bGrowableH; /** * @exclude from published api. */ protected boolean m_bGrowableW; /** * @exclude from published api. */ protected boolean m_bInfiniteMaxH; /** * @exclude from published api. */ protected boolean m_bInfiniteMaxW; /** * @exclude from published api. */ protected UnitSpan m_oMinW = UnitSpan.ZERO; /** * @exclude from published api. */ protected UnitSpan m_oMaxW = UnitSpan.ZERO; /** * @exclude from published api. */ protected UnitSpan m_oMinH = UnitSpan.ZERO; /** * @exclude from published api. */ protected UnitSpan m_oMaxH = UnitSpan.ZERO; /** * @exclude from published api. */ protected Margins m_oNEMargins = new Margins(); /** * @exclude from published api. */ protected Margins m_oCapMargins = new Margins(); /** * @exclude from published api. */ protected Margins m_oContMargins = new Margins(); /** * @exclude from published api. */ protected Margins m_oBorderMargins = new Margins(); /** * @exclude from published api. */ protected Margins m_oContentBorderMargins = new Margins(); /** * @exclude from published api. */ protected UnitSpan m_oMaxEdgeThickness = UnitSpan.ZERO; /** * The anchor point indicates a known reference point * within the box model space and is not necessarily the top-left * corner of the box-model nominal extent. * The top-left value is returned by calling .getXY() * @exclude from published api. */ protected CoordPair m_oAnchorPoint = CoordPair.ZERO_ZERO; /** * @exclude from published api. */ protected int m_oAnchorType; /** * The start point for text, adjusted by any rotation. * @exclude from published api. */ protected CoordPair m_oRotatedContentTopLeft = CoordPair.ZERO_ZERO; /** * @exclude from published api. */ protected CoordPair m_oRotatedCaptionTopLeft = CoordPair.ZERO_ZERO; /** * @exclude from published api. */ protected boolean m_bWasRotated; /** * @exclude from published api. */ protected Angle m_oRotationAngle = Angle.ZERO; // Enummerations of eBMType /** * For a node that can use the base box model implementation. * * @exclude from published api. */ public static final int eBaseLayout = 0; /** * For a node that is a button; it requires a * box model implementation that makes the caption * extent cover the entire margined nominal extent. * * @exclude from published api. */ public static final int eButtonLayout = 1; /** * For a node that is a check button; it requires a box model * implementation that makes the caption extent cover the * entire margined nominal extent except what's covered by * the checkbox/radiio button. * * @exclude from published api. */ public static final int eCheckButtonLayout = 2; /** * For a node that has flowing textual contents; it requires * a box model implementation that can format them. * * @exclude from published api. */ public static final int eTextContentLayout = 3; /** * For a node that is a barcode; it requires a box model * implementation that formats the barcode data and * any text label. * * @exclude from published api. */ public static final int eBarcodeLayout = 4; /** * For a node that is a paperMetaData barcode, including * PDF417, DataMatrix, QRCode, etc. * The boxmodel gives us a BMP image stored in ImageData. * * @exclude from published api. */ public static final int ePMDBarcodeLayout = 5; /** * For a node that is an image; it requries a box model * implementation that separates the nominal extent * into a content region for the image data and * a caption region for the optional caption text data. * * @exclude from published api. */ public static final int eImageLayout = 6; /** * For a node that is a pageArea; it requires a box model * implementation that resolves the correct pagesizes * * @exclude from published api. */ public static final int ePageLayout = 7; /** * For a node that is a exclusion group group; * it requires a specialized box model implementation. * * @exclude from published api. */ public static final int eExclGroupLayout = 8; /** * Gets the box model type required for the node. * * @param oNode the form node that the box model applies to. * @param oEnv the layout environment. * @return a new box model layout type. * * @exclude from published api. */ public static int getBoxModelType(Element oNode, LayoutEnv oEnv) { int eType = eBaseLayout; if (oNode != null) { if (oNode instanceof Field) { UI oUI = (UI) oNode.peekElement(XFA.UITAG, true, 0); Element oCurrentUI = oUI.getUIElement(false); int oCurrentUITag = oCurrentUI.getClassTag(); if (oCurrentUITag == XFA.CHECKBUTTONTAG) eType = eCheckButtonLayout; else if (oCurrentUITag == XFA.BUTTONTAG) eType = eButtonLayout; else if (oCurrentUITag == XFA.BARCODETAG) { // Javaport: TODO // String sType = oCurrentUI.getAttribute(XFA.TYPETAG).toString(); // // isNotSupported returns true if the barcode is not supported by the hardware // // nor the software but still needs to be rendered. // // The name of this method is not very clear... // boolean bBarcodeLayout = oEnv.getBarcodeResolver().isSoftwareSupported(sType) || // oEnv.getBarcodeResolver().isHardwareSupported(sType) || // oEnv.getBarcodeResolver().isNotSupported(sType); // // // // PunchCard controlled barcode // // // if (oEnv.getBarcodeResolver().isSpecial(sType)) { // eType = ePMDBarcodeLayout; // } // else if (bBarcodeLayout) { // eType = eBarcodeLayout; // } } else if (oCurrentUITag == XFA.IMAGEEDITTAG) eType = eImageLayout; else { eType = eTextContentLayout; Element oValue = oNode.peekElement(XFA.VALUETAG, false, 0); if (oValue != null) { //Ignore images Node oContent = oValue.getOneOfChild(true, true); int oContentTag = oContent.getClassTag(); if (oContentTag == XFA.IMAGETAG) { eType = eImageLayout; } } } } else if (oNode instanceof Draw) { Element oValue = oNode.peekElement(XFA.VALUETAG, true, 0); Node oContent = oValue.getOneOfChild(true, true); int oContentTag = oContent.getClassTag(); if (oContentTag == XFA.TEXTTAG || oContentTag == XFA.DECIMALTAG || oContentTag == XFA.INTEGERTAG || oContentTag == XFA.FLOATTAG || oContentTag == XFA.DATETAG || oContentTag == XFA.DATETIMETAG || oContentTag == XFA.TIMETAG || oContentTag == XFA.EXDATATAG) eType = eTextContentLayout; // // Do we have an image? // else if (oContentTag == XFA.IMAGETAG) eType = eImageLayout; } else if (oNode instanceof Subform) { //subforms are noncaptionable, thus they use vanilla boxmodel } else if (oNode instanceof ExclGroup) { //excl groups are captionable, so they get their own box model eType = eExclGroupLayout; } else if (oNode instanceof PageArea) { eType = ePageLayout; } } return eType; } /** * Creates a new, fully initialized instance of a box model. * * @param node the form node that the box model applies to. * @param env the layout environment. * @param bAllowProxy allow proxy -- ie. drawn from stored text run definitions. ????. * @return a new box model layout. */ public static BoxModelLayout newBoxModel(Element node, LayoutEnv env, boolean bAllowProxy) { // //Create a new, fully initialized box model instance with the an implementation //that's customized for the node type. // BoxModelLayout oBM = null; try { int eType = getBoxModelType(node, env); if (eType == eTextContentLayout) { // // Cached text runs? // If we're derived from a and have proxy info, then // create a simpler box model object. // if (bAllowProxy && node instanceof Draw) { oBM = new BoxModelRenderProxy(env); } else { oBM = new BoxModelContent(env, bAllowProxy); } oBM.initialize(node); } // Javaport: none of these are needed yet. // else if (eType == eCheckButtonLayout) { // oBM = new BoxModelChkBttn(oEnv); // oBM.initialize(oNode); // } // else if (eType == eButtonLayout) { // oBM = new BoxModelButton(oEnv); // oBM.initialize(oNode); // } // else if (eType == eBarcodeLayout) { // oBM = new BoxModelBarcode(oEnv); // oBM.initialize(oNode); // } // else if (eType == ePMDBarcodeLayout) { // oBM = new BoxModelPMDBarcode(oEnv); // oBM.initialize(oNode); // } // else if (eType == eImageLayout) { // oBM = new BoxModelImage(oEnv); // oBM.initialize(oNode); // } // else if (eType == ePageLayout) { // oBM = new BoxModelPage(oEnv); // oBM.initialize(oNode); // } // else if (eType == eExclGroupLayout) { // oBM = new BoxModelExclGroup(oEnv); // oBM.initialize(oNode); // } // else { // // Cached text runs? // if (bAllowProxy) { // oBM = new BoxModelRenderProxy(oEnv); // } // else { // //Generic box model // oBM = new BoxModelLayout(); // } // oBM.initialize(oNode); // } } catch (ExFull e) { // Javaport: For now, return null for UNSUPPORTED_OPERATION ExFulls. if (e.firstResId() != ResId.UNSUPPORTED_OPERATION) throw e; oBM = null; } return oBM; } BoxModelLayout() { super(); m_oAnchorType = EnumAttr.TOP_LEFT; m_bWasRotated = false; m_bGrowableH = false; m_bGrowableW = false; m_bInfiniteMaxH = false; m_bInfiniteMaxW = false; m_oRotationAngle = Angle.ZERO; } /** * Clears the box model layout. * * @exclude from published api. */ public void clear() { //Reset the box model layout m_oAnchorType = EnumAttr.TOP_LEFT; m_oAnchorPoint = CoordPair.ZERO_ZERO; m_oBorderMargins = new Margins(); m_oContentBorderMargins = new Margins(); m_oNEMargins = new Margins(); m_oContMargins = new Margins(); m_oCapMargins = new Margins(); m_oNE = Rect.ZERO; m_oRotatedContentTopLeft = CoordPair.ZERO_ZERO; m_oMaxEdgeThickness = UnitSpan.ZERO; m_oRotationAngle = Angle.ZERO; m_bGrowableH = false; m_bGrowableW = false; m_bInfiniteMaxH = false; m_bInfiniteMaxW = false; m_oMinW = m_oMaxW = m_oMinH = m_oMaxH = UnitSpan.ZERO; } /** * Gets the nominal bounding rectangle * relative to the local box model origin. * @return The nominal extent rectangle. */ public Rect getNominalExtent() { return m_oNE; } /** * Gets the width of the box model. * @return The width of the box model. */ public UnitSpan getWidth() { return m_oNE.width(); } /** * Gets the height of the box model. * @return The height of the box model. */ public UnitSpan getHeight() { return m_oNE.height(); } /** * Gets the visual bounding rectangle * relative to the local box model origin. * The visual extent is the nominal extent plus any border thickness * that extends outside. * @return The visual extent rectangle. */ public Rect getVisualExtent() { //Strategy //Add maximum border thicknesses to the nominal extent to yield the visual extent. //This implementation offers only a quicker (less accurate) visual extent by adjusting //each side of the nominal extent by max edge thickness. See initVisualExtent(..) for //more details. Rect oNE = getNominalExtent(); return new Rect(oNE.left().subtract(m_oMaxEdgeThickness), oNE.top().subtract(m_oMaxEdgeThickness), oNE.right().add(m_oMaxEdgeThickness), oNE.bottom().add(m_oMaxEdgeThickness)); } /** * Gets the nominal extent border rectangle * relative to the local box model origin. * @return The border extent rectangle. */ public Rect getBorderExtent() { //Border = NE - border_margins Rect oNE = getNominalExtent(); return new Rect(oNE.left().add(m_oBorderMargins.marginLeft()), oNE.top().add(m_oBorderMargins.marginTop()), oNE.right().subtract(m_oBorderMargins.marginRight()), oNE.bottom().subtract(m_oBorderMargins.marginBottom())); } /** * Gets the content border rectangle * relative to the local box model origin. * @return The content border extent rectangle. */ public Rect getContentBorderExtent() { // default is empty return Rect.ZERO; } /** * Gets the caption bounding rectangle * relative to the local box model origin. * @return The caption extent rectangle, which may be empty. */ public Rect getCaptionExtent() { //default is empty return Rect.ZERO; } /** * Gets the content rectangle. * @return The content extent rectangle. */ public Rect getContentExtent() { //Default content = NE - NEMargins - ContentMargins Rect oNE = getNominalExtent(); return new Rect(oNE.left().add(m_oNEMargins.marginLeft()).add(m_oContMargins.marginLeft()), oNE.top().add(m_oNEMargins.marginTop()).add(m_oContMargins.marginTop()), oNE.right().subtract(m_oNEMargins.marginRight()).subtract(m_oContMargins.marginRight()), oNE.bottom().subtract(m_oNEMargins.marginBottom()).subtract(m_oContMargins.marginBottom())); } /** * Gets the margins (top/left/bottom/right insets) of the caption extent. * @return The caption extent margins. */ public Margins getCaptionExtentMargins() { return m_oCapMargins; } /** * Gets the margins (top/left/bottom/right insets) of the content extent. * @return The content extent margins. */ public Margins getContentExtentMargins() { return m_oContMargins; } /** * Gets the rotation angle. * @return The rotation angle. */ public Angle getAngle() { return m_oRotationAngle; } /** * Gets the margins (top/left/bottom/right insets) of the nominal extent. * @return The nominal extent margins. */ public Margins getNominalExtentMargins() { return m_oNEMargins; } /** * Resets the top margin inset to zero. * * @exclude from published api. */ public void disableTopMargin() { m_oNEMargins = new Margins(m_oNEMargins.marginLeft(), UnitSpan.ZERO, m_oNEMargins.marginRight(), m_oNEMargins.marginBottom()); } /** * Resets the bottom margin inset to zero. * * @exclude from published api. */ public void disableBottomMargin() { m_oNEMargins = new Margins(m_oNEMargins.marginLeft(), m_oNEMargins.marginTop(), m_oNEMargins.marginRight(), UnitSpan.ZERO); } /** * Resets the content top margin to zero. * * @exclude from published api. */ public void disableContentTopMargin() { m_oContMargins = new Margins(m_oContMargins.marginLeft(), UnitSpan.ZERO, m_oContMargins.marginRight(), m_oContMargins.marginBottom()); } /** * Resets the content bottom margin to zero. * * @exclude from published api. */ public void disableContentBottomMargin() { m_oContMargins = new Margins(m_oContMargins.marginLeft(), m_oContMargins.marginTop(), m_oContMargins.marginRight(), UnitSpan.ZERO); } /** * Resets the caption top margin to zero. * * @exclude from published api. */ public void disableCaptionTopMargin() { m_oCapMargins = new Margins(m_oCapMargins.marginLeft(), UnitSpan.ZERO, m_oCapMargins.marginRight(), m_oCapMargins.marginBottom()); } /** * Reset the caption bottom margin to zero. * * @exclude from published api. */ public void disableCaptionBottomMargin() { m_oCapMargins = new Margins(m_oCapMargins.marginLeft(), m_oCapMargins.marginTop(), m_oCapMargins.marginRight(), UnitSpan.ZERO); } /** * Enumerates the box model's caption using given layout handler. * @param pHandler enumeration handler. * @param oOffset offset to apply to all enumerated caption data. * * @exclude from published api. */ public boolean enumerateCaption(LayoutHandler pHandler, CoordPair oOffset, boolean bTruncate /* = false */, Rect oInvalidatedRect /* = Rect.ZERO */) { return true; } /** * Enumerates the box model's contents through the given * layout handler. * @param pHandler enumeration handler. * @param oOffset offset to apply to all enumerated content data. * @param bWrapText indicates whether content data should wrap to. * extents * * @exclude from published api. */ public boolean enumerateContent(LayoutHandler pHandler, CoordPair oOffset, boolean bWrapText /* = true */, boolean bTruncate /* = false */, Rect oInvalidatedRect /* = Rect.ZERO */) { return true; } /** * Gets a string containing the box model caption. * @param sType indicates how to represent the data. * within the returned string (rtf|html|plain) * @param colorTable array of color values, can be null. * @param fontTable array of fonts used, can be null. * @return the string representation of box model caption, * or the empty string if there isn't any. * * @exclude from published api. */ public String getCaptionByType(String sType, List colorTable /* = null */, List fontTable /* = null */) { return ""; } /** * Gets a string containing the box model content. * @param sType indicates how to represent the data. * within the returned string (rtf|html|plain) * @param colorTable array of color values, can be null. * @param fontTable array of fonts used, can be null. * @return the string representation of box model contents, * or the empty string if there isn't any. * * @exclude from published api. */ public String getContentByType(String sType, List colorTable /* = null */, List fontTable /* = null */) { return ""; } /** * Gets the top left of the content region adjusted for rotations. * This is key since a rotated content region is adjusted so * that it is oriented 'up' always, which is not the correct * top left for text when a rotation is used * * @exclude from published api. */ public CoordPair getRotatedContentTopLeft() { //This is the top left of content region adjusted for any rotation. return m_oRotatedContentTopLeft; } /** * Gets the top left of the caption region adjusted for rotations. * This is key since a rotated caption region is adjusted so * that it is oriented 'up' always, which is not the correct * top left for text when a rotation is used * * @exclude from published api. */ public CoordPair getRotatedCaptionTopLeft() { //This is the top left of caption region adjusted for any rotation. return m_oRotatedCaptionTopLeft; } /** * Determines if this box model has any formattable content * within it's caption region. * @return true if it has. */ public boolean hasCaption() { return false; } /** * Determines if this box model has any formattable content * within it's content region. * @return true if it has. * * @exclude from published api. */ public boolean hasContent() { return false; } /** * Determines if this box model has had a rotation applied. * @return true if it has. */ public boolean hasRotation() { return m_bWasRotated; } /** * Determines if the caption extent has been fully contained * within this box model. * @return true if it has. * * @exclude from published api. */ public boolean hasCaptionExtentContained() { Rect oNE = getNominalExtent(); Rect oCE = getCaptionExtent(); return oNE.contains(oCE); } /** * Determines if the content extent has been fully contained * within this box model. * @return true if it has. * * @exclude from published api. */ public boolean hasContentExtentContained() { Rect oNE = getNominalExtent(); Rect oCE = getContentExtent(); return oNE.contains(oCE); } /** * Determines if this box model has embedded content. * @return true if the box model has. * * @exclude from published api. */ public boolean hasEmbeddedContent() { return false; } /** * Determines if this box model has been involved in a split. * @return true if the box model has. * * @exclude from published api. */ public boolean hasSplit() { return false; } /** * Initializes the box model internals. * It is not necessary to call this since newBoxModel(...) * does this automatically. * @param oNode the form node that the box model applies to. * * @exclude from published api. */ public void initialize(Element oNode) { //Strategy //1)Set xy/anchor point //2)Set nominal extent //3)Set margins //4)Set border //5)Adjust to rotation (if any) assert(oNode != null); if (! isBoxModelCompatible(oNode)) return; initWidthHeight(oNode, false); initAnchorPoint(oNode); initMargins(oNode); initRotatedContentTopLeft(); initBorder(oNode); respectRotation(oNode); initVisualExtent(oNode); } /** * Determines if this box model has a font that's been * substituted. Used for text caching. * @return true if the box model has fonts that were substituted. * * @exclude from published api. */ public boolean isFontSubstituted() { return false; } /** * Is this box model is based on a proxy definition -- ie. drawn from stored text run definitions. * @return true if drawn from text runs. * * @exclude from published api. */ public boolean isProxy() { return false; } /** * Re-initializes the box model. * @param oNode the form node that the box model applies to. * * @exclude from published api. */ public void reinitialize(Element oNode) { clear(); assert(oNode != null); initialize(oNode); } /** * Resizes the box model by setting it's new nominal extent. * Content/caption extents will be updated as well. * @param oW new nominal extent width. * @param oH new nominal extent height. * @param oNode the form node that the box model applies to. * * @exclude from published api. */ public void resizeToNominal(UnitSpan oW, UnitSpan oH, Element oNode) { // // All we have to do is set nominal extent and then // border/content/position will be updated automatically. // assert(UnitSpan.ZERO.lte(oW)); assert(UnitSpan.ZERO.lte(oH)); m_oNE = m_oNE.width(oW, false); m_oNE = m_oNE.height(oH, false); } /** * Resizes the box model by setting it's new nominal extent width. * The height will automatically update if the box model is h-growable. * Content/caption extents will be updated as well. * @param oW new nominal extent width. * @param oNode the form node that the box model applies to. * * @exclude from published api. */ public void resizeToNominalWidth(UnitSpan oW, Element oNode) { // // All we have to do is set nominal extent width and then // border/content/position will be updated automatically. // assert(UnitSpan.ZERO.lte(oW)); m_oNE.width(oW, false); } /** * Resizes the box model by setting it's new content extent. * The nominal extent + caption extent will be reformulated based * on the new content size. * @param oContentW new width of content. * @param oContentH new height of content. * @param oNode the form node that the box model applies to. * * @exclude from published api. */ public void resizeToContent(UnitSpan oContentW, UnitSpan oContentH, Element oNode) { // // Resize this box-model around the given dimensions of // it's new content extents and current margin values. // Content = NE - margins // assert(UnitSpan.ZERO.lte(oContentW)); assert(UnitSpan.ZERO.lte(oContentW)); m_oNE = m_oNE.width(oContentW .add(m_oNEMargins.marginLeft()) .add(m_oContMargins.marginLeft()) .add(m_oContMargins.marginRight()) .add(m_oNEMargins.marginRight()), false); m_oNE = m_oNE.height(oContentH .add(m_oNEMargins.marginTop()) .add(m_oContMargins.marginTop()) .add(m_oContMargins.marginBottom()) .add(m_oNEMargins.marginBottom()), false); } /** * Split the contents of this box model by trimming * anything would not fit within new height. * @param oNewHeight the distance from top of nominal extent. * at which to perform split. * @param oNewBM upon return this refers to a box model. * is the portion of the original box modle that did * not fit. * @param oNode the form node that the box model applies to. * @return true if box model was successfully split. * * @exclude from published api. */ public boolean split(UnitSpan oNewHeight, ObjectHolder oNewBM, Element oNode) { boolean bSplit = false; BoxModelLayout pImpl = null; bSplit = splitImpl(oNewHeight, pImpl, oNode); if (bSplit) oNewBM.value = pImpl; else oNewBM.value = new BoxModelLayout(); return bSplit; } /** * @exclude from published api. */ protected boolean splitImpl(UnitSpan oNewHeight, BoxModelLayout oNewBM, Element oNode) { return false; } // // These function guard against precision errors with our unitspans that affect // // our <= and >= unitspan comparisons. These macros will compare give or take a 5 millionths of an inch epsilon. // private static boolean UNITS_LTE(UnitSpan a, UnitSpan b) { // if (a.gt(b)) // return Math.abs(a.valueAsUnit(UnitSpan.INCHES_1M) - b.valueAsUnit(UnitSpan.INCHES_1M)) <= 5; // return true; // } private static boolean UNITS_GTE(UnitSpan a, UnitSpan b) { if (a.lt(b)) return Math.abs(a.valueAsUnit(UnitSpan.INCHES_1M) - b.valueAsUnit(UnitSpan.INCHES_1M)) >= 5; return true; } /** * Determines if this box model has a growable width. * @return true if it does. * * @exclude from published api. */ public boolean hasGrowableW() { return m_bGrowableW; } /** * Determines if this box model has a growable height. * @return true if it does. * * @exclude from published api. */ public boolean hasGrowableH() { return m_bGrowableH; } /** * @exclude from published api. */ public int getAnchor() { return m_oAnchorType; } /** * @exclude from published api. */ public CoordPair getAnchorPoint() { return m_oAnchorPoint; } /** * @exclude from published api. */ public void setAnchor(int eVal) { m_oAnchorType = eVal; } /** * @exclude from published api. */ public void setAnchorPoint(CoordPair oPt) { m_oAnchorPoint = oPt; } /** * @exclude from published api. */ public void initAnchorPoint(Element oNode) { // int eType = EnumAttr.TOP_LEFT; // if (oNode.isPropertySpecified(XFA.ANCHORTYPETAG, true, 0)) // eType = oNode.getEnum(XFA.ANCHORTYPETAG); m_oAnchorPoint = CoordPair.ZERO_ZERO; // TOP_LEFT. Do nothing. if (EnumAttr.TOP_CENTER == m_oAnchorType) m_oAnchorPoint = new CoordPair(m_oNE.width().divide(2), m_oAnchorPoint.y()); else if (EnumAttr.TOP_RIGHT == m_oAnchorType) m_oAnchorPoint = new CoordPair(m_oNE.width(), m_oAnchorPoint.x()); else if (EnumAttr.MIDDLE_LEFT == m_oAnchorType) m_oAnchorPoint = new CoordPair(m_oAnchorPoint.x(), m_oNE.height().divide(2)); else if (EnumAttr.MIDDLE_CENTER == m_oAnchorType) { m_oAnchorPoint = new CoordPair(m_oNE.width().divide(2), m_oNE.height().divide(2)); } else if (EnumAttr.MIDDLE_RIGHT == m_oAnchorType) { m_oAnchorPoint = new CoordPair(m_oNE.width(), m_oNE.height().divide(2)); } else if (EnumAttr.BOTTOM_LEFT == m_oAnchorType) m_oAnchorPoint = new CoordPair(m_oAnchorPoint.x(), m_oNE.height()); else if (EnumAttr.BOTTOM_CENTER == m_oAnchorType) { m_oAnchorPoint = new CoordPair(m_oNE.width().divide(2), m_oNE.height()); } else if (EnumAttr.BOTTOM_RIGHT == m_oAnchorType) { m_oAnchorPoint = new CoordPair(m_oNE.width(), m_oNE.height()); } } /** * @exclude from published api. */ public void initBorder(Element oNode) { if (oNode.isPropertySpecified(XFA.BORDERTAG, true, 0)) { Element oBorder = oNode.peekElement(XFA.BORDERTAG, true, 0); Element oBorderMargins = oBorder.peekElement(XFA.MARGINTAG, true, 0); ObjectHolder oLHolder = new ObjectHolder(); ObjectHolder oTHolder = new ObjectHolder(); ObjectHolder oRHolder = new ObjectHolder(); ObjectHolder oBHolder = new ObjectHolder(); ((Margin)oBorderMargins).getInsets(oTHolder, oRHolder, oBHolder, oLHolder); m_oBorderMargins = new Margins(oLHolder.value, oTHolder.value, oRHolder.value, oBHolder.value); } if (oNode instanceof Field) { UI oUI = (UI) oNode.peekElement(XFA.UITAG, false, 0); if (oUI != null) { Element oCurrentUI = oUI.getUIElement(false); if (oCurrentUI != null && (oCurrentUI.isSameClass(XFA.CHECKBUTTONTAG) || oCurrentUI.isSameClass(XFA.CHOICELISTTAG) || oCurrentUI.isSameClass(XFA.DATETIMEEDITTAG) || oCurrentUI.isSameClass(XFA.NUMERICEDITTAG) || oCurrentUI.isSameClass(XFA.PASSWORDEDITTAG) || oCurrentUI.isSameClass(XFA.SIGNATURETAG) || oCurrentUI.isSameClass(XFA.TEXTEDITTAG)) && oCurrentUI.isPropertySpecified(XFA.BORDERTAG, true, 0)) { Element oBorder = oCurrentUI.peekElement(XFA.BORDERTAG, true, 0); Element oBorderMargins = oBorder.peekElement(XFA.MARGINTAG, true, 0); ObjectHolder oLHolder = new ObjectHolder(); ObjectHolder oTHolder = new ObjectHolder(); ObjectHolder oRHolder = new ObjectHolder(); ObjectHolder oBHolder = new ObjectHolder(); ((Margin)oBorderMargins).getInsets(oTHolder, oRHolder, oBHolder, oLHolder); m_oContentBorderMargins = new Margins(oLHolder.value, oTHolder.value, oRHolder.value, oBHolder.value); } } } } /** * @exclude from published api. */ public void initVisualExtent(Element oNode) { // //Strategy //Perform the necessary calculations for the approximate visual extent of this box model. //The visual extent of a box model will be calculated by taking the nominal extent and expanding //it by the maximum border thickness. Yes, this is an approximation of the visual extent, but doing so //has several benefits: //i) automatically works for rotated box models //ii) it's smaller, faster and less complex than a more exact implementation //iii)at this time perfect accuracy is not warranted for getVisualExtent() - as long as the returned //visual extent covers the entire object. // //Rather than have each boxmodel instance store another Rect for the visual extent, simply store //the max border thickness. Whenever the visual extent is required it will be calculated using the current //nominal extent. A single unitspan member var uses 1/4 the memory footprint of having a Rect member var. // assert(oNode != null); m_oMaxEdgeThickness = UnitSpan.ZERO; if (oNode != null) { if (oNode.isPropertySpecified(XFA.BORDERTAG, true, 0)) { Element oBorder = oNode.peekElement(XFA.BORDERTAG, false, 0); // //Right handedness means border is entirely within nominal extent // if (oBorder.getEnum(XFA.HANDTAG) != EnumAttr.HAND_RIGHT) { for (int nNumEdges = 0; nNumEdges < 4; nNumEdges++) { Element oEdge = oBorder.peekElement(XFA.EDGETAG, false, nNumEdges); if (oEdge == null) break; Measurement oThickness = new Measurement(oEdge.getAttribute(XFA.THICKNESSTAG)); if (oThickness.getUnitSpan().gt(m_oMaxEdgeThickness)) m_oMaxEdgeThickness = oThickness.getUnitSpan(); } } } // //Some draws have special cicumstances. Arcs, rectangles and line edges //can affect the visual extents with their edge thicknesses // if (oNode instanceof Draw) { Element oValue = oNode.peekElement(XFA.VALUETAG, true, 0); Content oContent = (Content) oValue.getOneOfChild(true, true); int oContentTag = oContent.getClassTag(); if (oContentTag == XFA.RECTANGLETAG || oContentTag == XFA.ARCTAG || oContentTag == XFA.LINETAG) { int nTotalPossibleEdges = 1; if (oContentTag == XFA.RECTANGLETAG) nTotalPossibleEdges = 4; for (int nNumEdges = 0; nNumEdges < nTotalPossibleEdges; nNumEdges++) { Element oEdge = ((Element) oContent).peekElement(XFA.EDGETAG, false, nNumEdges); if (oEdge == null) { // //WATSON 1110608 - Line edges are special, er more special (specialer?). //Even if there is no edge defined, a default edge still gets drawn, which affects the visual extent. //This is different from most objects in that other objects require at least an element to be specified. // if (oContentTag == XFA.LINETAG) { oEdge = ((Element) oContent).peekElement(XFA.EDGETAG, true, nNumEdges);//default } else break; } Measurement oThickness = new Measurement(oEdge.getAttribute(XFA.THICKNESSTAG)); if (oThickness.getUnitSpan().gt(m_oMaxEdgeThickness)) m_oMaxEdgeThickness = oThickness.getUnitSpan(); } } } } } /** * @exclude from published api. */ protected void initWidthHeight(Element oNode, boolean bSupportsGrowability) { //Retrieve the w/h of the nominal extents. //Default implementation of initWidtHeight makes objects non-growable. //Objects that can be growable should override this function. //If not specified the default for objects is to use the minW/minH in its place. //In other words, objects that do not support the notion of 'growing' //will use the min values in the absence of a specified w/h. //Boxmodel objects that want to support growable will do so //in thier own boxmodel implementation. //Objects like rects/arcs/lines/images etc that do not specify a w/h but specify //a minW/H will use the min value, ie // //will result in an arc draw that has a nominal extent 3in high and 2in wide. UnitSpan oW = UnitSpan.ZERO; UnitSpan oH = UnitSpan.ZERO; if (oNode.isPropertySpecified(XFA.WTAG, true, 0)) { Measurement oMeasW = new Measurement(oNode.getAttribute(XFA.WTAG)); oW = oMeasW.getUnitSpan(); } else if (oNode.isPropertySpecified(XFA.MINWTAG, true, 0)) { Measurement oMeasW = new Measurement(oNode.getAttribute(XFA.MINWTAG)); oW = oMeasW.getUnitSpan(); } if (oNode.isPropertySpecified(XFA.HTAG, true, 0)) { Measurement oMeasH = new Measurement(oNode.getAttribute(XFA.HTAG)); oH = oMeasH.getUnitSpan(); } else if (oNode.isPropertySpecified(XFA.MINHTAG, true, 0)) { Measurement oMeasH = new Measurement(oNode.getAttribute(XFA.MINHTAG)); oH = oMeasH.getUnitSpan(); } // //Guard against bad values // if (0 > oW.value()) oW = UnitSpan.ZERO; if (0 > oH.value()) oH = UnitSpan.ZERO; // //Set the nominal extents // m_oNE = m_oNE.changeUnits(UnitSpan.INCHES_72K); m_oNE = m_oNE.width(oW, false); // lefWidth(moLeft, oW); m_oNE = m_oNE.height(oH, false); // topHeight(moTop, oH); m_bGrowableH = false; m_bGrowableW = false; m_bInfiniteMaxH = false; m_bInfiniteMaxW = false; if (bSupportsGrowability) { assert(oNode instanceof Container); if (oNode instanceof Container) { Container oContainer = (Container) oNode; m_bGrowableW = oContainer.isWidthGrowable(); m_bGrowableH = oContainer.isHeightGrowable(); } } if (! m_bGrowableW) { // //Non-growable ne width was determined in initWH() // m_oMinW = m_oMaxW = m_oNE.width(); } else { // //For now just record the ranges //Important to only query for min values if they are specified. Otherwise they'll //return the h value by default. // m_oMinW = UnitSpan.ZERO; if (oNode.isPropertySpecified(XFA.MINWTAG, true, 0)) { Measurement oMeas = new Measurement(oNode.getAttribute(XFA.MINWTAG)); m_oMinW = oMeas.getUnitSpan(); } Measurement oMeas = new Measurement(oNode.getAttribute(XFA.MAXWTAG)); m_oMaxW = oMeas.getUnitSpan(); m_bInfiniteMaxW = ! oNode.isPropertySpecified(XFA.MAXWTAG, true, 0); //Kludge - if maxW is zero then treat this as infinite maxW. //The reason is that maxW="" returns as specified, and the value is zero. //The downside is that if someone says maxW="0in" then this too is treated //as infinite growability. For now I'd rather support maxW="" properly, since //maxW="0in" is not really a good idea on any day. if (! m_bInfiniteMaxW && m_oMaxW.equals(UnitSpan.ZERO)) m_bInfiniteMaxW = true; } if (! m_bGrowableH) { //Non-growable ne height was determined in initWH() m_oMinH = m_oMaxH = m_oNE.height(); } else { //For now just record the ranges. //Important to only query for min values if they are specified. Otherwise they'll //return the h value by default. m_oMinH = UnitSpan.ZERO; if (oNode.isPropertySpecified(XFA.MINHTAG, true, 0)) { Measurement oMeas = new Measurement(oNode.getAttribute(XFA.MINHTAG)); m_oMinH = oMeas.getUnitSpan(); } Measurement oMeas = new Measurement(oNode.getAttribute(XFA.MAXHTAG)); m_oMaxH = oMeas.getUnitSpan(); m_bInfiniteMaxH = ! oNode.isPropertySpecified(XFA.MAXHTAG, true, 0); //Kludge - if maxH is zero then treat this as infinite maxH. //The reason is that maxH="" returns as specified, and the value is zero. //The downside is that if someone says maxH="0in" then this too is treated //as infinite growability. For now I'd rather support maxH="" properly, since //maxH="0in" is not really a good idea on any day. if (! m_bInfiniteMaxH && m_oMaxH.equals(UnitSpan.ZERO)) m_bInfiniteMaxH = true; } assert(UnitSpan.ZERO.lte(m_oMinW)); assert(UnitSpan.ZERO.lte(m_oMinH)); assert(UnitSpan.ZERO.lte(m_oMaxH)); assert(UnitSpan.ZERO.lte(m_oMaxW)); assert(m_bInfiniteMaxW || UNITS_GTE(m_oMaxW, m_oMinW)); assert(m_bInfiniteMaxH || UNITS_GTE(m_oMaxH, m_oMinH)); if (UnitSpan.ZERO.gt(m_oMinW)) m_oMinW = UnitSpan.ZERO; if (UnitSpan.ZERO.gt(m_oMinH)) m_oMinH = UnitSpan.ZERO; if (UnitSpan.ZERO.gt(m_oMaxH)) m_oMaxH = UnitSpan.ZERO; if (UnitSpan.ZERO.gt(m_oMaxW)) m_oMaxW = UnitSpan.ZERO; // //Imperative to set units to inches_72k to limit prevision loss in text engine. // m_oMinH = new UnitSpan(UnitSpan.INCHES_72K, m_oMinH.value()); m_oMinW = new UnitSpan(UnitSpan.INCHES_72K, m_oMinW.value()); m_oMaxH = new UnitSpan(UnitSpan.INCHES_72K, m_oMaxH.value()); m_oMaxW = new UnitSpan(UnitSpan.INCHES_72K, m_oMaxW.value()); } /** * @exclude from published api. */ protected void initMargins(Element oNode) { // // There are 3 types of margins we are interested in. // // 1. Nominal Extent Margins // 2. Content Margins // 3. Caption Margins // // These margins are used to calculate the appropriate // extents for our caption and content regions. // // Content margins are currently reserved for the // following UI types: // // DateTimeEdit, ChoiceList, NumericEdit, PasswordEdit, // TextEdit, CheckButton and Signature. // // // Init Nominal Extent Margins // if (oNode.isPropertySpecified(XFA.MARGINTAG, true, 0)) { Element oMargins = oNode.peekElement(XFA.MARGINTAG, true, 0); ObjectHolder oLHolder = new ObjectHolder(); ObjectHolder oTHolder = new ObjectHolder(); ObjectHolder oRHolder = new ObjectHolder(); ObjectHolder oBHolder = new ObjectHolder(); ((Margin)oMargins).getInsets(oTHolder, oRHolder, oBHolder, oLHolder); UnitSpan oL = oLHolder.value.changeUnits(UnitSpan.INCHES_72K); UnitSpan oR = oRHolder.value.changeUnits(UnitSpan.INCHES_72K); UnitSpan oT = oTHolder.value.changeUnits(UnitSpan.INCHES_72K); UnitSpan oB = oBHolder.value.changeUnits(UnitSpan.INCHES_72K); m_oNEMargins = new Margins(oL, oT, oR, oB); } // // If this is a field or a draw, then we will initialize the content and caption margins appropriately. // if (oNode instanceof Field || oNode instanceof Draw) { // //Watson 1430544 + 1487018, 1487021, 1487025, 1487027, 1487891. //We cannot use peekElement calls to drill down to query widget/caption margins, since we the default auto-calculates in a context //sensitive manner (based on parental border thickness + font size). //So the returned margin must be a resident of the same model as it's parental ui type, which must be in the same model as the etc //Calling getProperty() ensures that default nodes get copied over to the form model, if that's where the field resides. //To avoid receiving damage notifications we must mute the nodes before and unmute them again afterwards. Otherwise the act of building //a layout could cause be broadcasting fake damage. // Element oNonConstMutableNode = oNode; oNonConstMutableNode.mute(); // // Drill down to the content margins // Element oUI = (Element) oNode.getProperty(XFA.UITAG, 0); oUI.mute(); //to be safe, mute the ui so the no peers hear this Element oCurrentUI = (Element) oUI.getOneOfChild(); oUI.unMute(); int oCurrentUITag = oCurrentUI.getClassTag(); if (oCurrentUITag == XFA.TEXTEDITTAG || oCurrentUITag == XFA.NUMERICEDITTAG || oCurrentUITag == XFA.CHECKBUTTONTAG || oCurrentUITag == XFA.DATETIMEEDITTAG || oCurrentUITag == XFA.SIGNATURETAG || oCurrentUITag == XFA.PASSWORDEDITTAG || oCurrentUITag == XFA.IMAGEEDITTAG || oCurrentUITag == XFA.CHOICELISTTAG) { oCurrentUI.mute();//to be safe, mute the ui so the no peers hear this Element oMargins = (Element) oCurrentUI.getProperty(XFA.MARGINTAG, 0); oCurrentUI.unMute(); ObjectHolder oLHolder = new ObjectHolder(); ObjectHolder oTHolder = new ObjectHolder(); ObjectHolder oRHolder = new ObjectHolder(); ObjectHolder oBHolder = new ObjectHolder(); ((Margin)oMargins).getInsets(oTHolder, oRHolder, oBHolder, oLHolder); UnitSpan oL = oLHolder.value.changeUnits(UnitSpan.INCHES_72K); UnitSpan oR = oRHolder.value.changeUnits(UnitSpan.INCHES_72K); UnitSpan oT = oTHolder.value.changeUnits(UnitSpan.INCHES_72K); UnitSpan oB = oBHolder.value.changeUnits(UnitSpan.INCHES_72K); m_oContMargins = new Margins(oL, oT, oR, oB); } // //Drill down to the caption margins using getProperty() (if there is a caption) // if (oNode.isPropertySpecified(XFA.CAPTIONTAG, true, 0)) { Element oCaption = (Element) oNode.getProperty(XFA.CAPTIONTAG, 0); oCaption.mute(); //to be safe, mute the ui so the layout is undamaged by this act Element oMargins = (Element) oCaption.getProperty(XFA.MARGINTAG, 0); oCaption.unMute(); ObjectHolder oLHolder = new ObjectHolder(); ObjectHolder oTHolder = new ObjectHolder(); ObjectHolder oRHolder = new ObjectHolder(); ObjectHolder oBHolder = new ObjectHolder(); ((Margin)oMargins).getInsets(oTHolder, oRHolder, oBHolder, oLHolder); UnitSpan oL = oLHolder.value.changeUnits(UnitSpan.INCHES_72K); UnitSpan oR = oRHolder.value.changeUnits(UnitSpan.INCHES_72K); UnitSpan oT = oTHolder.value.changeUnits(UnitSpan.INCHES_72K); UnitSpan oB = oBHolder.value.changeUnits(UnitSpan.INCHES_72K); m_oCapMargins = new Margins(oL, oT, oR, oB); } //Finished drilling down to the content/caption margins. Allow the field/draw to send peer notifications again oNonConstMutableNode.unMute(); } } /** * @exclude from published api. */ protected void initRotatedContentTopLeft() { m_oRotatedContentTopLeft = getContentExtent().topLeft(); } /** * @exclude from published api. */ protected boolean isBoxModelCompatible(Element oNode) { // //Return true if oNode represents a form node that //subscribes to the box model layout paradigm {draw, field, //subform, area, contentArea, pageArea, exclGroup } and //false otherwise. // boolean bCompatible = false; if (oNode != null) { bCompatible = oNode instanceof Draw || oNode instanceof Field || oNode instanceof Subform || oNode instanceof AreaContainer || oNode instanceof ContentArea || oNode instanceof PageArea || oNode instanceof ExclGroup; } return bCompatible; } /** * @exclude from published api. */ protected void respectRotation(Element oNode) { //Adjust the box model if it is rotated. //Only support rotation on fields+draws, m_bWasRotated = false; m_oRotationAngle = Angle.ZERO; if (oNode instanceof Draw || oNode instanceof Field) { // Set the default value for the rotated top left, // since this value gets referenced whether the object // is rotated or not. m_oRotatedContentTopLeft = getContentExtent().topLeft(); if (oNode.isPropertySpecified(XFA.ROTATETAG, true, 0)) { Rotate oRotate = new Rotate(XFA.ROTATE, oNode.getAttribute(XFA.ROTATETAG).toString()); Angle oAngle = oRotate.getAngle(); int lAngle = oAngle.degrees(); lAngle = lAngle % 360; if (0 > lAngle) lAngle += 360; oAngle = new Angle(lAngle); m_oRotationAngle = oAngle; Margins oPrevMargins = m_oNEMargins; Margins oPrevBorderMargins = m_oBorderMargins; Margins oPrevWidgetBorderMargins = m_oContentBorderMargins; Margins oPrevWidgetContentMargins = m_oContMargins; Margins oPrevWidgetCaptionMargins = m_oCapMargins; CoordPair oPrevContentExtentTL = getContentExtent().topLeft(); Rect rcPrevNE = getNominalExtent(); CoordPair oNewTL = CoordPair.ZERO_ZERO; CoordPair oNewTR = CoordPair.ZERO_ZERO; //CoordPair oNewBL = new CoordPair(); CoordPair oNewBR = CoordPair.ZERO_ZERO; CoordPair oPrevTL = rcPrevNE.topLeft(); CoordPair oPrevTR = rcPrevNE.topRight(); CoordPair oPrevBL = rcPrevNE.bottomLeft(); CoordPair oPrevBR = rcPrevNE.bottomRight(); // //Line slope will have to be adjusted //by renderer - can't modify template/form nodes here. // switch (lAngle) { case 0: //nothing to do return; case 270: { //1)rotate the 4 corner points 270 degrees about 'm_oAnchorPoint' //2)adjust new anchor point to new orientation //3)flip content margins + border margins //4)for both caption+non caption extents, // rotate the 4 corner points 270 degrees about 'anchor' point oNewTR = oPrevTL.rotatePoint(m_oAnchorPoint, oAngle); oNewBR = oPrevTR.rotatePoint(m_oAnchorPoint, oAngle); //oNewBL = oPrevBR.rotatePoint(m_oAnchorPoint, oAngle); oNewTL = oPrevBL.rotatePoint(m_oAnchorPoint, oAngle); m_oNEMargins = new Margins(oPrevMargins); m_oNEMargins = new Margins(oPrevMargins.marginBottom(), oPrevMargins.marginLeft(), oPrevMargins.marginTop(), oPrevMargins.marginRight()); m_oBorderMargins = new Margins(oPrevBorderMargins.marginBottom(), oPrevBorderMargins.marginLeft(), oPrevBorderMargins.marginTop(), oPrevBorderMargins.marginRight()); m_oContentBorderMargins = new Margins(oPrevWidgetBorderMargins.marginBottom(), oPrevWidgetBorderMargins.marginLeft(), oPrevWidgetBorderMargins.marginTop(), oPrevWidgetBorderMargins.marginRight()); m_oContMargins = new Margins(oPrevWidgetContentMargins.marginBottom(), oPrevWidgetContentMargins.marginLeft(), oPrevWidgetContentMargins.marginTop(), oPrevWidgetContentMargins.marginRight()); m_oCapMargins = new Margins(oPrevWidgetCaptionMargins.marginBottom(), oPrevWidgetCaptionMargins.marginLeft(), oPrevWidgetCaptionMargins.marginTop(), oPrevWidgetCaptionMargins.marginRight()); // //Adjust the top left of content extent for text, etc. // m_oRotatedContentTopLeft = oPrevContentExtentTL.rotatePoint(m_oAnchorPoint, oAngle); } break; case 180: { //1)rotate the 4 corner points 180 degrees about 'm_oAnchorPoint' //2)adjust new anchor point to new orientation //3)flip content margins + border margins //4)for both caption+non caption extents, // rotate the 4 corner points 180 degrees about 'anchor' point oNewBR = oPrevTL.rotatePoint(m_oAnchorPoint, oAngle); //A //oNewBL = oPrevTR.rotatePoint(m_oAnchorPoint, oAngle); //B oNewTL = oPrevBR.rotatePoint(m_oAnchorPoint, oAngle); //C oNewTR = oPrevBL.rotatePoint(m_oAnchorPoint, oAngle); //D m_oNEMargins = new Margins(oPrevMargins.marginRight(), oPrevMargins.marginBottom(), oPrevMargins.marginLeft(), oPrevMargins.marginTop()); m_oBorderMargins = new Margins(oPrevBorderMargins.marginRight(), oPrevBorderMargins.marginBottom(), oPrevBorderMargins.marginLeft(), oPrevBorderMargins.marginTop()); m_oContentBorderMargins = new Margins(oPrevWidgetBorderMargins.marginRight(), oPrevWidgetBorderMargins.marginBottom(), oPrevWidgetBorderMargins.marginLeft(), oPrevWidgetBorderMargins.marginTop()); m_oContMargins = new Margins(oPrevWidgetContentMargins.marginRight(), oPrevWidgetContentMargins.marginBottom(), oPrevWidgetContentMargins.marginLeft(), oPrevWidgetContentMargins.marginTop()); m_oCapMargins = new Margins(oPrevWidgetCaptionMargins.marginRight(), oPrevWidgetCaptionMargins.marginBottom(), oPrevWidgetCaptionMargins.marginLeft(), oPrevWidgetCaptionMargins.marginTop()); // //Adjust the top left of content extent for text, etc. // m_oRotatedContentTopLeft = oPrevContentExtentTL.rotatePoint(m_oAnchorPoint, oAngle); } break; case 90: { //1)rotate the 4 corner points 90 degrees about 'm_oAnchorPoint' //2)adjust new anchor point to new orientation //3)flip content margins + border margins //4)for both caption+non caption extents, // rotate the 4 corner points 180 degrees about 'anchor' point //oNewBL = oPrevTL.rotatePoint(m_oAnchorPoint, oAngle); //A oNewTL = oPrevTR.rotatePoint(m_oAnchorPoint, oAngle); //B oNewTR = oPrevBR.rotatePoint(m_oAnchorPoint, oAngle); //C oNewBR = oPrevBL.rotatePoint(m_oAnchorPoint, oAngle); //D m_oNEMargins = new Margins(oPrevMargins.marginTop(), oPrevMargins.marginRight(), oPrevMargins.marginBottom(), oPrevMargins.marginLeft()); m_oBorderMargins = new Margins(oPrevBorderMargins.marginTop(), oPrevBorderMargins.marginRight(), oPrevBorderMargins.marginBottom(), oPrevBorderMargins.marginLeft()); m_oContentBorderMargins = new Margins(oPrevWidgetBorderMargins.marginTop(), oPrevWidgetBorderMargins.marginRight(), oPrevWidgetBorderMargins.marginBottom(), oPrevWidgetBorderMargins.marginLeft()); m_oContMargins = new Margins(oPrevWidgetContentMargins.marginTop(), oPrevWidgetContentMargins.marginRight(), oPrevWidgetContentMargins.marginBottom(), oPrevWidgetContentMargins.marginLeft()); m_oCapMargins = new Margins(oPrevWidgetCaptionMargins.marginTop(), oPrevWidgetCaptionMargins.marginRight(), oPrevWidgetCaptionMargins.marginBottom(), oPrevWidgetCaptionMargins.marginLeft()); //Adjust the top left of content extent for text, etc. m_oRotatedContentTopLeft = oPrevContentExtentTL.rotatePoint(m_oAnchorPoint, oAngle); } break; default: { //Only 90 degree increments are handled //Todo: log warning message? assert(false); } break; } // Record if there was a rotation m_bWasRotated = (0 != lAngle); // //Todo: calculate true anchor // m_oAnchorType = EnumAttr.TOP_LEFT; m_oAnchorPoint = oNewTL; // // Set the new nominal extent // UnitSpan oNewWidth = oNewTR.x().subtract(oNewTL.x()); UnitSpan oNewHeight = oNewBR.y().subtract(oNewTR.y()); if (oNewWidth.value() < 0) oNewWidth = oNewWidth.multiply(-1L); if (oNewHeight.value() < 0) oNewHeight = oNewHeight.multiply(-1L); assert(oNewWidth.gte(UnitSpan.ZERO)); assert(oNewHeight.gte(UnitSpan.ZERO)); m_oNE = m_oNE.width(oNewWidth, false); m_oNE = m_oNE.height(oNewHeight, false); } } } /** * @exclude from published api. */ protected void setGrowableH(UnitSpan oMinH, UnitSpan oMaxH) { assert(oMinH.lte(oMaxH) || oMaxH.equals(new UnitSpan(UnitSpan.INCHES_72K, -1))); assert(oMinH.gte(UnitSpan.ZERO)); m_bInfiniteMaxH = (oMaxH.equals(new UnitSpan(UnitSpan.INCHES_72K, -1))); if (oMinH.lt(oMaxH) || m_bInfiniteMaxH) { m_bGrowableH = true; m_oMinH = oMinH; m_oMaxH = oMaxH; } else { m_bGrowableH = false; m_bInfiniteMaxH = false; m_oMinH = oMinH; m_oMaxH = oMinH; } } /** * @exclude from published api. */ protected void setGrowableW(UnitSpan oMinW, UnitSpan oMaxW) { assert(oMinW.lte(oMaxW) || oMaxW.equals(new UnitSpan(UnitSpan.INCHES_72K, -1))); assert(oMinW.gte(UnitSpan.ZERO)); m_bInfiniteMaxW = (oMaxW.equals(new UnitSpan(UnitSpan.INCHES_72K, -1))); if (oMinW.lt(oMaxW) || m_bInfiniteMaxW) { m_bGrowableW = true; m_oMinW = oMinW; m_oMaxW = oMaxW; } else { m_bGrowableW = false; m_bInfiniteMaxW = false; m_oMinW = oMinW; m_oMaxW = oMinW; } } /** * Return true if this box model contains text that overflows it's allotted space * and false otherwise. * @return false if this object contains no text. * @exclude from published api. */ public boolean hasOverflowingContentText() { return false; } /** * Return true if this box model contains text that overflows it's allotted space * and false otherwise. * @return false if this object contains no text. * @exclude from published api. */ public boolean hasOverflowingCaptionText() { return false; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy