public static AttributedString assignArabicForms()

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;
    }