com.adobe.xfa.text.DrawAttr Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aem-sdk-api Show documentation
Show all versions of aem-sdk-api Show documentation
The Adobe Experience Manager SDK
The newest version!
package com.adobe.xfa.text;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import com.adobe.xfa.font.FontItem;
import com.adobe.xfa.gfx.GFXColour;
import com.adobe.xfa.gfx.GFXDriver;
import com.adobe.xfa.gfx.GFXFillAttr;
import com.adobe.xfa.gfx.GFXGlyphOrientation;
import com.adobe.xfa.gfx.GFXLineAttr;
import com.adobe.xfa.gfx.GFXTextAttr;
import com.adobe.xfa.font.FontInstance;
import com.adobe.xfa.text.Decoration.DecorationKey;
import com.adobe.xfa.text.Decoration.DecorationValue;
import com.adobe.xfa.ut.CoordPair;
import com.adobe.xfa.ut.FindBugsSuppress;
import com.adobe.xfa.ut.Rect;
import com.adobe.xfa.ut.UnitSpan;
/**
* @exclude from published api.
*/
//----------------------------------------------------------------------
//
// DrawAttr - Class declaration
//
//----------------------------------------------------------------------
class DrawAttr {
/**
* @exclude from published api.
*/
static class ClipRect {
private final DrawParm moParm;
private boolean mbClipRectSet;
ClipRect (DrawParm oParm) {
moParm = oParm;
mbClipRectSet = false;
}
void detach () { // TODO: need explicit calls to detach clip rect
if (mbClipRectSet) {
moParm.driver().popClipRect();
mbClipRectSet = false;
}
}
void set (Rect oClipRect) {
if (mbClipRectSet) {
moParm.driver().popClipRect();
}
moParm.driver().pushClipRect (true, oClipRect);
mbClipRectSet = true;
}
}
private static class DrawData extends GFXTextAttr {
DispRun mRun;
TextAttr mTextAttr;
DrawData () {
}
DrawData (GFXTextAttr source) {
super (source);
}
public boolean equals(Object object) { // NOPMD - UselessOverridingMethod - here for documentation/FindBugs suppression
// The fields added in this derived class do not participate in equality
return super.equals(object);
}
public int hashCode() { // NOPMD - UselessOverridingMethod - here for documentation/FindBugs suppression
// The fields added in this derived class do not participate in equality
return super.hashCode();
}
}
private final DispLineWrapped mpoLine;
private final DrawParm moParm;
private final DrawSelection moSelection = new DrawSelection();
private final boolean mbInteractive;
private final boolean mbBreakOnGlyphs;
private UnitSpan moBaseline;
private TextAttr mpoAttr;
private final GFXTextAttr moGfxAttr = new GFXTextAttr();
private FontInstance moFontOverride;
private UnitSpan moCharSpacing = UnitSpan.ZERO;
private UnitSpan moWordSpacing = UnitSpan.ZERO;
private boolean mbCharSpacingChanged;
private boolean mbWordSpacingChanged;
private boolean mbRTL;
private final Decoration moUnderline;
private final Decoration moLineThrough;
private final Decoration moOverline;
private static final boolean mbIncludeSpaces = false;
private final SortedMap moDecorations = new TreeMap();
private GlyphLoc moGlyphLoc;
private int mnGlyphLocIndex;
private int mnClipIndex;
private int mnBackup;
private boolean mbBackupSet;
private int mnPrevCharIndex;
private Rect moClipRect;
private boolean mbClipRectSet;
private int meGlyphOrientation;
DrawAttr (DispLineWrapped poLine, DrawParm oParm) {
mpoLine = poLine;
moParm = oParm;
moUnderline = Decoration.createUnderline (poLine, oParm);
moLineThrough = Decoration.createLineThrough (poLine, oParm);
moOverline = Decoration.createOverline (poLine, oParm);
mnPrevCharIndex = poLine.getCharCount(); // an impossible index
mbClipRectSet = false;
meGlyphOrientation = GFXGlyphOrientation.HORIZONTAL;
mbInteractive = moParm.env().interactive();
mbBreakOnGlyphs = moParm.driver().getMappingLevel() == GFXDriver.MAPPING_LEGACY;
}
TextAttr getAttr () {
return mpoAttr;
}
FontInstance getWorkingFont () {
return (moFontOverride == null) ? mpoAttr.fontInstance() : moFontOverride;
}
FontInstance getFontOverride () {
return moFontOverride;
}
GFXTextAttr getGfxAttr () {
return moGfxAttr;
}
void drawBackground () {
TextSelection poPrimary = moParm.primary();
TextSelection poSecondary = moParm.secondary();
if ((poPrimary != null) && poPrimary.isEmpty()) {
poPrimary = null;
}
if ((poSecondary != null) && poSecondary.isEmpty()) {
poSecondary = null;
}
if ((mpoLine.hasSingleColour()) && (poPrimary == null) && (poSecondary == null)) {
GFXColour oFG;
GFXColour oBG;
boolean bTransparent;
TextAttr poAttr = mpoLine.getStartAttr();
if (poAttr == null) {
oFG = GFXColour.black();
oBG = GFXColour.white();
bTransparent = false;
} else {
oFG = poAttr.colour();
oBG = poAttr.colourBg();
bTransparent = poAttr.transparent();
}
moSelection.addClip (Units.toFloat (mpoLine.getAMin()), Units.toFloat (mpoLine.getAMin().add (mpoLine.getAExtent())), oFG, oBG, bTransparent);
}
else {
mpoLine.preAllocOffsets();
}
int i;
for (i = 0; i < mpoLine.getGlyphCount(); i++) {
processBackgroundGlyph (i, poPrimary, poSecondary);
}
if (moParm.driver() != null) {
for (i = 0; i < moSelection.getClipCount(); i++) {
DrawSelection.Clip oClip = moSelection.getClip (i);
if (! oClip.mbTransparent) {
float oStart = oClip.moLeft;
if (oStart < moParm.invalidAMin()) {
oStart = moParm.invalidAMin();
}
float oEnd = oClip.moRight;
if (oEnd > moParm.invalidAMax()) {
oEnd = moParm.invalidAMax();
}
if (oStart < oEnd) {
GFXFillAttr oFillAttr = new GFXFillAttr();
oFillAttr.colour (oClip.moBG);
oFillAttr.colourBg (oClip.moBG);
moParm.driver().fillAttr (oFillAttr);
Rect oFillRect = new Rect (Units.toUnitSpan (oStart), mpoLine.getBMinExtended (true), Units.toUnitSpan (oEnd), mpoLine.getBMaxExtended (true));
oFillRect = ABXY.toXY (mpoLine.getXYOrigin(), oFillRect, mpoLine.frame().getLayoutOrientation());
moParm.driver().relFillRect (oFillRect);
}
}
}
}
}
@FindBugsSuppress(code="NP") // false positive? - oFontInstance
boolean prepareGlyph (RenderInfo oRenderInfo) {
oRenderInfo.mpoGlyphLoc = null;
for (boolean bRetry = true; bRetry; ) {
oRenderInfo.mnGlyphID = 0;
oRenderInfo.mcGlyph = '\0';
oRenderInfo.mbFlushBefore = false;
oRenderInfo.mbFlushAfter = false;
oRenderInfo.mbShifted = false;
oRenderInfo.mpoGlyphLoc = getGlyphLoc (mnGlyphLocIndex);
if (oRenderInfo.mpoGlyphLoc == null) {
if (mbInteractive) {
oRenderInfo.mpoGlyphLoc = nextSelection();
}
if (oRenderInfo.mpoGlyphLoc == null) {
return false;
}
oRenderInfo.mbFlushBefore = true;
oRenderInfo.mbShifted = true;
}
DrawSelection.Clip oClip = new DrawSelection.Clip();
DrawSelection.Clip poOverride = null;
if (mbInteractive) {
if (moSelection.getClipCount() == 0) {
oClip.moFG = GFXColour.black();
oClip.moBG = GFXColour.white();
}
else if (moSelection.getClipCount() == 1) {
oClip = moSelection.getClip (0);
}
else if (moSelection.getClipCount() > 1) {
GlyphLoc poOldGlyphLoc = oRenderInfo.mpoGlyphLoc;
float[] extents = getGlyphExtents (oRenderInfo.mpoGlyphLoc);
if ((mnClipIndex < moSelection.getClipCount()) && (extents[0] >= moSelection.getClip (mnClipIndex).moRight)) {
oRenderInfo.mpoGlyphLoc = nextSelection();
if (oRenderInfo.mpoGlyphLoc == null) {
return false;
}
oRenderInfo.mbFlushBefore = true;
oRenderInfo.mbShifted = true;
}
oClip = moSelection.getClip (mnClipIndex);
if (! mbBackupSet) {
if (oRenderInfo.mpoGlyphLoc != poOldGlyphLoc) {
extents = getGlyphExtents (oRenderInfo.mpoGlyphLoc);
}
if (extents[1] > oClip.moRight) {
mnBackup = mnGlyphLocIndex;
mbBackupSet = true;
}
}
}
poOverride = oClip;
}
mnGlyphLocIndex++;
DrawData data = initDrawAttr (oRenderInfo.mpoGlyphLoc);
int nCharIndex = oRenderInfo.mpoGlyphLoc.getMapIndex();
oRenderInfo.mcGlyph = mpoLine.getChar (nCharIndex);
// Unicode direction control characters appear in the glyph array created
// by WinSoft; don't attempt to draw them.
if ((oRenderInfo.mcGlyph < 0x202A) || (oRenderInfo.mcGlyph > 0x202E)) {
if (nCharIndex == mnPrevCharIndex) {
// Multiple glyphs from the same character: force run break so that
// Acrobat can map properly. TBD: revisit when acrobat uses new mapping
oRenderInfo.mbFlushBefore = true;
oRenderInfo.mbFlushAfter = true;
}
mnPrevCharIndex = nCharIndex;
if (poOverride != null) {
data.colour (poOverride.moFG);
data.colourBg (poOverride.moBG);
}
Glyph oGlyph = mpoLine.getGlyph (oRenderInfo.mpoGlyphLoc.getGlyphIndex());
// Pick up any TextAttr based attributes if the attribute pointer is
// non-null.
FontInstance oFontInstance = null;
UnitSpan oNewBaseline = moParm.offsetText();
UnitSpan oNewCharSpacing = UnitSpan.ZERO;
UnitSpan oNewWordSpacing = UnitSpan.ZERO;
mbCharSpacingChanged = false;
mbWordSpacingChanged = false;
if (data.mTextAttr != null) {
oFontInstance = data.mTextAttr.fontInstance();
if ((! mpoLine.isLayoutLine()) && data.mTextAttr.baselineShiftEnable() && (! data.mTextAttr.baselineShift().isNeutral())) {
oNewBaseline = data.mTextAttr.baselineShift().applyShift (oNewBaseline, moParm.shiftSize());
}
if (data.mTextAttr.charSpacingEnable()) {
oNewCharSpacing = data.mTextAttr.charSpacing().getLength();
}
if (data.mTextAttr.wordSpacingEnable()) {
oNewWordSpacing = data.mTextAttr.wordSpacing().getLength();
}
}
// Baseline change: must flush before
if (! UnitSpan.match (oNewBaseline, moBaseline)) {
moBaseline = oNewBaseline;
oRenderInfo.mbFlushBefore = true;
oRenderInfo.mbShifted = true;
}
// Character or word spacing change: if the driver handles these, a
// change must be treated as an attribute change. Don't worry about run
// breaks here; that happens in the TextDrawRun class.
if (! UnitSpan.match (oNewCharSpacing, moCharSpacing)) {
moCharSpacing = oNewCharSpacing;
mbCharSpacingChanged = true;
if (moParm.driver().charSpacingSupported()) {
oRenderInfo.mbAttrChange = true;
oRenderInfo.mbFlushBefore = true;
oRenderInfo.mbShifted = true;
}
}
if (! UnitSpan.match (oNewWordSpacing, moWordSpacing)) {
moWordSpacing = oNewWordSpacing;
mbWordSpacingChanged = true;
if (moParm.driver().wordSpacingSupported()) {
oRenderInfo.mbAttrChange = true;
oRenderInfo.mbFlushBefore = true;
oRenderInfo.mbShifted = true;
}
}
// Must break runs on direction change.
boolean bRTL = oGlyph.isRTL();
if (bRTL != mbRTL) {
oRenderInfo.mbFlushBefore = true;
mbRTL = bRTL;
}
// Check for any other attribute change.
int eGlyphOrientation = oGlyph.getOrientation();
if ((mpoAttr == null)
|| ((oFontInstance != mpoAttr.fontInstance()) && (oFontInstance != null))
|| ((data.mTextAttr != null) && (data.mTextAttr.transparent() != mpoAttr.transparent()))
|| (! moGfxAttr.equals (data))
|| (meGlyphOrientation != eGlyphOrientation)) {
mpoAttr = data.mTextAttr;
moGfxAttr.copyFrom (data);
meGlyphOrientation = eGlyphOrientation;
oRenderInfo.mbAttrChange = true;
oRenderInfo.mbFlushBefore = true;
}
// Pick up the character for rendering.
// TODO: FindBugs reports possible null pointer dereference of oFontInstance here
FontItem poFontItem = oFontInstance.getFontItem();
mpoLine.getRenderChar (data.mTextAttr, oFontInstance, oRenderInfo.mpoGlyphLoc, oGlyph, oRenderInfo, poFontItem);
if (mbBreakOnGlyphs) {
if (bRTL || (oRenderInfo.mcGlyph == '\0')) {
oRenderInfo.mbFlushBefore = true;
oRenderInfo.mbFlushAfter = true;
}
}
// Watson 1260903: Work-around for font service restrictions. With some
// output targets, glyph-only output must be done with Unicode fonts
// only. The line signals this by changing the font item pointer to one
// for a Unicode font. When the font item is overridden in this way,
// there must be a corresponding font instance override to use at render
// time.
// If the font item hasn't changed from the one in the font instance,
// clear any override that might be in effect.
if ((poFontItem == oFontInstance.getFontItem()) || (mpoAttr == null)) {
if (moFontOverride != null) {
moFontOverride = null;
oRenderInfo.mbAttrChange = true;
oRenderInfo.mbFlushBefore = true;
}
}
// If the font item has changed, the glyph will have to be rendered with
// an override. This override may already be in effect, so try to limit
// run breaks in such a case.
else {
FontInstance oOverride = poFontItem.reconcile (mpoAttr.size());
if (oOverride != moFontOverride) {
moFontOverride = oOverride;
oRenderInfo.mbAttrChange = true;
oRenderInfo.mbFlushBefore = true;
}
}
bRetry = false;
}
}
return oRenderInfo.mpoGlyphLoc != null;
}
UnitSpan getBaseline () {
return moBaseline;
}
boolean assertAttrs (ClipRect oClipRect) {
GFXDriver poDriver = moParm.driver();
poDriver.textAttr (moGfxAttr);
poDriver.glyphOrientation (meGlyphOrientation); // before font change
if (mpoAttr != null) {
poDriver.fontInstance (getWorkingFont());
poDriver.mode (mpoAttr.transparent() ? GFXDriver.MODE_TRANSPARENT : GFXDriver.MODE_OPAQUE);
if (mbCharSpacingChanged) {
poDriver.charSpacing (moCharSpacing);
}
if (mbWordSpacingChanged) {
poDriver.wordSpacing (moWordSpacing);
}
}
if (mbClipRectSet) {
if (moClipRect.isDegenerate()) {
return false;
}
oClipRect.set (moClipRect);
}
return true;
}
void flush () {
if (mpoLine.hasDecoration()) {
moUnderline.complete (moParm, moDecorations, mbIncludeSpaces);
moLineThrough.complete (moParm, moDecorations, mbIncludeSpaces);
moOverline.complete (moParm, moDecorations, mbIncludeSpaces);
Decoration.DecorationKey keys[] = new Decoration.DecorationKey[moDecorations.size()];
int i = 0;
for (Decoration.DecorationKey key : moDecorations.keySet())
keys[i++] = key;
int nDecorationStart = 0;
for (int nClip = 0; nClip < moSelection.getClipCount(); nClip++) {
DrawSelection.Clip oClip = moSelection.getClip (nClip);
for (; ; ) {
if ((nDecorationStart >= moDecorations.size())
|| (keys[nDecorationStart].moXEnd > oClip.moLeft)) {
break;
}
nDecorationStart++;
}
if (nDecorationStart >= moDecorations.size()) {
break;
}
for (int j = nDecorationStart; j < moDecorations.size(); j++) {
Decoration.DecorationKey oKey = keys[j];
if (oKey.moXStart >= oClip.moRight) {
break;
}
Decoration.DecorationValue oValue = moDecorations.get (oKey);
float oLeft = oClip.moLeft;
if (oKey.moXStart > oLeft) {
oLeft = oKey.moXStart;
}
float oRight = oClip.moRight;
if (oKey.moXEnd < oRight) {
oRight = oKey.moXEnd;
}
GFXLineAttr oLineAttr = new GFXLineAttr();
oLineAttr.colour (oClip.moFG);
oLineAttr.colourBg (oClip.moBG);
oLineAttr.width (oValue.moWidth);
CoordPair oP1 = new CoordPair (Units.toUnitSpan (oLeft), oValue.moYOffset);
CoordPair oP2 = new CoordPair (Units.toUnitSpan (oRight), oValue.moYOffset);
moParm.driver().lineAttr (oLineAttr);
oP1 = ABXY.toXY (mpoLine.getXYOrigin(), oP1, mpoLine.frame().getLayoutOrientation());
oP2 = ABXY.toXY (mpoLine.getXYOrigin(), oP2, mpoLine.frame().getLayoutOrientation());
moParm.driver().relLine (oP1, oP2);
}
}
}
}
void reset (DrawAttr oSource) {
mpoAttr = oSource.mpoAttr;
moGfxAttr.copyFrom (oSource.moGfxAttr);
moFontOverride = oSource.moFontOverride;
moCharSpacing = oSource.moCharSpacing;
mbCharSpacingChanged = oSource.mbCharSpacingChanged;
moWordSpacing = oSource.moWordSpacing;
mbWordSpacingChanged = oSource.mbWordSpacingChanged;
moClipRect = oSource.moClipRect;
mbClipRectSet = oSource.mbClipRectSet;
meGlyphOrientation = oSource.meGlyphOrientation;
}
static boolean getSelectionRectangles (DispLineWrapped poLine, TextSelection poSelection, UnitSpan oYOffset, List oRectangles) {
TextStream poStream = poSelection.stream();
int nPositions = poLine.getPositionCount();
boolean bFound = false;
int nSelectionStart = poSelection.start().index();
int nSelectionEnd = poSelection.end().index();
int i;
for (i = 0; i < nPositions; i++) {
DispPosn oPosition = poLine.getPosition (i);
if ((oPosition.pp().stream() == poStream) && (nSelectionStart < oPosition.pp().index() + oPosition.getMapLength()) && (nSelectionEnd > oPosition.pp().index())) {
bFound = true;
break;
}
}
if (! bFound) {
return false;
}
DrawSelection oSelectionInfo = new DrawSelection();
for (i = 0; i < poLine.getGlyphCount(); i++) {
processBackgroundGlyph (poLine, poLine.getGlyph (i), poLine.getOrderedGlyphLoc (i), poSelection, null, GFXColour.black(), GFXColour.white(), false, oSelectionInfo);
}
bFound = false;
for (i = 0; i < oSelectionInfo.getClipCount(); i++) {
DrawSelection.Clip oClip = oSelectionInfo.getClip (i);
if ((oClip.moFG != GFXColour.black()) && (oClip.moBG != GFXColour.white())) {
Rect oArea = new Rect (Units.toUnitSpan (oClip.moLeft),
oYOffset,
Units.toUnitSpan (oClip.moRight),
poLine.getBExtent().add (oYOffset));
oArea = ABXY.toXY (poLine.getXYOrigin(), oArea, poLine.frame().getLayoutOrientation());
oRectangles.add (oArea);
bFound = true;
}
}
return bFound;
}
private void processBackgroundGlyph (int nGlyphIndex, TextSelection poPrimary, TextSelection poSecondary) {
Glyph oGlyph = mpoLine.getGlyph (nGlyphIndex);
GlyphLoc oGlyphLoc = mpoLine.getOrderedGlyphLoc (nGlyphIndex);
DrawData data = initDrawAttr (oGlyphLoc);
boolean bAnySelection = (poPrimary != null) || (poSecondary != null);
if ((! mpoLine.hasSingleColour()) || bAnySelection) {
processBackgroundGlyph (mpoLine, oGlyph, oGlyphLoc, poPrimary, poSecondary, data.mTextAttr.colour(), data.mTextAttr.colourBg(), /* (data.mTextAttr == null) ? false : */ data.mTextAttr.transparent(), moSelection);
}
if (mpoLine.hasDecoration()) {
if ((oGlyphLoc.getMapLength() > 1) || mpoLine.isVisualChar (oGlyphLoc.getMapIndex())) {
FontInstance poFontInstance = null;
FontInstance poOldFontInstance = null;
if (mpoAttr != null) {
poOldFontInstance = mpoAttr.fontInstance();
}
if (data.mTextAttr != null) {
poFontInstance = data.mTextAttr.fontInstance();
}
if (poFontInstance != poOldFontInstance) {
if ((poOldFontInstance == null)
|| (poFontInstance == null)
|| (poFontInstance != poOldFontInstance)) {
moUnderline.fontChange (moParm, moDecorations);
moLineThrough.fontChange (moParm, moDecorations);
moOverline.fontChange (moParm, moDecorations);
mpoAttr = data.mTextAttr;
}
}
int nFlags = 0;
if (GFXGlyphOrientation.usesVerticalGlyphs (data.mRun.glyphOrientation())) {
nFlags |= Decoration.DECORATION_VERTICAL;
}
if ((oGlyphLoc.getMapLength() == 1)
&& (mpoLine.getBreakClass (oGlyphLoc.getMapIndex()) == TextCharProp.BREAK_SP)) {
nFlags |= Decoration.DECORATION_SPACE;
}
float oLeft = oGlyph.getDrawX (mpoLine) + mpoLine.getAMinFloat();
float oRight = oGlyph.getDrawNextX (mpoLine) + mpoLine.getAMinFloat();
// If there is a truncation rectangle, and this glyph extends beyond it,
// turn off the decoration line.
if (moParm.truncate() != null) {
if (oLeft < moParm.truncateAMin()) { // extends beyond the left margin
nFlags |= Decoration.DECORATION_SUPPRESS;
} else {
float oOverflow = oRight - moParm.truncateAMax();
if (oOverflow > 0) {
if ((oGlyph.isRTL())
|| ((oGlyphLoc.getMapIndex() + 1) != mpoLine.getVisualCharCount())
|| (oOverflow > 0.5f)) {
nFlags |= Decoration.DECORATION_SUPPRESS;
}
}
}
} else if ((oLeft > moParm.invalidAMax()) || (oRight < moParm.invalidAMin())) {
nFlags |= Decoration.DECORATION_SUPPRESS;
}
moUnderline.update (moParm, data.mTextAttr, oLeft, oRight, nFlags, moDecorations);
moLineThrough.update (moParm, data.mTextAttr, oLeft, oRight, nFlags, moDecorations);
moOverline.update (moParm, data.mTextAttr, oLeft, oRight, nFlags, moDecorations);
}
}
}
private static void processBackgroundGlyph (DispLineWrapped poLine, Glyph oGlyph, GlyphLoc oGlyphLoc, TextSelection poPrimary, TextSelection poSecondary, GFXColour oFG, GFXColour oBG, boolean bTransparent, DrawSelection oSelection) {
int nBaseIndex = oGlyphLoc.getMapIndex();
boolean bAnySelection = (poPrimary != null) || (poSecondary != null);
DispLine.PosnInfo posnInfo = new DispLine.PosnInfo();
for (int i = 0; i < oGlyphLoc.getMapLength(); i++) {
int nCharIndex;
if (oGlyph.isRTL()) {
nCharIndex = nBaseIndex + oGlyphLoc.getMapLength() - 1 - i;
} else {
nCharIndex = nBaseIndex + i;
}
int nPositionIndex = poLine.getPositionMap().findItem (nCharIndex);
assert (poLine.getPositionMap().isValidMapIndex (nPositionIndex));
DispPosn oPosition = poLine.getPosition (nPositionIndex);
TextStream poSelStream = oPosition.pp().stream();
DispLine.charToStreamInfo (oPosition, nCharIndex, posnInfo);
for (int nSel = 0; nSel < posnInfo.auxInfo; nSel++) {
TextSelection poSelection = null;
TextStream poStream = poSelStream;
int nStreamIndex = posnInfo.index + nSel;
if (bAnySelection) {
while (poStream != null) {
if (poPrimary != null) {
if ((poPrimary.stream() == poStream) && (nStreamIndex >= poPrimary.start().index()) && (nStreamIndex < poPrimary.end().index())) {
poSelection = poPrimary;
break;
}
}
if (poSecondary != null) {
if ((poSecondary.stream() == poStream) && (nStreamIndex >= poSecondary.start().index()) && (nStreamIndex < poSecondary.end().index())) {
poSelection = poSecondary;
break;
}
}
TextPosn poParentPosition = poStream.position();
if (poParentPosition == null) {
poStream = null;
} else {
poStream = poParentPosition.stream();
nStreamIndex = poParentPosition.index();
}
}
}
DispLineWrapped.CharRange oRange = poLine.getCharExtent (nPositionIndex, nCharIndex, nSel);
if (poSelection != null) {
oSelection.addClip (oRange.moMinX, oRange.moMaxX, poSelection.colour(), poSelection.colourBg(), false);
} else {
oSelection.addClip (oRange.moMinX, oRange.moMaxX, oFG, oBG, bTransparent);
}
}
}
}
private DrawData initDrawAttr (GlyphLoc oGlyphLoc) {
int nCharIndex = oGlyphLoc.getMapIndex();
DispRun run = mpoLine.getMappedRun (nCharIndex);
TextAttr textAttr = run.getAttr();
DrawData data;
if (textAttr == null) {
data = new DrawData();
} else {
data = new DrawData (textAttr.gfxTextAttr());
}
data.mRun = run;
data.mTextAttr = textAttr;
return data;
}
private GlyphLoc nextSelection () {
mnClipIndex++;
if (mnClipIndex >= moSelection.getClipCount()) {
return null;
}
if (mbBackupSet) {
mnGlyphLocIndex = mnBackup;
mbBackupSet = false;
}
setClipRect();
return getGlyphLoc (mnGlyphLocIndex);
}
private GlyphLoc getGlyphLoc (int nGlyphLocIndex) {
if (nGlyphLocIndex < mpoLine.getGlyphCount()) {
moGlyphLoc = mpoLine.getOrderedGlyphLoc (nGlyphLocIndex);
return moGlyphLoc;
}
return null;
}
private void setClipRect () {
DrawSelection.Clip oClip = moSelection.getClip (mnClipIndex);
// UnitSpan oRight = Units.toUnitSpan (oClip.moRight);
// Watson 1102681: Any glyph may draw outside its computed clip area, and
// will be picked up by the next clip area. However, the there is no
// next clip area for the right-most one, so extend its right side to the
// stream extent.
// JavaPort: This code has no effect - is this another bug in the C++?
// if ((mnClipIndex + 1) >= moSelection.getClipCount()) {
// UnitSpan oMaxRight = mpoLine.frame().getExtent().right();
// if (oRight.lt (oMaxRight)) {
// oRight = oMaxRight;
// }
// }
moClipRect = new Rect (Units.toUnitSpan (oClip.moLeft),
mpoLine.getBMinExtended (true),
Units.toUnitSpan (oClip.moRight),
mpoLine.getBMaxExtended (true));
moClipRect = ABXY.toXY (mpoLine.getXYOrigin(), moClipRect, mpoLine.frame().getLayoutOrientation());
mbClipRectSet = true;
}
private float[] getGlyphExtents (GlyphLoc poGlyphLoc) {
int nGlyphIndex = poGlyphLoc.getGlyphIndex();
Glyph oGlyph = mpoLine.getGlyph (nGlyphIndex);
DispRect oExtent = mpoLine.getABGlyphBBox (nGlyphIndex, true);
float oXOffset = oGlyph.getDrawX (mpoLine) + mpoLine.getAMinFloat();
oExtent.xMin += oXOffset;
oExtent.xMax += oXOffset;
float oLeft = oGlyph.getDrawX (mpoLine) + mpoLine.getAMinFloat();
if (oLeft > oExtent.xMin) {
oLeft = oExtent.xMin;
}
float oRight = oGlyph.getDrawNextX (mpoLine) + mpoLine.getAMinFloat();
if (oRight < oExtent.xMax) {
oRight = oExtent.xMax;
}
float[] result = new float [2];
result[0] = oLeft;
result[1] = oRight;
return result;
}
}