com.adobe.xfa.text.DrawRun 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 com.adobe.xfa.font.FontInstance;
import com.adobe.xfa.gfx.GFXDriver;
import com.adobe.xfa.gfx.GFXMappingList;
import com.adobe.xfa.ut.CoordPair;
import com.adobe.xfa.ut.UniCharIterator;
/**
* @exclude from published api.
*/
class DrawRun {
private final DispLineWrapped mpoLine; // owning displey line
private final DrawParm moParm; // draw parameters
private final DrawAttr moAttr; // run attributes
private boolean mbAttrChange; // is there an attribute change before this run?
private final DrawAttr.ClipRect moClipRect; // clip rectangle
private final StringBuilder msChar = new StringBuilder(); // character data run
private int mnRunStart; // start of run in line's character data
private int mnRunLength; // length of run in line's character data
private int mnGlyphCount; // number of accumulated glyphs
private boolean mbGlyphMode; // is this run in glyph mode?
private boolean mbIsRTL; // are these RTL glyphs?
private final GFXMappingList moMappingList; // accumulated mappings for this run
private final int meMappingType; // type of mapping required by driver
private float moX; // run start position X
private float moY; // run start position Y
private float moPrevX; // previous position X
private float moPrevY; // previous position Y
private boolean mbUnknownWidth; // last glyph has unknown width?
private float moCharSpacing; // current char spacing
private final boolean mbCharSpacingSupported; // driver supports char spacing?
private float moWordSpacing; // current word spacing
private final boolean mbWordSpacingSupported; // driver supports word spacing?
private final MultiMapper moMultiple = new MultiMapper(); // for mapping 1 char to multiple glyphs
DrawRun (DispLineWrapped poLine, DrawParm oParm) {
mpoLine = poLine;
moParm = oParm;
moAttr = new DrawAttr (poLine, oParm);
mbAttrChange = true; // force out first attr encountered
moClipRect = new DrawAttr.ClipRect (oParm);
// mnRunStart = 0;
// mnRunLength = 0;
// mnGlyphCount = 0;
// mbGlyphMode = false;
// mbIsRTL = false;
moMappingList = poLine.display().getContext().getMappingList();
meMappingType = oParm.driver().getMappingLevel();
// mbUnknownWidth = false;
mbCharSpacingSupported = oParm.driver().charSpacingSupported();
mbWordSpacingSupported = oParm.driver().wordSpacingSupported();
if (meMappingType == GFXDriver.MAPPING_FULL) {
moMappingList.reset();
}
}
void addGlyph (DrawAttr oCurrentAttr,
RenderInfo oRenderInfo,
float oX,
float oY,
boolean bIsRTL) {
boolean bNewGlyphMode = oRenderInfo.mcGlyph == '\0';
if (bNewGlyphMode != mbGlyphMode) {
flush();
mbGlyphMode = bNewGlyphMode;
}
setupRun (oCurrentAttr, oRenderInfo, oX, oY, bIsRTL);
int nRunStart = oRenderInfo.mpoGlyphLoc.getMapIndex();
int nRunLength = oRenderInfo.mpoGlyphLoc.getMapLength();
if (mpoLine.hasAXTEMappings())
{
int nAdjustedRunStart = nRunStart;
int nPosnIndex = 0;
DispPosn poPosition = null;
for (; nPosnIndex < mpoLine.getPositionCount(); nPosnIndex++) {
DispPosn oPosition = mpoLine.getPosition (nPosnIndex);
if (oPosition.getMapIndex() + oPosition.getMapLength() > nRunStart) {
poPosition = oPosition;
break;
}
nAdjustedRunStart += DispLine.getPositionStreamCount (oPosition);
nAdjustedRunStart -= oPosition.getMapLength();
}
assert (poPosition != null);
nRunStart = nAdjustedRunStart;
switch (DispLine.getPositionType (poPosition)) {
case DispLine.POSN_TYPE_LIGATURE:
assert (poPosition.getMapLength() == 1);
nRunLength = DispLine.getPositionStreamCount (poPosition);
break;
case DispLine.POSN_TYPE_MULTIPLE:
nRunStart -= oRenderInfo.mpoGlyphLoc.getMapIndex() - poPosition.getMapIndex();
nRunLength = 1;
break;
}
}
if (mbGlyphMode) {
int[] oGlyphArray = mpoLine.display().getContext().getGlyphArray (mnGlyphCount + 1);
oGlyphArray[mnGlyphCount] = oRenderInfo.mnGlyphID;
// Watson 1023477: Cannot simply add the number of characters covered by
// this glyph, because some characters create multiple glyphs causing the
// character to be double-counted. Instead, compute the length from the
// character(s) covered by this glyph. TBD: can remove this and collaps
// mnRunLength into mnGlyphCount once Acrobat stops using legacy mapping.
if (mnRunLength == 0) {
mnRunStart = nRunStart;
mnRunLength = nRunLength;
} else {
int nGlyphStart = nRunStart;
int nGlyphMax = nGlyphStart + nRunLength;
int nRunMax = mnRunStart + mnRunLength;
if (nGlyphStart < mnRunStart) {
mnRunStart = nGlyphStart;
}
if (nGlyphMax > nRunMax) {
nRunMax = nGlyphMax;
}
mnRunLength = nRunMax - mnRunStart;
}
accumulateMapping (nRunStart, mnGlyphCount, nRunLength);
updatePosition (oRenderInfo.mpoGlyphLoc, oX, oY, oRenderInfo.mnGlyphID, true);
}
else {
msChar.append ((char) oRenderInfo.mcGlyph);
updatePosition (oRenderInfo.mpoGlyphLoc, oX, oY, oRenderInfo.mnGlyphID, false);
// updatePosition (oRenderInfo.mpoGlyphLoc, oX, oY, oRenderInfo.mcGlyph, false);
accumulateMapping (nRunStart, mnGlyphCount);
mnRunLength++;
}
mnGlyphCount++;
}
void flush () {
if (mnGlyphCount > 0) {
StringBuilder debugMsg = null;
TextContext context = mpoLine.display().getContext();
if (context.debug()) {
debugMsg = new StringBuilder();
}
if (mbGlyphMode) {
int[] oGlyphArray = context.getGlyphArray();
if (flushCommon (debugMsg)) {
if (debugMsg != null) {
debugMsg.append (" Glyphs:");
for (int i = 0; i < mnGlyphCount; i++) {
debugMsg.append (' ');
debugMsg.append (Integer.toString (oGlyphArray[i]));
}
context.debug (debugMsg.toString());
}
moParm.driver().relGlyphs (oGlyphArray, mnGlyphCount);
}
}
else {
if (flushCommon (debugMsg)) {
if (debugMsg != null) {
debugMsg.append (" Chars:");
UniCharIterator iter = new UniCharIterator (msChar);
int c;
for (c = iter.next(); c != 0; c = iter.next()) {
debugMsg.append (' ');
debugMsg.append (Integer.toString (c));
}
context.debug (debugMsg.toString());
}
moParm.driver().relText (msChar.toString());
}
msChar.delete (0, msChar.length());
}
mnRunLength = 0;
mnGlyphCount = 0;
}
}
void clear () {
moClipRect.detach();
}
void forceAttrChange () {
mbAttrChange = true;
}
private void setupRun (DrawAttr oCurrentAttr, RenderInfo oRenderInfo, float oX, float oY, boolean bIsRTL) {
if ((mnGlyphCount > 0) && (! mbUnknownWidth) && (! mpoLine.legacyPositioning())) {
if ((moAttr.getFontOverride() != null)
|| ((moAttr.getAttr() != null) && (moAttr.getAttr().fontInstance() != null))) {
if ((oX != moPrevX) || (oY != moPrevY)) {
if ((Math.abs (oX - moPrevX) > 0.001) || (Math.abs (oY - moPrevY) > 0.001)) {
flush();
}
}
}
}
if (mnGlyphCount == 0) {
moAttr.reset (oCurrentAttr);
mnRunStart = oRenderInfo.mpoGlyphLoc.getMapIndex();
moX = oX;
moY = oY;
mbIsRTL = bIsRTL;
moCharSpacing = 0;
moWordSpacing = 0;
TextAttr poAttr = moAttr.getAttr();
if (poAttr != null) {
if (poAttr.charSpacingEnable()) {
moCharSpacing = Units.toFloat (poAttr.charSpacing().getLength());
}
if (poAttr.wordSpacingEnable()) {
moWordSpacing = Units.toFloat (poAttr.wordSpacing().getLength());
}
}
if (oRenderInfo.mbAttrChange) {
mbAttrChange = true;
oRenderInfo.mbAttrChange = false;
}
}
}
private boolean flushCommon (StringBuilder debugMsg) {
boolean attrChange = mbAttrChange;
mbAttrChange = false;
if (attrChange && (! moAttr.assertAttrs (moClipRect))) {
return false;
}
GFXDriver poDriver = moParm.driver();
CoordPair oOffset = new CoordPair (Units.toUnitSpan (moX), Units.toUnitSpan (moY));
oOffset = ABXY.toXY (mpoLine.getXYOrigin(), oOffset, mpoLine.frame().getLayoutOrientation());
poDriver.relPosition (oOffset);
if (debugMsg != null) {
debugMsg.append ("At Y=");
debugMsg.append (oOffset.y().toString());
debugMsg.append (", X=");
debugMsg.append (oOffset.x().toString());
debugMsg.append (", ");
}
flushMultiple();
switch (meMappingType)
{
case GFXDriver.MAPPING_LEGACY:
poDriver.mapChars (mnRunStart, mnRunLength);
break;
case GFXDriver.MAPPING_FULL:
poDriver.mapGlyphs (moMappingList, mbIsRTL);
moMappingList.reset();
break;
}
return true;
}
private void updatePosition (GlyphLoc poGlyphLoc, float oX, float oY, int nGlyph, boolean bIsGlyph) {
FontInstance oFontInstance = moAttr.getWorkingFont();
mbUnknownWidth = true;
moPrevX = oX;
moPrevY = oY;
if (oFontInstance != null) {
boolean bHorizontal = ! mpoLine.verticalOrientation();
float oOffset = oFontInstance.getGlyphWidth (nGlyph, bHorizontal);
// float oOffset = bIsGlyph ? oFontInstance.getGlyphWidth (nGlyph, bHorizontal)
// : oFontInstance.getCharWidth (nGlyph, bHorizontal);
if (oOffset >= 0) {
mbUnknownWidth = false;
if (mbCharSpacingSupported) {
oOffset += moCharSpacing;
}
if (mbWordSpacingSupported && (mpoLine.getBreakClass (poGlyphLoc.getMapIndex()) == TextCharProp.BREAK_SP)) {
oOffset += moWordSpacing;
}
moPrevX += oOffset;
}
}
}
private void accumulateMapping (int nCharIndex, int nGlyphIndex, int nCharLength) {
if (meMappingType != GFXDriver.MAPPING_FULL) {
return;
}
if (nCharLength != 1) {
flushMultiple();
moMappingList.addMapping (nCharIndex, nGlyphIndex, nCharLength);
return;
}
// if (moMultiple == null) {
// moMultiple = new MultiMapper();
// }
if (! moMultiple.canAccumulate (nCharIndex, nGlyphIndex)) {
flushMultiple();
}
moMultiple.accumulate (nCharIndex, nGlyphIndex);
}
private void accumulateMapping (int nCharIndex, int nGlyphIndex) {
accumulateMapping (nCharIndex, nGlyphIndex, 1);
}
private void flushMultiple () {
moMultiple.flush (moMappingList);
}
}