private void internalDecompose(CharSequence source, StringBuffer target) {
        StringBuffer buffer = new StringBuffer(8);
        boolean canonical = (form & COMPATIBILITY_MASK) == 0;
        int ch32;
        //for (int i = 0; i < source.length(); i += (ch32<65536 ? 1 : 2)) {
        for (int i = 0; i < source.length();) {
            buffer.setLength(0);
            //ch32 = UTF16.charAt(source, i);
            ch32 = source.charAt(i++);
            if (UTF16CharacterSet.isHighSurrogate(ch32)) {
                char low = source.charAt(i++);
                ch32 = UTF16CharacterSet.combinePair((char)ch32, low);
            }
            data.getRecursiveDecomposition(canonical, ch32, buffer);

            // add all of the characters in the decomposition.
            // (may be just the original character, if there was
            // no decomposition mapping)

            int ch;
            //for (int j = 0; j < buffer.length(); j += (ch<65536 ? 1 : 2)) {
            for (int j = 0; j < buffer.length();) {
                //ch = UTF16.charAt(buffer, j);
                ch = buffer.charAt(j++);
                if (UTF16CharacterSet.isHighSurrogate(ch)) {
                    char low = buffer.charAt(j++);
                    ch = UTF16CharacterSet.combinePair((char)ch, low);
                }
                int chClass = data.getCanonicalClass(ch);
                int k = target.length(); // insertion point
                if (chClass != 0) {

                    // bubble-sort combining marks as necessary

                    int ch2;
                    while (k > 0) {
                        int step = 1;
                        ch2 = target.charAt(k-1);
                        if (UTF16CharacterSet.isSurrogate(ch2)) {
                            step = 2;
                            char high = target.charAt(k-2);
                            ch2 = UTF16CharacterSet.combinePair(high, (char)ch2);
                        }
                        if (data.getCanonicalClass(ch2) <= chClass) break;
                        k -= step;
                    }
//                    for (; k > 0; k -= (ch2<65536 ? 1 : 2)) {
//                        ch2 = UTF16.charAt(target, k-1);
//                        if (data.getCanonicalClass(ch2) <= chClass) break;
//                    }
                }
                if (ch < 65536) {
                    target.insert(k, (char)ch);
                } else {
                    char[] chars = new char[]{UTF16CharacterSet.highSurrogate(ch), UTF16CharacterSet.lowSurrogate(ch)};
                    target.insert(k, chars);
                }
                //target.insert(k, UTF16.valueOf(ch));
            }
        }
    }