com.adobe.xfa.text.LayoutRenderer 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.GFXEnv;
import com.adobe.xfa.gfx.GFXMapping;
import com.adobe.xfa.gfx.GFXMappingList;
import com.adobe.xfa.ut.CoordPair;
import com.adobe.xfa.ut.Rect;
import com.adobe.xfa.ut.UnitSpan;
import com.adobe.xfa.ut.UniCharIterator;
/**
* @exclude from published api.
*/
class LayoutRenderer extends GFXEnv {
private final LayoutDriver mpoDriver;
LayoutRenderer (TextLayout poLayout, DispLineWrapped poDispLine, UnitSpan oFullAscent, UnitSpan oFullDescent, boolean bAllowCharGlyphs) {
interactive (false);
mpoDriver = new LayoutDriver (this, poLayout, poDispLine, oFullAscent, oFullDescent, bAllowCharGlyphs);
fontService (poDispLine.stream().fontService());
driverAttach();
}
void finish () {
mpoDriver.finish();
}
public GFXDriver driver () {
return mpoDriver;
}
}
class LayoutDriver extends GFXDriver {
static class RunInfo {
int mGlyphCount;
CoordPair mDefaultOffset;
boolean mIsRTL;
RunInfo (UnitSpan initialY) {
mGlyphCount = 0;
mDefaultOffset = new CoordPair (UnitSpan.ZERO, initialY);
mIsRTL = false;
}
};
private static abstract class RunHelper {
static class GlyphInfo {
final int mGlyphID;
final float mGlyphWidth;
GlyphInfo (int glyphID, float glyphWidth) {
mGlyphID = glyphID;
mGlyphWidth = glyphWidth;
}
};
private final TextAttr mpoAttr;
private final boolean mbCharMode;
private final FontInstance moFontInstance;
void generateRun (CoordPair oPenPosn, TextLayoutLine oLayoutLine, RunInfo runInfo) {
TextGlyphRun oRun = new TextGlyphRun();
UnitSpan oVerticalShiftOffset = UnitSpan.ZERO;
if (mpoAttr != null) {
TextAttr poAttr = mpoAttr.getOriginalAttr();
if (poAttr == null) {
poAttr = mpoAttr;
} else {
oVerticalShiftOffset = mpoAttr.baselineShift().getLength();
}
oRun.setAttr (poAttr);
}
oRun.setCharRun (mbCharMode);
oRun.setRTL (runInfo.mIsRTL);
int nGlyphCount = 0;
float oAccumulatedWidth = 0;
GlyphInfo glyphInfo = getNextGlyph();
while (glyphInfo != null) {
oRun.addGlyph (glyphInfo.mGlyphID);
oAccumulatedWidth += glyphInfo.mGlyphWidth;
glyphInfo = getNextGlyph();
nGlyphCount++;
}
CoordPair oRunPosn = new CoordPair (oPenPosn.x(), oPenPosn.y().subtract (oVerticalShiftOffset));
oRun.setPosition (oRunPosn);
// if ((runInfo.mGlyphCount == 0) && (oPenPosn.x().value() != 0)) {
if (! oRunPosn.equals (runInfo.mDefaultOffset)) { // TODO: need glyph widths to check for shift
oRun.setShift (oRunPosn.subtract (runInfo.mDefaultOffset));
}
runInfo.mDefaultOffset = new CoordPair (oRunPosn.x().add (Units.toUnitSpan (oAccumulatedWidth)),
runInfo.mDefaultOffset.y());
oLayoutLine.addRun (oRun);
runInfo.mGlyphCount += nGlyphCount;
}
protected RunHelper (TextAttr poAttr, boolean bCharMode) {
mpoAttr = poAttr;
mbCharMode = bCharMode;
moFontInstance = poAttr != null ? poAttr.fontInstance() : null;
}
protected FontInstance getFontInstance () {
return moFontInstance;
}
abstract protected GlyphInfo getNextGlyph ();
}
private static class CharRunHelper extends RunHelper {
private final UniCharIterator mIterator;
CharRunHelper (TextAttr poAttr, String sText, boolean bCharMode) {
super (poAttr, bCharMode);
mIterator = new UniCharIterator (sText);
}
CharRunHelper (TextAttr poAttr, String sText) {
this (poAttr, sText, true);
}
protected GlyphInfo getNextGlyph () {
int c = mIterator.next();
if (c == 0) {
return null;
}
float oWidth;
if (getFontInstance() == null) {
oWidth = 0;
} else {
oWidth = getFontInstance().getCharWidth (c, true);
}
return new GlyphInfo (c, oWidth);
}
}
private static class CharGlyphRunHelper extends CharRunHelper {
CharGlyphRunHelper (TextAttr poAttr, String sText) {
super (poAttr, sText, false);
}
protected GlyphInfo getNextGlyph () {
GlyphInfo info = super.getNextGlyph();
if (info == null) {
return null;
}
if (getFontInstance() != null) {
int nGlyphID = getFontInstance().getGlyphID (info.mGlyphID);
if (nGlyphID != 0) { // TODO: proper .notdef handling
info = new GlyphInfo (nGlyphID, info.mGlyphWidth);
}
}
return info;
}
}
private static class GlyphRunHelper extends RunHelper {
private final int[] mpnGlyphIDs;
private final int mnLength;
private int mnIndex;
GlyphRunHelper (TextAttr poAttr, int[] pnGlyphIDs, int nLength) {
super (poAttr, false);
mpnGlyphIDs = pnGlyphIDs;
mnLength = nLength;
mnIndex = 0;
}
protected GlyphInfo getNextGlyph () {
if (mnIndex >= mnLength) {
return null;
}
int nGlyph = mpnGlyphIDs[mnIndex];
mnIndex++;
float oWidth = 0;
if (getFontInstance() != null) {
oWidth = getFontInstance().getGlyphWidth (nGlyph, true); // TBD: vertical text
}
return new GlyphInfo (nGlyph, oWidth);
}
}
private final TextLayout mpoLayout;
private final DispLineWrapped mpoDispLine;
private final boolean mbAllowCharGlyphs;
private final TextLayoutLine moLayoutLine = new TextLayoutLine();
private final GFXMappingList moMappings = new GFXMappingList();
private TextAttr mpoTextAttr;
private final RunInfo mRunInfo;
private final MultiMapper moMultiple = new MultiMapper();
LayoutDriver (LayoutRenderer oRenderer, TextLayout poLayout, DispLineWrapped poDispLine, UnitSpan oFullAscent, UnitSpan oFullDescent, boolean bAllowCharGlyphs) {
super (oRenderer);
mpoLayout = poLayout;
mpoDispLine = poDispLine;
mbAllowCharGlyphs = bAllowCharGlyphs;
mpoTextAttr = null;
mRunInfo = new RunInfo (poDispLine.getXYOrigin().y().add (oFullAscent));
initDeviceUnitsPerInch (1000, 1000);
moLayoutLine.setFullAscent (oFullAscent);
moLayoutLine.setFullDescent (oFullDescent);
TextFrame poFrame = poDispLine.frame();
TextSparseStream poStream = poFrame.getStream();
int nIndex = poLayout.getLineCount();
int eStartState;
if ((nIndex == 0) && (poFrame == poStream.getFrame (0))) {
eStartState = TextLayoutLine.LINE_END_ULTIMATE;
} else if (poDispLine.isFirstParaLine()) {
eStartState = TextLayoutLine.LINE_END_PARA;
} else {
eStartState = TextLayoutLine.LINE_END_WORD_WRAP;
}
eStartState = ResolveLineEndState (eStartState, poDispLine.getStartBreak());
moLayoutLine.setLineStartState (eStartState);
int eEndState;
if ((nIndex + 1 == poFrame.getLineCount()) && (poFrame == poStream.getFrame (poStream.getFrameCount() - 1))) {
eEndState = TextLayoutLine.LINE_END_ULTIMATE;
} else {
switch (poDispLine.getLastParaLine()) {
case DispLine.HARD_NEW_LINE:
eEndState = TextLayoutLine.LINE_END_FORCED;
break;
case DispLine.REAL_LAST_LINE:
eEndState = TextLayoutLine.LINE_END_PARA;
break;
default:
eEndState = TextLayoutLine.LINE_END_WORD_WRAP;
break;
}
}
eEndState = ResolveLineEndState (eEndState, poDispLine.getEndBreak());
moLayoutLine.setLineEndState (eEndState);
}
void finish () {
flushMultiple();
moLayoutLine.setMappings (moMappings);
mpoLayout.addLine (moLayoutLine);
}
// Inherited from class GFXDriver
public void absLine (CoordPair oEnd, int eDrawMode) {
}
public void absFillRect (Rect oRect, int eDrawMode) {
}
// TBD:
public void paraHint () {
}
public void absText (String sText, int eDrawMode) {
if (sText.length() == 0) {
return;
}
if (mbAllowCharGlyphs) {
CharRunHelper oHelper = new CharRunHelper (mpoTextAttr, sText); // TODO: cache and reuse instance?
oHelper.generateRun (getAbsPosition(), moLayoutLine, mRunInfo); // TBD: rel position?
} else {
CharGlyphRunHelper oHelper = new CharGlyphRunHelper (mpoTextAttr, sText); // TODO: cache and reuse instance?
oHelper.generateRun (getAbsPosition(), moLayoutLine, mRunInfo); // TBD: rel position?
}
}
public void absGlyphs (int[] pnGlyphs, int length) {
if (length == 0) {
return;
}
GlyphRunHelper oHelper = new GlyphRunHelper (mpoTextAttr, pnGlyphs, length); // TODO: cache and reuse instance?
oHelper.generateRun (getAbsPosition(), moLayoutLine, mRunInfo); // TBD: rel position?
mRunInfo.mIsRTL = false;
}
public void setUnicodeChars (int pcText[]) { // TODO: add render context support in C++ for leaders in Editor?
StringBuilder sContent = new StringBuilder();
int nSize = pcText.length;
for (int i = 0; i < nSize; i++) {
int c = pcText[i];
if ((i + 1) == nSize) {
switch (moLayoutLine.getLineEndState()) {
case TextLayoutLine.LINE_END_FORCED:
assert (c == ' ');
c = '\n';
break;
case TextLayoutLine.LINE_END_PARA:
assert (c == ' ');
c = '\u2029';
break;
}
}
sContent.append ((char) c);
}
moLayoutLine.setContent (sContent.toString());
}
public void mapGlyphs (GFXMappingList oMappings, boolean bIsRTL) {
boolean bCharIndexFound = false;
for (int i = 0; i < oMappings.getMappingCount(); i++) {
GFXMapping oRelMapping = oMappings.getMapping (i);
if ((! bCharIndexFound) && (oRelMapping.getCharCount() > 0)) {
int nCharIndex = oRelMapping.getCharIndex (0);
TextAttr poAttr = mpoDispLine.getMappedAttr (nCharIndex);
if (poAttr != null) {
mpoTextAttr = poAttr;
}
bCharIndexFound = true;
}
int eMultiple = moMultiple.canAccumulate (oRelMapping, mRunInfo.mGlyphCount);
if (eMultiple != MultiMapper.GLYPH_NOT_MULTIPLE) {
if (eMultiple == MultiMapper.GLYPH_FLUSH_FIRST) {
flushMultiple();
}
moMultiple.accumulate (oRelMapping, mRunInfo.mGlyphCount);
}
else {
flushMultiple();
GFXMapping oAbsMapping = new GFXMapping();
int j;
for (j = 0; j < oRelMapping.getCharCount(); j++) {
oAbsMapping.addCharIndex (oRelMapping.getCharIndex (j));
}
for (j = 0; j < oRelMapping.getGlyphCount(); j++) {
oAbsMapping.addGlyphIndex (oRelMapping.getGlyphIndex (j) + mRunInfo.mGlyphCount);
}
moMappings.addMapping (oAbsMapping);
}
}
mRunInfo.mIsRTL = bIsRTL;
}
public int getMappingLevel () {
return MAPPING_FULL;
}
public int height () {
return 1 << 16;
}
public int width () {
return 1 << 16;
}
public boolean interactive () {
return false;
}
public void setClipRect (Rect oRect) {
}
private void flushMultiple () {
moMultiple.flush (moMappings);
}
private static int ResolveLineEndState (int eLineState, int eBreakState) {
if (eLineState == TextLayoutLine.LINE_END_WORD_WRAP) {
switch (eBreakState) {
case DispLine.LINE_BREAK_HYPHEN_SUPPRESS:
return TextLayoutLine.LINE_END_LAST_WORD;
case DispLine.LINE_BREAK_HYPHEN:
return TextLayoutLine.LINE_END_HYPHEN;
case DispLine.LINE_BREAK_FORCED:
return TextLayoutLine.LINE_END_EMERGENCY;
}
}
return eLineState;
}
}