Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c6df994b authored by Roozbeh Pournader's avatar Roozbeh Pournader Committed by android-build-merger
Browse files

Merge "Keep spans while transforming to uppercase" into oc-dev

am: cd3f72d6

Change-Id: Ie93ae0764c46883c46f5d4f5a8996d57aa143b7e
parents 97a97c72 cd3f72d6
Loading
Loading
Loading
Loading
+60 −2
Original line number Diff line number Diff line
@@ -17,6 +17,10 @@ package android.text.method;

import android.content.Context;
import android.graphics.Rect;
import android.icu.text.CaseMap;
import android.icu.text.Edits;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
@@ -35,7 +39,7 @@ public class AllCapsTransformationMethod implements TransformationMethod2 {
    private Locale mLocale;

    public AllCapsTransformationMethod(Context context) {
        mLocale = context.getResources().getConfiguration().locale;
        mLocale = context.getResources().getConfiguration().getLocales().get(0);
    }

    @Override
@@ -56,7 +60,61 @@ public class AllCapsTransformationMethod implements TransformationMethod2 {
        if (locale == null) {
            locale = mLocale;
        }
        return source.toString().toUpperCase(locale);

        if (!(source instanceof Spanned)) { // No spans
            return CaseMap.toUpper().apply(
                    locale, source, new StringBuilder(),
                    null /* we don't need the edits */);
        }

        final Edits edits = new Edits();
        final SpannableStringBuilder result = CaseMap.toUpper().apply(
                locale, source, new SpannableStringBuilder(), edits);
        if (!edits.hasChanges()) {
            // No changes happened while capitalizing. We can return the source as it was.
            return source;
        }

        final Edits.Iterator iterator = edits.getFineIterator();
        final Spanned spanned = (Spanned) source;
        final int sourceLength = source.length();
        final Object[] spans = spanned.getSpans(0, sourceLength, Object.class);
        for (Object span : spans) {
            final int sourceStart = spanned.getSpanStart(span);
            final int sourceEnd = spanned.getSpanEnd(span);
            final int flags = spanned.getSpanFlags(span);
            // Make sure the indexes are not at the end of the string, since in that case
            // iterator.findSourceIndex() would fail.
            final int destStart = sourceStart == sourceLength ? result.length() :
                    mapToDest(iterator, sourceStart);
            final int destEnd = sourceEnd == sourceLength ? result.length() :
                    mapToDest(iterator, sourceEnd);
            result.setSpan(span, destStart, destEnd, flags);
        }
        return result;
    }

    private static int mapToDest(Edits.Iterator iterator, int sourceIndex) {
        // Guaranteed to succeed if sourceIndex < source.length().
        iterator.findSourceIndex(sourceIndex);
        if (sourceIndex == iterator.sourceIndex()) {
            return iterator.destinationIndex();
        }
        // We handle the situation differently depending on if we are in the changed slice or an
        // unchanged one: In an unchanged slice, we can find the exact location the span
        // boundary was before and map there.
        //
        // But in a changed slice, we need to treat the whole destination slice as an atomic unit.
        // We adjust the span boundary to the end of that slice to reduce of the chance of adjacent
        // spans in the source overlapping in the result. (The choice for the end vs the beginning
        // is somewhat arbitrary, but was taken because we except to see slightly more spans only
        // affecting a base character compared to spans only affecting a combining character.)
        if (iterator.hasChange()) {
            return iterator.destinationIndex() + iterator.newLength();
        } else {
            // Move the index 1:1 along with this unchanged piece of text.
            return iterator.destinationIndex() + (sourceIndex - iterator.sourceIndex());
        }
    }

    @Override