in batik-gvt/src/main/java/org/apache/batik/gvt/text/ArabicTextHandler.java [68:235]
public static AttributedString assignArabicForms(AttributedString as) {
// first check to see if the string contains any arabic chars
// if not, then don't need to do anything
if (!containsArabic(as)) {
return as;
}
// if the string contains any ligatures with transparent chars
// eg. AtB where AB form a ligature and t is transparent, then
// reorder that part of the string so that it becomes tAB
// construct the reordered ACI
AttributedCharacterIterator aci = as.getIterator();
int numChars = aci.getEndIndex() - aci.getBeginIndex();
int[] charOrder = null;
if (numChars >= 3) {
char prevChar = aci.first();
char c = aci.next();
int i = 1;
for (char nextChar = aci.next();
nextChar != AttributedCharacterIterator.DONE;
prevChar = c, c = nextChar, nextChar = aci.next(), i++) {
if (arabicCharTransparent(c)) {
if (hasSubstitute(prevChar, nextChar)) {
// found a ligature, separated by a transparent char
if (charOrder == null) {
charOrder = new int[numChars];
for (int j = 0; j < numChars; j++) {
charOrder[j] = j + aci.getBeginIndex();
}
}
int temp = charOrder[i];
charOrder[i] = charOrder[i-1];
charOrder[i-1] = temp;
}
}
}
}
if (charOrder != null) {
// need to reconstruct the reordered attributed string
StringBuffer reorderedString = new StringBuffer(numChars);
char c;
for (int i = 0; i < numChars; i++) {
c = aci.setIndex(charOrder[i]);
reorderedString.append( c );
}
AttributedString reorderedAS;
reorderedAS = new AttributedString(reorderedString.toString());
for (int i = 0; i < numChars; i++) {
aci.setIndex(charOrder[i]);
Map attributes = aci.getAttributes();
reorderedAS.addAttributes(attributes, i, i+1);
}
if (charOrder[0] != aci.getBeginIndex()) {
// have swapped the first char. Need to move
// any position attributes
aci.setIndex(charOrder[0]);
Float x = (Float) aci.getAttribute(
GVTAttributedCharacterIterator.TextAttribute.X);
Float y = (Float) aci.getAttribute(
GVTAttributedCharacterIterator.TextAttribute.Y);
if (x != null && !x.isNaN()) {
reorderedAS.addAttribute
(GVTAttributedCharacterIterator.TextAttribute.X,
Float.NaN, charOrder[0], charOrder[0]+1);
reorderedAS.addAttribute
(GVTAttributedCharacterIterator.TextAttribute.X,
x, 0, 1);
}
if (y != null && !y.isNaN()) {
reorderedAS.addAttribute
(GVTAttributedCharacterIterator.TextAttribute.Y,
Float.NaN, charOrder[0], charOrder[0]+1);
reorderedAS.addAttribute
(GVTAttributedCharacterIterator.TextAttribute.Y,
y, 0, 1);
}
}
as = reorderedAS;
}
// first assign none to all arabic letters
aci = as.getIterator();
int runStart = -1;
int idx = aci.getBeginIndex();
for (int c = aci.first();
c != AttributedCharacterIterator.DONE;
c = aci.next(), idx++) {
if ((c >= arabicStart) && (c <= arabicEnd)) {
if (runStart == -1)
runStart = idx;
} else if (runStart != -1) {
as.addAttribute(ARABIC_FORM, ARABIC_NONE, runStart, idx);
runStart = -1;
}
}
if (runStart != -1)
as.addAttribute(ARABIC_FORM, ARABIC_NONE, runStart, idx);
aci = as.getIterator(); // Make sure ACI tracks ARABIC_FORM
int end = aci.getBeginIndex();
Integer currentForm = ARABIC_NONE;
// for each run of arabic chars, assign the appropriate form
while (aci.setIndex(end) != AttributedCharacterIterator.DONE) {
int start = aci.getRunStart(ARABIC_FORM);
end = aci.getRunLimit(ARABIC_FORM);
char currentChar = aci.setIndex(start);
currentForm = (Integer)aci.getAttribute(ARABIC_FORM);
if (currentForm == null) {
// only modify if the chars in the run are arabic
continue;
}
int currentIndex = start;
int prevCharIndex = start-1;
while (currentIndex < end) {
char prevChar = currentChar;
currentChar= aci.setIndex(currentIndex);
while (arabicCharTransparent(currentChar) &&
(currentIndex < end)) {
currentIndex++;
currentChar = aci.setIndex(currentIndex);
}
if (currentIndex >= end) {
break;
}
Integer prevForm = currentForm;
currentForm = ARABIC_NONE;
if (prevCharIndex >= start) { // if not at the start
// if prev char right AND current char left
if (arabicCharShapesRight(prevChar)
&& arabicCharShapesLeft(currentChar)) {
// Increment the form of the previous char
prevForm = prevForm + 1;
as.addAttribute(ARABIC_FORM, prevForm,
prevCharIndex, prevCharIndex+1);
// and set the form of the current char to INITIAL
currentForm = ARABIC_INITIAL;
} else if (arabicCharShaped(currentChar)) {
// set the form of the current char to ISOLATE
currentForm = ARABIC_ISOLATED;
}
// if this is the first arabic char and its
// shaped, set to ISOLATE
} else if (arabicCharShaped(currentChar)) {
// set the form of the current char to ISOLATE
currentForm = ARABIC_ISOLATED;
}
if (currentForm != ARABIC_NONE)
as.addAttribute(ARABIC_FORM, currentForm,
currentIndex, currentIndex+1);
prevCharIndex = currentIndex;
currentIndex++;
}
}
return as;
}