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

com.adobe.xfa.text.TextFrame Maven / Gradle / Ivy

There is a newer version: 2024.11.18751.20241128T090041Z-241100
Show newest version
package com.adobe.xfa.text;

import com.adobe.xfa.gfx.GFXDriver;
import com.adobe.xfa.gfx.GFXEnv;
import com.adobe.xfa.gfx.GFXModelContext;

import com.adobe.xfa.ut.CoordPair;
import com.adobe.xfa.ut.Rect;
import com.adobe.xfa.ut.Storage;
import com.adobe.xfa.ut.UnitSpan;

/**
 * The text frame class represents the geometry and eventually layout of
 * a single frame.
 * 

* The client creates all frame instances, either to pass to the sparse * stream API or as a result of its implementation of the sparse stream * event handling methods. The client must populate its created frames * with geometry information. A future implementation may allow the * client to set text attributes for a frame as well. *

*

* Once the client passes a frame instance to the sparse stream, AXTE * takes over and populates its layout. The layout may come from a * client-supplied layout object, or it may be generated by AXTE as the * result of a reflow operation. *

*

* Frames are reference counted objects, allowing the client to retain * handles to objects that are managed by AXTE. *

*

* While frames have width and height geometry, it is up to the client * to decide how to map frames into its rendering space. AXTE treats * the top-left corner of each frame as its origin. *

* @exclude from published api. */ public abstract class TextFrame implements GFXModelContext { static final int LAYOUT_NORMAL = 0; static final int LAYOUT_INITIAL = 1; static final int LAYOUT_SUSPECT = 2; private static final Rect gDefaultExtent = Rect.ZERO; private TextSparseStream mpoStream; private TextPosn moStart; // TODO: which member objects to pre-create? private CoordPair moXYOrigin = CoordPair.ZERO_ZERO; private UnitSpan moAMax = UnitSpan.ZERO; private UnitSpan moBMax = UnitSpan.ZERO; private Rect moExtent = gDefaultExtent; private final Storage moLines = new Storage(); // text broken into lines private int mnActualCombCells; private int meLayout = LAYOUT_NORMAL; private int meOldOrientation = TextAttr.ORIENTATION_HORIZONTAL; private boolean mbIsDirty; /** * Default constructor. */ public TextFrame () { } /** * Copy constructor. * @param oSource - Source frame to copy. */ public TextFrame (TextFrame oSource) { copyFrom (oSource); } /** * Query whether vertical alignment occurs at a point. *

* The text label class performs vertical alignment at a point. The * text block and region have a nominal height. Vertical alignment * occurs within this height. This method asks the stream what sort of * vertical alignment it supports. * @return TRUE if the stream aligns vertically at a point; FALSE if it * aligns vertically within a nominal height. */ public boolean alignVPoint () { return minHeight().value() < 0; } /** * Query whether horizontal alignment occurs at a point. *

* The text label class performs horizontal alignment at a point. The * text block and region have a nominal width. Horizontal alignment * occurs within this width. This method asks the stream what sort of * horizontal alignment it supports. * @return TRUE if the stream aligns horizontally at a point; FALSE if * it aligns horizontally within a nominal width. */ public boolean alignHPoint () { return minWidth().value() < 0; } /** * Query whether the stream has an unlimited width. *

* The text label can grow arbitrarily in X. A text region may have a * maximum width, or it may allow unlimited horizontal growth. This * method asks the object whether it has an unlimited width. * @return TRUE if the width is unlimited; FALSE if there is a limit on * the width. */ public boolean unlimitedWidth () { return maxWidth().value() < 0; } /** * Query whether the stream has an unlimited height. *

* The text label can grow arbitrarily in Y. A text region may have a * maximum height, or it may allow unlimited vertical growth. This * method asks the object whether it has an unlimited height. * @return TRUE if the height is unlimited; FALSE if there is a limit on * the height. */ public boolean unlimitedHeight () { return maxHeight().value() < 0; } /** * Query whether this frame is "dirty". *

* A frame is considered dirty if a layout operation changes any of its * lines. Any frame that contains a content change or any frame * thereafter whose lines change due to reflow will be considered dirty. * When a frame is initially loaded with layout through any of the * TextSparse stream call-backs, it starts out not being dirty. The * application can use this method to determine whether to write the * frame's content on save. * @return True if the frame is dirty; false if not. */ public boolean isDirty () { return mbIsDirty; } /** * Set the frame's dirty flag. * @param bDirty - New value for the frame's dirty flag. */ public void setDirty (boolean bDirty) { mbIsDirty = bDirty; } /** * Obtain the rectangle(s) in the laid-out text corresponding to the * given range in this frame. *

* A single range might yield multiple rectangles if it spans multiple * lines or there is bidirectional text. Note that the selection range * may span multiple frames. * @param oRange - Selection range. * @param oRectangles - Array to receive the rectangles. * @return True if any rectangles were found; false otherwise. This * method could return false if the range doesn't correspond to text in * this frame or the range is degenerate. */ // public boolean GetSelectionRectangles (TextRange oRange, Storage oRectangles) { // TextSelection oSelection; // oSelection = oRange; // oRectangles.setSize (0, false); // return GetSelectionRectangles (oSelection, UnitSpan.ZERO, oRectangles); // } /** * Render the frame contents, using the properties provided. *

* Given a set of rendering properties in an instance of class {@link * TextDrawInfo}, this method performs the appropriate rendering. * @param oDrawInfo - Rendering properties. For more information, * please see the description of {@link TextDrawInfo}. */ public void gfxDraw (TextDrawInfo oDrawInfo) { Rect oInvalid = oDrawInfo.getInvalid(); if (oInvalid.isDegenerate()) { UnitSpan oLarge = new UnitSpan (UnitSpan.INCHES_72K, 0xFFFFFF); UnitSpan oLargeNeg = new UnitSpan (UnitSpan.INCHES_72K, -0xFFFFFF); if (unlimitedWidth()) { oInvalid.leftRight (oLargeNeg, oLarge); } else { oInvalid.leftRight (UnitSpan.ZERO, maxWidth()); } if (unlimitedHeight()) { oInvalid.topBottom (oLargeNeg, oLarge); } else { oInvalid.topBottom (UnitSpan.ZERO, maxHeight()); } } DrawParm oParm = new DrawParm (oDrawInfo); oParm.setInvalid (oInvalid); gfxDraw (oParm, UnitSpan.ZERO); } /** * Render the frame's content. *

* This method is provided so that the application can render a single * frame's content in an application-controlled environment. The top * left corner of the frame is mapped to (0,0) in relative coordinates, * so the application may need to push an offset before calling this * method. * @param poGfxEnv - Graphic environment in which to do the rendering. * @param poInvalid - Pointer to invalidation rectangle (in frame * coordinates). If NULL, the frame uses its maximum width and height. * @param poSelection - Optional text selection. If non-null, this * represents a range and alternate colours for drawing of selected * text. Note that a single selection instance can be used across all * frames in the sparse stream. * @param eOpt - Run optimization flag. Enumeration values are in class * TextPrefOpt. OPT_UNKNOWN or OPT_CHAR produces the most accurate * behaviour, where each character is individually positioned. OPT_WORD * will result in the first character of each word being positioned, and * the graphic driver positioning the remaining characters based on the * character advances. OPT_LINE extends the word concept to entire * lines. Reducing the number of positioning operations performed by * the display improves display performance, but it may result in a loss * of accuracy when font sizes are rounded, depending on the abilities * of the underlying graphics environment. Note that AGM- and PDF-based * environments can use OPT_LINE for maximum performance without losing * accuracy. */ public void gfxDraw (GFXEnv poGfxEnv, Rect poInvalid, TextSelection poSelection, int eOpt) { TextDrawInfo oDrawInfo = new TextDrawInfo (poGfxEnv); if (poInvalid != null) { oDrawInfo.setInvalid (poInvalid); } oDrawInfo.setPrimary (poSelection); // oDrawInfo.setOpt (eOpt); gfxDraw (oDrawInfo); } public void gfxDraw (GFXEnv poGfxEnv, Rect poInvalid, TextSelection poSelection) { gfxDraw (poGfxEnv, poInvalid, poSelection, 0); } public void gfxDraw (GFXEnv poGfxEnv, Rect poInvalid) { gfxDraw (poGfxEnv, poInvalid, null, 0); } public void gfxDraw (GFXEnv poGfxEnv) { gfxDraw (poGfxEnv, null, null, 0); } /** * Generate a text layout object from this frame's layout. * @param bAllowCharGlyphs - True if glyph IDs can be replaced with * their corresponding Unicode character IDs where such corresponding * characters exist. False if all output glyphs are to be represented * by glyph IDs. * @return Text layout object with the layout of this frame. */ public TextLayout format (boolean bAllowCharGlyphs) { TextLayout poLayout = new TextLayout(); for (int i = 0; i < moLines.size(); i++) { getLine(i).compose (poLayout, bAllowCharGlyphs); } return poLayout; } /** * Return the frame's layout orientation. * @return The layout orientation in effect for this text frame. * Orienation may be horizontal, vertical RTL or vertical RTL. */ public int getLayoutOrientation () { return display().getLayoutOrientation(); } /** * Assignment operator. * @param oSource - Source frame to copy. */ public void copyFrom (TextFrame oSource) { meLayout = oSource.meLayout; mbIsDirty = oSource.mbIsDirty; } /** * Return the frame's minimum width. *

* All frames have both a minimum and maximum width, which may or may * not be the same. This method returns the minimum width. * @return Minimum width allowed for the frame. A value of zero is * possible, as is a value less than zero. In the latter case, it * indicates that the frame is horizontally aligned at a point, though * callers should use the AlignHPoint() method to test for this. */ abstract public UnitSpan minWidth (); /** * Return the frame's minimum height. *

* All frames have both a minimum and maximum height, which may or may * not be the same. This method returns the minimum height. * @return Minimum height allowed for the frame. A value of zero is * possible, as is a value less than zero. In the latter case, it * indicates that the frame is verrically aligned at a point, though * callers should use the AlignVPoint() method to test for this. */ abstract public UnitSpan minHeight (); /** * Return the frame's maximum width. *

* All frames have both a minimum and maximum width, which may or may * not be the same. This method returns the maximum width. * @return maximum width allowed for the frame. A value of zero is * possible, as is a value less than zero. In the latter case, it * indicates that the frame has unlimited width, though callers should * use the UnlimitedWidth() method to test for this. */ abstract public UnitSpan maxWidth (); /** * Return the frame's maximum height. *

* All frames have both a minimum and maximum height, which may or may * not be the same. This method returns the maximum height. * @return maximum height allowed for the frame. A value of zero is * possible, as is a value less than zero. In the latter case, it * indicates that the frame has unlimited height, though callers should * use the Unlimitedheight() method to test for this. */ abstract public UnitSpan maxHeight (); /** * Create a copy (deep clone) of this frame object. *

* The copy must have the same geometry as this object. It is up to * AXTE to subsequently manage the clones layout and relationship to * content. * @return Cloned copy of the frame. The lifetime of this object will * be managed with reference counting. */ abstract public TextFrame cloneFrame (); TextSparseStream getStream () { return mpoStream; } void setStream (TextSparseStream poStream) { mpoStream = poStream; } TextPosn getStart () { return moStart; } void setStart (TextPosnBase oStart) { moStart = new TextPosn (oStart); moStart.position (TextPosn.POSN_BEFORE); // Obscure: Each frame's position will advance for content insertions // only of those insertions strictly before the frame's position. An // insertion at the frame's start ends up being included in the frame's // content (which is normally the right thing). However, if the frame // before this one was empty and just got loaded with content, our start // position will not have advanced because it was not strictly after the // empty frame's start position. Class TextSparseStream detects this // condition and calls SetStart() to update our position. But we must // also update our first line's start position in such a case. if ((moLines != null) && (moLines.size() > 0)) { DispLineWrapped poLine = getLine (0); if (poLine.getPositionCount() > 0) { TextPosn oLineStart = poLine.getPosition(0).pp(); if ((moStart.stream() == oLineStart.stream()) && (moStart.index() >= oLineStart.index())) { oLineStart.copyFrom (moStart); oLineStart.tighten (true); } } } } TextDisplay display () { assert (mpoStream != null); assert (mpoStream.display() != null); return mpoStream.display(); } // TextGfxConnect TextConnect () { // return Display().textConnect(); // } UnitSpan getAMax () { return moAMax; } UnitSpan getBMax () { return moBMax; } Rect getExtent () { return moExtent; } void setExtent (Rect oExtent) { moAMax = oExtent.right(); moBMax = oExtent.bottom(); moExtent = ABXY.toXY (getXYOrigin(), oExtent, getLayoutOrientation()); } Rect runtimeExtent (boolean bExtended) { return xyFullExtent (bExtended); } CoordPair getXYOrigin () { return moXYOrigin; } // boolean GetSelectionRectangles (TextSelection poSelection, UnitSpan oOffset, Storage oRectangles) { // boolean bFound = false; // for (int i = 0; i < moLines.size(); i++) { // boolean bThisTime; // TextDispLineWrapped poLine = moLines[i]; // bThisTime = TextDispDrawAttr.getSelectionRectangles (poLine, poSelection, oYOffset, oRectangles); // if (bThisTime) { // bFound = true; // } else if (bFound) { // break; // } // } // // return bFound; // } int getActualCombCells () { return mnActualCombCells; } int getLayoutState () { return meLayout; } Rect preLayout (FormatInfo oFormatInfo) { Rect oOldExtent = Rect.ZERO; // Save the current extent, so that we can properly invalidate if it gets // smaller. if (moLines.size() > 0) { oOldExtent = abSubExtent (0, moLines.size(), meOldOrientation, true); } switch (oFormatInfo.getChange().type()) { case DispChange.CHANGE_NONE: case DispChange.CHANGE_INSERT: case DispChange.CHANGE_DELETE: case DispChange.CHANGE_OTHER: if (meLayout != LAYOUT_SUSPECT) { meLayout = LAYOUT_NORMAL; } mbIsDirty = true; break; case DispChange.CHANGE_FRAME: if (mpoStream.getFrame (oFormatInfo.getSuspectFrameIndex()) == this) { meLayout = LAYOUT_NORMAL; } break; default: meLayout = LAYOUT_NORMAL; mbIsDirty = true; } mnActualCombCells = combCells(); if ((mnActualCombCells > 0) || (oFormatInfo.getJustH() == TextAttr.JUST_H_COMB_LEFT) || (oFormatInfo.getJustH() == TextAttr.JUST_H_COMB_CENTRE) || (oFormatInfo.getJustH() == TextAttr.JUST_H_COMB_RIGHT)) { if (mnActualCombCells == 0) { mnActualCombCells = mpoStream.maxSize(); } if (mnActualCombCells == 0) { mnActualCombCells = 1; // fake at least one cell } } return oOldExtent; } void postLayout (FormatInfo oFormatInfo, Rect oOldExtent, boolean bIsJustifyOnly) { if (moLines.size() == 0) { return; // This frame about to be removed } // Justification starts here // First, compute the width of the text block. If there is a // justification width, it takes priority. Otherwise, use the greater of // the longest line width and the minimum width. This is the width in // which all (other) lines will be horizontally justified. Iterating // through the lines to examine their widths also gives us an opportunity // to determine the text height. UnitSpan oWidth = UnitSpan.ZERO; UnitSpan oLinesHeight = UnitSpan.ZERO; boolean bRestrictWidth = false; boolean bIsHorizontalLayout = false; if (isOrientationHorizontal()) { if (enforceAlignmentWidth()) { oWidth = alignmentWidth(); bRestrictWidth = true; } else if (! alignHPoint()) { oWidth = minWidth(); } bIsHorizontalLayout = true; } else { if (enforceAlignmentHeight()) { oWidth = alignmentHeight(); bRestrictWidth = true; } else if (! alignHPoint()) { oWidth = minHeight(); } bIsHorizontalLayout = false; } int nLines = bIsJustifyOnly ? moLines.size() : oFormatInfo.getNewSize(); for (int i = 0; i < nLines; i++) { DispLineWrapped poLine = getLine (i); UnitSpan oRawWidth = poLine.getRawWidth(); if ((! bRestrictWidth) && (oRawWidth.gt (oWidth))) { oWidth = oRawWidth; } oLinesHeight = oLinesHeight.add (poLine.getBExtent()); } if (! bRestrictWidth) { UnitSpan oMaxWidth = bIsHorizontalLayout ? maxWidth() : maxHeight(); if ((oMaxWidth.value() >= 0) && (oWidth.gt (oMaxWidth))) { oWidth = oMaxWidth; } } // Vertical justification starts here. UnitSpan oJustifyHeight = UnitSpan.ZERO; UnitSpan oOffsetY = UnitSpan.ZERO; // If vertically justified at a point, compute the amount to move up if // middle- or bottom-justified. if (alignVPoint()) { switch (oFormatInfo.getJustV()) { case TextAttr.JUST_V_MIDDLE: oOffsetY = oLinesHeight.divide (2); oOffsetY = new UnitSpan (oOffsetY.units(), -oOffsetY.value()); oJustifyHeight = oOffsetY; break; case TextAttr.JUST_V_BOTTOM: oOffsetY = new UnitSpan (oLinesHeight.units(), -oLinesHeight.value()); break; default: oJustifyHeight = oLinesHeight; break; } } // Vertical justification in a given height: compute the amount to move // down if middle- or bottom-justified. else { if (bIsHorizontalLayout) { oJustifyHeight = enforceAlignmentHeight() ? alignmentHeight() : minHeight(); } else { oJustifyHeight = enforceAlignmentWidth() ? alignmentWidth() : minWidth(); } UnitSpan oRoomLeft = oJustifyHeight.subtract (oLinesHeight); if (oRoomLeft.value() > 0) { switch (oFormatInfo.getJustV()) { case TextAttr.JUST_V_MIDDLE: oOffsetY = oLinesHeight.divide (2); break; case TextAttr.JUST_V_BOTTOM: oOffsetY = oRoomLeft; break; } } else { oJustifyHeight = oLinesHeight; } } UnitSpan oOriginX = bIsHorizontalLayout ? UnitSpan.ZERO : oJustifyHeight; moXYOrigin = new CoordPair (oOriginX, moXYOrigin.y()); // Now we can do the actual justification. Run through the lines and get // each to justify itself. Also set its final vertical position. int i; for (i = 0; i < nLines; i++) { DispLineWrapped poLine = getLine (i); if ((i >= oFormatInfo.getOldSize()) || (oFormatInfo.getOld (i) != null)) { poLine.justify (oWidth); // this line has been reformatted } CoordPair oLineOrigin = new CoordPair (UnitSpan.ZERO, oOffsetY); oLineOrigin = ABXY.toXY (moXYOrigin, oLineOrigin, getLayoutOrientation()); poLine.setXYOrigin (oLineOrigin); oOffsetY = poLine.getBMax(); } // Calculate the display extent for the owning stream. Rect oExtent = abSubExtent (0, nLines); // UnitSpan oAMin = oExtent.left(); // UnitSpan oBMin = getLine(0).getBMinExtended (false); // UnitSpan oAMax = oExtent.right(); // UnitSpan oBMax = getLine(nLines-1).getBMaxExtended (false); if (! adjustAndSetExtent (oLinesHeight, oExtent, oFormatInfo.getNewSize() > 1)) { oFormatInfo.setFits (false); } // boolean bExtentSet = false; // TODO: invalidation code removed // Set the stream's extent if we haven't done so already. // if (! bExtentSet) { // setExtent (oExtent); // TODO: now done in adjustAndSetExtent() // } // This frees any lines that have been replaced, as well as any at the // end of our array (if it got shorter). oFormatInfo.releaseOldLines(); // Update font subsetting information for each line. if (! oFormatInfo.isUpdate()) { for (i = 0; i < moLines.size(); i++) { getLine(i).updateSubsettedChars(); } } debugLines(); meOldOrientation = getLayoutOrientation(); moStart = getLine(0).getStartPosition(); } /* void InvalidateArea (Rect oInvalid, boolean bEraseBkgnd) { Display().invalidateArea (oInvalid, bEraseBkgnd, this); } */ /* void Justify (TextDispFormatInfo oFormatInfo) { Rect oOldExtent; PreLayout (oFormatInfo, oOldExtent); PostLayout (oFormatInfo, oOldExtent, true); } */ /* void ScrollTo (TextPosnBase oPosn, GFXEnv oGfxEnv) { TextConnect().scrollTo (oPosn, oGfxEnv); } */ /* void OnChange (boolean bExtentChanged) { TextConnect().onChange (bExtentChanged); } */ UnitSpan subHeight (int nStart, int nEnd) { int nMax = moLines.size(); if (nMax == 0) { return UnitSpan.ZERO; } int nSafeStart = nStart; if (nSafeStart >= nMax) { nSafeStart = nMax - 1; } int nSafeEnd = nEnd; if (nSafeEnd > nMax) { nSafeEnd = nMax; } if (nSafeEnd <= nSafeStart) { return UnitSpan.ZERO; } UnitSpan oStart = getLine(nSafeStart).getBMin(); UnitSpan oEnd = getLine(nSafeEnd-1).getBMax(); /* if (GetGfxEnv() != null) { oStart = GetGfxEnv().unitH (GetGfxEnv().devH (oStart)); oEnd = GetGfxEnv().unitH (GetGfxEnv().devH (oEnd)); } */ return oEnd.subtract (oStart); } UnitSpan lineMinY (int nIndex) { if (nIndex >= moLines.size()) { return UnitSpan.ZERO; } else { return getLine(nIndex).getXYOrigin().y(); } } void debugLines () { TextContext context = getContext(); if (context.debug()) { for (int i = 0; i < moLines.size(); i++) { getLine(i).textDebug (i); } } } TextContext getContext () { return mpoStream.getContext(); } /* GFXEnv GetGfxEnv () { return Display().getGfxEnv(); } */ /* TextFontMap GetFontMap () { return Display().getFontMap(); } */ DispMapSet getDisposableMaps () { return display().getDisposableMaps(); } public void releaseDisposableMaps (DispMapSet poMaps) { display().releaseDisposableMaps (poMaps); } /* AXTEWRSBase GetWRS () { return Display().getWRS(); } */ /* TextGlyphArray GetGlyphArray () { return Display().getGlyphArray(); } */ /* void SetLocale (TextAttr poAttr) { Display().setLocale (poAttr); } */ /* TextLocaleInfo GetLocale (String sLocaleName) { return Display().getLocale (sLocaleName); } */ /* TextBreakFinder GetBreakFinder () { return Display().getBreakFinder(); } */ boolean isOrientationHorizontal () { return getLayoutOrientation() == TextAttr.ORIENTATION_HORIZONTAL; } boolean isOrientationVertical () { return getLayoutOrientation() != TextAttr.ORIENTATION_HORIZONTAL; } boolean isRTL (TextAttr poAttr) { return display().isRTL (poAttr); } boolean isIdeographic (TextAttr poAttr) { return display().isIdeographic (poAttr); } /* boolean OptycaJustify (TextAttr poAttr) { return Display().optycaJustify (poAttr); } */ /* int GetDigits (TextAttr poAttr) { return Display().getDigits (poAttr); } */ /* bool GetBreakCandidates (int nCount) { return Display().getBreakCandidates (nCount); } */ DispLineWrapped allocateWrappedLine (LineDesc oLineDesc) { DispLineWrapped poLine = getContext().allocateWrappedLine (this, oLineDesc); poLine.setVerticalOrientation (getLayoutOrientation() != TextAttr.ORIENTATION_HORIZONTAL); return poLine; } void releaseWrappedLine (DispLineWrapped poLine) { getContext().releaseWrappedLine (poLine); } int getLegacyLevel () { return display().getLegacyLevel(); } public int getLineCount () { return moLines.size(); } DispLineWrapped getLine (int nIndex) { return (DispLineWrapped) moLines.get (nIndex); } Storage getLines () { return moLines; } boolean gfxDraw (DrawParm oParm, UnitSpan oOffset) { boolean bFit = true; GFXModelContext poContext = ((TextFrame) (this)); GFXDriver poDriver = oParm.env().driverAttach (poContext); oParm.setDriver (poDriver); CoordPair oFrameOrigin = new CoordPair (UnitSpan.ZERO, oOffset); oParm.driver().pushOffset (true, oFrameOrigin); try { oFrameOrigin = new CoordPair (getXYOrigin().x(), oFrameOrigin.y()); oParm.translate (oFrameOrigin, getLayoutOrientation()); for (int i = 0; i < moLines.size(); i++) { DispLineWrapped poLine = getLine (i); UnitSpan oBMin = poLine.getBMin(); UnitSpan oBMax = poLine.getBMax(); UnitSpan oBExtent = poLine.getBExtent(); if (oParm.truncate() != null) { if (oBMax.gt (oParm.truncateBMax())) { // Watson 1312011: Make sure it really overflows; not just round-off due // to Designer's incessant switching between awkward units. int oRound1 = UnitSpan.convertUnit (UnitSpan.POINTS_1K, oBMax.units(), oBMax.value()); int oRound2 = UnitSpan.convertUnit (UnitSpan.POINTS_1K, oParm.truncateBMax().units(), oParm.truncateBMax().value()); int nDiff = oRound1 - oRound2; if (nDiff > 1) { bFit = false; break; } } } boolean bInvalidHasHeight = (oParm.invalid().height().value() > 0); if (bInvalidHasHeight) { if (oBMin.gt (oParm.invalidBMax())) { break; // starts "below" invalid area // no need to continue } if (oBMin.equals (oParm.invalidBMax()) && oBExtent.gt (UnitSpan.ZERO)) { // starts at end of invalid area break; // no need to continue } } if (oBMax.gt (oParm.invalidBMin()) || (oBMax.equals (oParm.invalidBMin()) && (! bInvalidHasHeight))) { // see if there is any overlap and draw bFit = poLine.gfxDraw (oParm) && bFit; } } } finally { oParm.driver().popOffset(); oParm.env().driverDetach (poContext); } oParm.setDriver (null); return bFit; } boolean isInsertAtEnd (DispChange oChange, int nLine) { if (oChange.type() != DispChange.CHANGE_INSERT) { // Determine if the change is an insert at the end of a line. An // insertion at the end of a line (a fairly common case in typing) means // that we can start formatting on that line. Any other change might // cause part of the line's text to now fit on the previous line (e.g., // inserting a space in the first word or deleting text). return false; } DispLineWrapped poLine = getLine (nLine); if ((poLine.getStartBreak() == DispLine.LINE_BREAK_HYPHEN) || (poLine.getStartBreak() == DispLine.LINE_BREAK_HYPHEN_SUPPRESS)) { return false; // insertion may change hyphenation } TextPosnBase oResult = new TextPosnBase(); if (poLine.getCaretStartEnd (oChange.stream(), true, false, oResult) == DispLineWrapped.CARET_INVALID) { return false; } return oChange.index() >= oResult.index(); } public int combCells () { return 0; } boolean allowExtension () { return false; } boolean suppressWordWrap () { return false; } UnitSpan alignmentHeight () { return maxHeight(); } boolean enforceAlignmentHeight () { return false; } UnitSpan alignmentWidth () { return minWidth(); } boolean enforceAlignmentWidth () { return false; } boolean testFitSize () { return false; } boolean enforceDisplayExtent () { return false; } TextNullFrame isNullFrame () { return null; } protected void reflowFromHere () { if (mpoStream == null) { return; } TextDisplay poDisplay = mpoStream.display(); if (poDisplay == null) { return; } poDisplay.updateToEnd (moStart.stream(), moStart.index()); } // Adjusted stream's extent after formatting. private boolean adjustAndSetExtent (UnitSpan oHeight, Rect oABExtent, boolean bTestFit) { boolean bFit = true; // Override the calculated width if the stream has a fixed width. if ((! unlimitedWidth()) && (maxWidth().gt (oABExtent.width()))) { oABExtent = oABExtent.leftRight (UnitSpan.ZERO, maxWidth()); } if (! unlimitedHeight()) { // If there is a fixed height, override the calculated height if it is // smaller or the height must be enforced. boolean bForceExtent = enforceDisplayExtent(); if (oHeight.lte (maxHeight())) { bForceExtent = true; } else if (bTestFit && testFitSize()) { bFit = false; // should not be inserted } if (bForceExtent) { oABExtent = oABExtent.topBottom (UnitSpan.ZERO, maxHeight()); } } setExtent (oABExtent); return bFit; } // private Rect abFullExtent (boolean bExtended) { // return abSubExtent (0, moLines.size(), bExtended); // } private Rect abSubExtent (int nStart, int nEnd) { return abSubExtent (nStart, nEnd, getLayoutOrientation(), false); } // private Rect abSubExtent (int nStart, int nEnd, boolean bExtended) { // return abSubExtent (nStart, nEnd, getLayoutOrientation(), bExtended); // } private Rect abSubExtent (int nStart, int nEnd, int eOrientation, boolean bExtended) { return subExtent (true, nStart, nEnd, getLayoutOrientation(), bExtended); } private Rect xyFullExtent (boolean bExtended) { return xySubExtent (0, moLines.size(), bExtended); } // private Rect XYFullExtent () { // return xySubExtent (0, moLines.size(), false); // } private Rect xySubExtent (int nStart, int nEnd, boolean bExtended) { return xySubExtent (nStart, nEnd, getLayoutOrientation(), bExtended); } private Rect xySubExtent (int nStart, int nEnd, int eOrientation, boolean bExtended) { return subExtent (false, nStart, nEnd, getLayoutOrientation(), bExtended); } private Rect subExtent (boolean bAB, int nStart, int nEnd, int eOrientation, boolean bExtended) { UnitSpan oLeft = UnitSpan.ZERO; UnitSpan oTop = UnitSpan.ZERO; UnitSpan oRight = UnitSpan.ZERO; UnitSpan oBottom = UnitSpan.ZERO; for (int i = nStart; i < nEnd; i++) { DispLineWrapped poLine = getLine (i); if (poLine != null) { UnitSpan oAMin = poLine.getAMin(); UnitSpan oAMax = poLine.getAMax (bExtended); if (oLeft == null) { oTop = bExtended ? poLine.getBMinExtended (false) : poLine.getBMin(); oLeft = oAMin; oRight = oAMax; } else { if (oAMin.lt (oLeft)) { oLeft = oAMin; } if (oAMax.gt (oRight)) { oRight = oAMax; } } oBottom = bExtended ? poLine.getBMaxExtended (false): poLine.getBMax(); } } Rect result = new Rect (oLeft, oTop, oRight, oBottom); if (! bAB) { result = ABXY.toXY (getXYOrigin(), result, eOrientation); } return result; } //---------------------------------------------------------------------- // // clearLineArray: Delete all the non-NULL pointers in a // given line array. Note: this should be a template // function because the functionality is used elsewhere it // Text Services. Unfortunately, it doesn't with the Borland // compiler. // //---------------------------------------------------------------------- // private static void clearLineArray (List oLines) { // for (int i = 0; i < oLines.size(); i++) { // oLines.set (i, null); // } // } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy