com.adobe.xfa.text.AFERun 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
package com.adobe.xfa.text;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import com.adobe.fontengine.inlineformatting.AttributedRun;
import com.adobe.fontengine.inlineformatting.ElementAttribute;
import com.adobe.fontengine.inlineformatting.InterElementAttribute;
import com.adobe.xfa.ut.FindBugsSuppress;
import com.adobe.xfa.ut.Storage;
/**
* @exclude from published api.
*/
class AFERun implements AttributedRun {
private Storage mElements;
@FindBugsSuppress(code="UwF") // will never be written as long as gEnableDebugging == false
private TextContext mContext;
private int mInstance;
private int mEvent;
private boolean mMapRequired = false;
private static final AtomicInteger gNextDebugInstance = new AtomicInteger();
private static final boolean gEnableDebugging = false;
AFERun (TextContext context) {
if (gEnableDebugging && (context != null) && context.debug()) {
mContext = context;
}
}
void load (DispLineRaw line) {
StringBuilder debugMsg = null;
if (mContext != null) {
mInstance = gNextDebugInstance.incrementAndGet();
debugMsg = startDebug ("create");
debugMsg.append ("[");
}
int charCount = line.getCharCount();
if (mElements == null) {
mElements = new Storage(charCount);
} else {
mElements.setSize (0); // TODO: could try to reuse elements
}
int runIndex = 0;
int runCharLimit = 0;
AFEElement prevElement = null;
DispRun dispRun = null;
DispRun prevRun = null;
MappingManager mappingManager = line.getFormatInfo().getMappingManager();
TextContext context = line.display().getContext();
for (int i = 0; i < charCount; i++) {
if ((debugMsg != null) && (i > 0)) {
debugMsg.append (", ");
}
int bidiLevel = 0;
if (mappingManager != null) {
bidiLevel = mappingManager.getLevel (i);
}
DispEmbed embed = line.isObject (i);
if (embed != null) {
AFEElement element = new AFEElement (context, embed.getEmbed(), i);
element.populateEmbed (dispRun, bidiLevel);
mElements.add (element);
prevRun = null;
prevElement = null;
if (debugMsg != null) {
debugMsg.append (" object (");
debugMsg.append (element.getEmbed().toString());
debugMsg.append (")");
}
} else {
if (i >= runCharLimit) {
dispRun = line.getRun (runIndex);
runCharLimit = dispRun.getMapIndex() + dispRun.getMapLength();
runIndex++;
}
int c = line.getChar (i);
AFEElement element = new AFEElement (context, c, i);
element.populateChar (prevElement, dispRun, prevRun, bidiLevel);
mElements.add (element);
prevElement = element;
prevRun = dispRun;
if (debugMsg != null) {
if (c == '\'') {
debugMsg.append ("'\\''");
} else if ((c >= 0x20) && (c < 0x7F)) {
debugMsg.append ('\'');
debugMsg.append ((char) c);
debugMsg.append ('\'');
} else {
debugMsg.append (Units.hexToString (c));
}
}
}
}
if (debugMsg != null) {
debugMsg.append (']');
mContext.debug (debugMsg.toString());
}
}
int getSize () {
return mElements.size();
}
AFEElement getElement (int position) {
return e (position);
}
boolean isMapRequired () {
return mMapRequired;
}
public void adjustPlacementAndAdvance (int position, double xPlacementDelta, double yPlacementDelta, double xAdvanceDelta, double yAdvanceDelta) {
AFEElement element = null;
if ((xPlacementDelta != 0) || (yPlacementDelta != 0) || (xAdvanceDelta != 0) || (yAdvanceDelta != 0)) {
element = e (position);
element.adjustPlacementAndAdvance (xPlacementDelta, yPlacementDelta, xAdvanceDelta, yAdvanceDelta);
debugElementPlacementAndAdvance (element, position, "adjustPlacementAndAdvance");
}
}
public int elementAt (int position) {
return e(position).elementAt();
}
public Object getElementStyle (int position, ElementAttribute attribute) {
return e(position).getElementStyle (attribute);
}
public double getElementXAdvance (int position) {
return e(position).getElementXAdvance();
}
public double getElementXPlacement( int position) {
return e(position).getElementXPlacement();
}
public double getElementYAdvance (int position) {
return e(position).getElementYAdvance();
}
public double getElementYPlacement (int position) {
return e(position).getElementYPlacement();
}
public Object getInterElementStyleBefore (int position, InterElementAttribute attribute) {
return e(position).getInterElementStyleBefore (attribute);
}
public int getSubrunLimit (int start, int limit, ElementAttribute attribute) {
AFEElement first = e (start);
for (int test = start+1; test < limit; test++) {
if (! first.matchAttr (e (test), attribute)) {
return test;
}
}
return limit;
}
public int getSubrunLimit (int start, int limit, @SuppressWarnings("unchecked") Set attributes) {
AFEElement first = e (start);
for (int test = start+1; test < limit; test++) {
if (! first.matchAttr (e (test), attributes)) {
return test;
}
}
return limit;
}
public void remove (int position) {
mElements.remove (position);
mMapRequired = true;
}
public void replace (int[] positions, int[] elementIDs) {
replaceManyWithMany (positions, elementIDs);
}
public void replace (int position, int elementID) {
replaceOneWithOne (position, elementID);
}
public void replace (int position, int[] elementIDs) {
replaceOneWithMany (position, elementIDs);
}
public void replace (int[] positions, int elementID) {
replaceManyWithOne (positions, elementID);
}
public void replace (int start, int limit, int elementID) {
replaceRangeWithOne (start, limit, elementID);
}
public void setElementPlacementAndAdvance (int position, double xPlacement, double yPlacement, double xAdvance, double yAdvance) {
AFEElement element = e (position);
element.setElementPlacementAndAdvance (xPlacement, yPlacement, xAdvance, yAdvance);
debugElementPlacementAndAdvance (element, position, "setElementPlacementAndAdvance");
}
public void setElementStyle (int position, ElementAttribute attribute, Object value) {
debugElementStyle (position, position+1, attribute, value);
e(position).setElementStyle (attribute, value);
}
public void setElementStyle (int start, int limit, ElementAttribute attribute, Object value) {
debugElementStyle (start, limit, attribute, value);
for (int i = start; i < limit; i++) {
e(i).setElementStyle (attribute, value);
}
}
public void setInterElementStyleBefore (int position, InterElementAttribute attribute, Object value) {
debugInterElementStyle (position, position+1, attribute, value);
e(position).setInterElementStyleBefore (attribute, value);
}
public void setInterElementStyleBefore (int start, int limit, InterElementAttribute attribute, Object value) {
debugInterElementStyle (start, limit, attribute, value);
for (int i = start; i < limit; i++) {
e(i).setInterElementStyleBefore (attribute, value);
}
}
public void startWorkingWithPositions (int start, int limit) {
if (mContext != null) {
StringBuilder debugMsg = startDebug ("startWorkingWithPositions");
debugMsg.append ('[');
debugInt (debugMsg, start);
debugMsg.append ('-');
debugInt (debugMsg, limit - 1);
debugMsg.append (']');
mContext.debug (debugMsg.toString());
}
for (int i = start; i < limit; i++) {
e(i).startWorkingWithPositions();
}
}
public String toString () {
StringBuilder result = new StringBuilder("Run:\n");
for (int i = 0; i < mElements.size(); i++) {
result.append(" (");
result.append(e(i).toString());
result.append(")\n");
}
return result.toString();
}
private AFEElement e (int position) {
assert (position < mElements.size());
return mElements.get(position);
}
private void insert (int position, int[] elementIDs) {
AFEElement sample = e (position);
sample.setElement (elementIDs[0], true);
sample.setInMultiple (true);
for (int i = 1; i < elementIDs.length; i++) {
AFEElement insert = new AFEElement (sample);
insert.setElement (elementIDs[i], true);
mElements.add (position, insert);
position++;
}
mMapRequired = true;
}
private void remove (int[] positions) {
for (int i = positions.length; i > 1; i--) { // don't remove first
i--;
mElements.remove (positions[i]);
}
mMapRequired = true;
}
private AFEElement removeRange (int start, int limit) {
for (limit--; limit > start; limit--) {
mElements.remove (limit);
}
mMapRequired = true;
return e (start); // not removed
}
private void replaceManyWithMany (int[] positions, int[] elementIDs) {
assert (positions.length > 0);
int i;
if (elementIDs.length == 0) {
for (i = positions.length; i > 0; ) {
i--;
remove (positions[i]);
}
} else if (elementIDs.length == 1) {
replaceManyWithOne (positions, elementIDs[0]);
} else if (positions.length == 1) {
replaceOneWithMany (positions[0], elementIDs);
} else if (isSequential (positions)) {
replaceRangeWithMany (positions[0], positions[0] + positions.length, elementIDs);
} else {
mMapRequired = true;
debugReplace (positions, elementIDs);
remove (positions);
insert (positions[0], elementIDs); // TODO: no way to map this in current glyph loc architecture
}
}
private void replaceManyWithOne (int[] positions, int elementID) {
assert (positions.length > 0);
if (positions.length == 1) {
replaceOneWithOne (positions[0], elementID);
} else if (isSequential (positions)) {
replaceRangeWithOne (positions[0], positions[0] + positions.length, elementID);
} else {
assert (false); // TODO: not supported in AXTE mapping
if (mContext != null) {
int[] elementIDs = new int [1];
elementIDs[0] = elementID;
debugReplace (positions, elementIDs);
}
remove (positions);
AFEElement afeElement = e (positions[0]);
afeElement.setElement (elementID, true);
afeElement.setMapLength (afeElement.getMapLength() + positions.length - 1); // TODO: need to rework glyph loc map for this to make sense
}
}
private void replaceOneWithMany (int position, int[] elementIDs) {
if (elementIDs.length == 0) {
remove (position);
} else if (elementIDs.length == 1) {
replaceOneWithOne (position, elementIDs[0]);
} else {
if (mContext != null) {
int[] positions = new int [1];
positions[0] = position;
debugReplace (positions, elementIDs);
}
insert (position, elementIDs);
}
}
private void replaceOneWithOne (int position, int elementID) {
if (mContext != null) {
int[] positions = new int [] {position};
int[] elementIDs = new int [] {elementID};
debugReplace (positions, elementIDs);
}
e(position).setElement (elementID, false);
}
private void replaceRangeWithOne (int start, int limit, int elementID) {
if (mContext != null) {
int[] elementIDs = new int [] {elementID};
debugReplaceRange (start, limit, elementIDs);
}
AFEElement keeper = removeRange (start, limit);
keeper.setElement (elementID, true);
keeper.setMapLength (keeper.getMapLength() + (limit - start - 1));
}
private void replaceRangeWithMany (int start, int limit, int[] elementIDs) {
debugReplaceRange (start, limit, elementIDs);
removeRange (start, limit);
AFEElement keeper = removeRange (start, limit);
keeper.setMapLength (keeper.getMapLength() + (limit - start - 1));
insert (start, elementIDs);
}
private static boolean isSequential (int[] positions) {
assert (positions.length > 0);
int prev = positions[0];
for (int i = 1; i < positions.length; i++) {
prev++;
if (positions[i] != prev) {
return false;
}
}
return true;
}
private StringBuilder startDebug (String event) {
StringBuilder result = new StringBuilder();
result.append (Units.intToString (mInstance, 4));
result.append ("(");
result.append (Units.intToString (++mEvent, true));
result.append (") ");
result.append (event);
result.append (": ");
return result;
}
public void debugElementPlacementAndAdvance (AFEElement element, int position, String event) {
if (mContext == null) {
return;
}
StringBuilder debugMsg = startDebug (event);
debugMsg.append ("[");
debugInt (debugMsg, position);
debugMsg.append ("] placement (");
debugMsg.append (Double.toString (element.getScaledXPlacement()));
debugMsg.append (", ");
debugMsg.append (Double.toString (element.getScaledYPlacement()));
debugMsg.append (") advance (");
debugMsg.append (Double.toString (element.getScaledXAdvance()));
debugMsg.append (", ");
debugMsg.append (Double.toString (element.getScaledYAdvance()));
debugMsg.append (")");
mContext.debug (debugMsg.toString());
}
private final void debugReplace (int[] positions, int[] elementIDs) {
if (mContext == null) {
return;
}
int i;
StringBuilder debugMsg = startDebug ("replace");
debugMsg.append ('[');
int count = 0;
int start = -1;
int prev = Integer.MAX_VALUE;
for (i = 0; i < positions.length; i++) {
int pos = positions[i];
if (pos != (prev + 1)) {
if (debugReplaceRange (debugMsg, count, start, prev)) {
count++;
start = pos;
}
}
prev = pos;
debugInt (debugMsg, i, positions[i]);
}
debugReplaceRange (debugMsg, count, start, prev);
debugMsg.append ("] [");
for (i = 0; i < elementIDs.length; i++) {
debugHex (debugMsg, i, elementIDs[i]);
}
debugMsg.append (']');
mContext.debug (debugMsg.toString());
}
private void debugReplaceRange (int start, int limit, int[] elementIDs) {
if (mContext == null) {
return;
}
int length = limit - start;
int[] positions = new int [length];
for (int i = 0; i < length; i++) {
positions[i] = start + i;
}
debugReplace (positions, elementIDs);
}
private final boolean debugReplaceRange (StringBuilder debugMsg, int count, int start, int end) {
if (start < 0) {
return false;
}
StringBuilder range = new StringBuilder();
debugInt (range, start);
if (end > start) {
range.append ('-');
debugInt (range, end);
}
debugElement (debugMsg, count, range.toString());
return true;
}
private final void debugElementStyle (int start, int limit, ElementAttribute attribute, Object value) {
debugStyle ("setElementStyle", start, limit, attribute, value);
}
private final void debugInterElementStyle (int start, int limit, InterElementAttribute attribute, Object value) {
debugStyle ("setInterElementStyle", start, limit, attribute, value);
}
private final void debugStyle (String type, int start, int limit, Object attribute, Object value) {
if (mContext == null) {
return;
}
StringBuilder debugMsg = startDebug (type);
debugMsg.append ("[");
debugInt (debugMsg, start);
if ((limit - start) > 1) {
debugMsg.append ("-");
debugInt (debugMsg, limit - 1);
}
debugMsg.append ("] attribute (");
debugMsg.append (attribute.toString());
debugMsg.append (") value (");
debugMsg.append (value.toString());
debugMsg.append (")");
mContext.debug (debugMsg.toString());
}
private final static void debugHex (StringBuilder result, int index, int value) {
debugElement (result, index, Units.hexToString (value, 4, "0x"));
}
private final static void debugInt (StringBuilder result, int value) {
debugInt (result, 0, value);
}
private final static void debugInt (StringBuilder result, int index, int value) {
debugElement (result, index, Units.intToString (value, 0));
}
private final static void debugElement (StringBuilder result, int index, String value) {
if (index > 0) {
result.append (", ");
}
result.append (value);
}
}