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

Commit 4be80155 authored by Seigo Nonaka's avatar Seigo Nonaka
Browse files

Fix shiftDrawingOffsetForStartOverhang

The shiftDrawingOffsetForStartOverhang has couple of issues
- The TextView does not propagate attribute to Layout builder.
-- Fixed by passing value to builder
- The right most offset is not shifted in case of RTL.
-- Fixed by applying right overhang in case of RTL direction.
- The offset is not correctly applied in case of multi paragraph
  multi directional text. e.g. first paragraph is LTR and second
  paragraph is RTL.
-- Fixed by applying shift amount for each paragraph. With this
   change, global shifting drawing offset no longer work. Instead
   shifting drawing offset for each paragraph.

Bug: 434885800
Test: atest CtsGraphicsTestCases
Test: atest CtsTextTestCases
Flag: com.android.text.flags.fix_shift_drawing_amount
Change-Id: I7d94515ff68948c39c96d59e221c91a1398b33cf
parent 06f8ee78
Loading
Loading
Loading
Loading
+23 −12
Original line number Original line Diff line number Diff line
@@ -719,6 +719,16 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback
    public void draw(Canvas c, Path highlight, Paint highlightpaint,
    public void draw(Canvas c, Path highlight, Paint highlightpaint,
                     int cursorOffset) {
                     int cursorOffset) {
        if (mDirect != null && highlight == null) {
        if (mDirect != null && highlight == null) {
            if (com.android.text.flags.Flags.fixShiftDrawingAmount()) {
                float leftShift = 0;
                if (getUseBoundsForWidth() && getShiftDrawingOffsetForStartOverhang()) {
                    RectF drawingRect = computeDrawingBoundingBox();
                    if (drawingRect.left < 0) {
                        leftShift = -drawingRect.left;
                    }
                }
                c.drawText(mDirect, leftShift, mBottom - mDesc, mPaint);
            } else {
                float leftShift = 0;
                float leftShift = 0;
                if (getUseBoundsForWidth() && getShiftDrawingOffsetForStartOverhang()) {
                if (getUseBoundsForWidth() && getShiftDrawingOffsetForStartOverhang()) {
                    RectF drawingRect = computeDrawingBoundingBox();
                    RectF drawingRect = computeDrawingBoundingBox();
@@ -731,10 +741,11 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback
                c.drawText(mDirect, 0, mBottom - mDesc, mPaint);
                c.drawText(mDirect, 0, mBottom - mDesc, mPaint);


                if (leftShift != 0) {
                if (leftShift != 0) {
                // Manually translate back to the original position because of b/324498002, using
                    // Manually translate back to the original position because of b/324498002,
                // save/restore disappears the toggle switch drawables.
                    // using save/restore disappears the toggle switch drawables.
                    c.translate(-leftShift, 0);
                    c.translate(-leftShift, 0);
                }
                }
            }
        } else {
        } else {
            super.draw(c, highlight, highlightpaint, cursorOffset);
            super.draw(c, highlight, highlightpaint, cursorOffset);
        }
        }
+40 −11
Original line number Original line Diff line number Diff line
@@ -264,6 +264,7 @@ public abstract class Layout {
            TextDirectionHeuristic textDir) {
            TextDirectionHeuristic textDir) {
        return getDesiredWidthWithLimit(source, start, end, paint, textDir, Float.MAX_VALUE, false);
        return getDesiredWidthWithLimit(source, start, end, paint, textDir, Float.MAX_VALUE, false);
    }
    }

    /**
    /**
     * Return how wide a layout must be in order to display the
     * Return how wide a layout must be in order to display the
     * specified text slice with one line per paragraph.
     * specified text slice with one line per paragraph.
@@ -275,7 +276,9 @@ public abstract class Layout {
            TextPaint paint, TextDirectionHeuristic textDir, float upperLimit,
            TextPaint paint, TextDirectionHeuristic textDir, float upperLimit,
            boolean useBoundsForWidth) {
            boolean useBoundsForWidth) {
        float need = 0;
        float need = 0;

        RectF bounds = useBoundsForWidth ? new RectF() : null;
        float left = 0;
        float right = 0;
        int next;
        int next;
        for (int i = start; i <= end; i = next) {
        for (int i = start; i <= end; i = next) {
            next = TextUtils.indexOf(source, '\n', i, end);
            next = TextUtils.indexOf(source, '\n', i, end);
@@ -284,7 +287,12 @@ public abstract class Layout {
                next = end;
                next = end;


            // note, omits trailing paragraph char
            // note, omits trailing paragraph char
            float w = measurePara(paint, source, i, next, textDir, useBoundsForWidth);
            float w = measurePara(paint, source, i, next, textDir, bounds);
            if (com.android.text.flags.Flags.fixShiftDrawingAmount() && useBoundsForWidth) {
                left = Math.min(bounds.left, left);
                right = Math.max(bounds.right, right);
                w = Math.max(right - left, w);
            }
            if (w > upperLimit) {
            if (w > upperLimit) {
                return upperLimit;
                return upperLimit;
            }
            }
@@ -500,13 +508,15 @@ public abstract class Layout {
            @Nullable Paint selectionPaint,
            @Nullable Paint selectionPaint,
            int cursorOffsetVertical) {
            int cursorOffsetVertical) {
        float leftShift = 0;
        float leftShift = 0;
        if (mUseBoundsForWidth && mShiftDrawingOffsetForStartOverhang) {
        if (!com.android.text.flags.Flags.fixShiftDrawingAmount()
                && mUseBoundsForWidth && mShiftDrawingOffsetForStartOverhang) {
            RectF drawingRect = computeDrawingBoundingBox();
            RectF drawingRect = computeDrawingBoundingBox();
            if (drawingRect.left < 0) {
            if (drawingRect.left < 0) {
                leftShift = -drawingRect.left;
                leftShift = -drawingRect.left;
                canvas.translate(leftShift, 0);
                canvas.translate(leftShift, 0);
            }
            }
        }
        }

        final long lineRange = getLineRangeForDraw(canvas);
        final long lineRange = getLineRangeForDraw(canvas);
        int firstLine = TextUtils.unpackRangeStartFromLong(lineRange);
        int firstLine = TextUtils.unpackRangeStartFromLong(lineRange);
        int lastLine = TextUtils.unpackRangeEndFromLong(lineRange);
        int lastLine = TextUtils.unpackRangeEndFromLong(lineRange);
@@ -529,7 +539,7 @@ public abstract class Layout {
                    cursorOffsetVertical, firstLine, lastLine);
                    cursorOffsetVertical, firstLine, lastLine);
        }
        }


        if (leftShift != 0) {
        if (!com.android.text.flags.Flags.fixShiftDrawingAmount() && leftShift != 0) {
            // Manually translate back to the original position because of b/324498002, using
            // Manually translate back to the original position because of b/324498002, using
            // save/restore disappears the toggle switch drawables.
            // save/restore disappears the toggle switch drawables.
            canvas.translate(-leftShift, 0);
            canvas.translate(-leftShift, 0);
@@ -786,6 +796,15 @@ public abstract class Layout {


        TextLine tl = TextLine.obtain();
        TextLine tl = TextLine.obtain();


        int leftOverhang = 0;
        int rightOverhang = 0;
        if (com.android.text.flags.Flags.fixShiftDrawingAmount()
                && mUseBoundsForWidth && mShiftDrawingOffsetForStartOverhang) {
            RectF drawingRect = computeDrawingBoundingBox();
            leftOverhang = (int) Math.ceil(Math.max(-drawingRect.left, 0));
            rightOverhang = (int) Math.ceil(Math.max(drawingRect.right - mWidth, 0));
        }

        // Draw the lines, one at a time.
        // Draw the lines, one at a time.
        // The baseline is the top of the following line minus the current line's descent.
        // The baseline is the top of the following line minus the current line's descent.
        for (int lineNum = firstLine; lineNum <= lastLine; lineNum++) {
        for (int lineNum = firstLine; lineNum <= lastLine; lineNum++) {
@@ -897,25 +916,25 @@ public abstract class Layout {
            if (align == Alignment.ALIGN_NORMAL) {
            if (align == Alignment.ALIGN_NORMAL) {
                if (dir == DIR_LEFT_TO_RIGHT) {
                if (dir == DIR_LEFT_TO_RIGHT) {
                    indentWidth = getIndentAdjust(lineNum, Alignment.ALIGN_LEFT);
                    indentWidth = getIndentAdjust(lineNum, Alignment.ALIGN_LEFT);
                    x = left + indentWidth;
                    x = left + indentWidth + leftOverhang;
                } else {
                } else {
                    indentWidth = -getIndentAdjust(lineNum, Alignment.ALIGN_RIGHT);
                    indentWidth = -getIndentAdjust(lineNum, Alignment.ALIGN_RIGHT);
                    x = right - indentWidth;
                    x = right - indentWidth - rightOverhang;
                }
                }
            } else {
            } else {
                int max = (int)getLineExtent(lineNum, tabStops, false);
                int max = (int)getLineExtent(lineNum, tabStops, false);
                if (align == Alignment.ALIGN_OPPOSITE) {
                if (align == Alignment.ALIGN_OPPOSITE) {
                    if (dir == DIR_LEFT_TO_RIGHT) {
                    if (dir == DIR_LEFT_TO_RIGHT) {
                        indentWidth = -getIndentAdjust(lineNum, Alignment.ALIGN_RIGHT);
                        indentWidth = -getIndentAdjust(lineNum, Alignment.ALIGN_RIGHT);
                        x = right - max - indentWidth;
                        x = right - max - indentWidth - rightOverhang;
                    } else {
                    } else {
                        indentWidth = getIndentAdjust(lineNum, Alignment.ALIGN_LEFT);
                        indentWidth = getIndentAdjust(lineNum, Alignment.ALIGN_LEFT);
                        x = left - max + indentWidth;
                        x = left - max + indentWidth + leftOverhang;
                    }
                    }
                } else { // Alignment.ALIGN_CENTER
                } else { // Alignment.ALIGN_CENTER
                    indentWidth = getIndentAdjust(lineNum, Alignment.ALIGN_CENTER);
                    indentWidth = getIndentAdjust(lineNum, Alignment.ALIGN_CENTER);
                    max = max & ~1;
                    max = max & ~1;
                    x = ((right + left - max) >> 1) + indentWidth;
                    x = ((right + left - max) >> 1) + indentWidth + leftOverhang;
                }
                }
            }
            }


@@ -1311,6 +1330,7 @@ public abstract class Layout {
        TextLine tl = TextLine.obtain();
        TextLine tl = TextLine.obtain();
        RectF rectF = new RectF();
        RectF rectF = new RectF();
        for (int line = 0; line < getLineCount(); ++line) {
        for (int line = 0; line < getLineCount(); ++line) {
            rectF.setEmpty();
            final int start = getLineStart(line);
            final int start = getLineStart(line);
            final int end = getLineVisibleEnd(line);
            final int end = getLineVisibleEnd(line);


@@ -3274,9 +3294,12 @@ public abstract class Layout {
    }
    }


    private static float measurePara(TextPaint paint, CharSequence text, int start, int end,
    private static float measurePara(TextPaint paint, CharSequence text, int start, int end,
            TextDirectionHeuristic textDir, boolean useBoundsForWidth) {
            TextDirectionHeuristic textDir, RectF bounds) {
        MeasuredParagraph mt = null;
        MeasuredParagraph mt = null;
        TextLine tl = TextLine.obtain();
        TextLine tl = TextLine.obtain();
        if (bounds != null) {
            bounds.setEmpty();
        }
        try {
        try {
            mt = MeasuredParagraph.buildForBidi(text, start, end, textDir, mt);
            mt = MeasuredParagraph.buildForBidi(text, start, end, textDir, mt);
            final char[] chars = mt.getChars();
            final char[] chars = mt.getChars();
@@ -3314,7 +3337,13 @@ public abstract class Layout {
            tl.set(paint, text, start, end, dir, directions, hasTabs, tabStops,
            tl.set(paint, text, start, end, dir, directions, hasTabs, tabStops,
                    0 /* ellipsisStart */, 0 /* ellipsisEnd */,
                    0 /* ellipsisStart */, 0 /* ellipsisEnd */,
                    false /* use fallback line spacing. unused */);
                    false /* use fallback line spacing. unused */);
            return margin + Math.abs(tl.metrics(null, null, useBoundsForWidth, null));
            float w = tl.metrics(null, bounds, bounds != null, null);
            if (bounds != null) {
                if (w < 0) { // RTL
                    bounds.offset(-w, 0f);
                }
            }
            return margin + Math.abs(w);
        } finally {
        } finally {
            TextLine.recycle(tl);
            TextLine.recycle(tl);
            if (mt != null) {
            if (mt != null) {
+3 −0
Original line number Original line Diff line number Diff line
@@ -1359,6 +1359,9 @@ public class TextLine {
            if (drawBounds != null && mTmpRectForPaintAPI == null) {
            if (drawBounds != null && mTmpRectForPaintAPI == null) {
                mTmpRectForPaintAPI = new RectF();
                mTmpRectForPaintAPI = new RectF();
            }
            }
            if (drawBounds != null) {
                mTmpRectForPaintAPI.setEmpty();
            }
            totalWidth = getRunAdvance(wp, start, end, contextStart, contextEnd, runIsRtl, offset,
            totalWidth = getRunAdvance(wp, start, end, contextStart, contextEnd, runIsRtl, offset,
                    advances, advancesIndex, drawBounds == null ? null : mTmpRectForPaintAPI,
                    advances, advancesIndex, drawBounds == null ? null : mTmpRectForPaintAPI,
                    lineInfo);
                    lineInfo);
+8 −0
Original line number Original line Diff line number Diff line
@@ -255,3 +255,11 @@ flag {
  bug: "417989314"
  bug: "417989314"


}
}

flag {
  name: "fix_shift_drawing_amount"
  namespace: "text"
  description: "Fixing shift_drawing_offset_for_start_overhang that had an issue."
  bug: "434885800"

}
+22 −1
Original line number Original line Diff line number Diff line
@@ -11049,6 +11049,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                        .setUseBoundsForWidth(mUseBoundsForWidth)
                        .setUseBoundsForWidth(mUseBoundsForWidth)
                        .setMinimumFontMetrics(getResolvedMinimumFontMetrics());
                        .setMinimumFontMetrics(getResolvedMinimumFontMetrics());
                if (com.android.text.flags.Flags.fixShiftDrawingAmount()) {
                    builder.setShiftDrawingOffsetForStartOverhang(
                            mShiftDrawingOffsetForStartOverhang);
                }
                if (shouldEllipsize) {
                if (shouldEllipsize) {
                    builder.setEllipsize(mEllipsize)
                    builder.setEllipsize(mEllipsize)
                            .setEllipsizedWidth(ellipsisWidth);
                            .setEllipsizedWidth(ellipsisWidth);
@@ -11114,6 +11119,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                    .setEllipsize(getKeyListener() == null ? effectiveEllipsize : null)
                    .setEllipsize(getKeyListener() == null ? effectiveEllipsize : null)
                    .setEllipsizedWidth(ellipsisWidth)
                    .setEllipsizedWidth(ellipsisWidth)
                    .setMinimumFontMetrics(getResolvedMinimumFontMetrics());
                    .setMinimumFontMetrics(getResolvedMinimumFontMetrics());
            if (com.android.text.flags.Flags.fixShiftDrawingAmount()) {
                builder.setShiftDrawingOffsetForStartOverhang(
                        mShiftDrawingOffsetForStartOverhang);
            }
            result = builder.build();
            result = builder.build();
        } else {
        } else {
            if (boring == UNKNOWN_BORING) {
            if (boring == UNKNOWN_BORING) {
@@ -11198,6 +11207,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                            mLineBreakStyle, mLineBreakWordStyle))
                            mLineBreakStyle, mLineBreakWordStyle))
                    .setUseBoundsForWidth(mUseBoundsForWidth)
                    .setUseBoundsForWidth(mUseBoundsForWidth)
                    .setMinimumFontMetrics(getResolvedMinimumFontMetrics());
                    .setMinimumFontMetrics(getResolvedMinimumFontMetrics());
            if (com.android.text.flags.Flags.fixShiftDrawingAmount()) {
                builder.setShiftDrawingOffsetForStartOverhang(mShiftDrawingOffsetForStartOverhang);
            }
            if (shouldEllipsize) {
            if (shouldEllipsize) {
                builder.setEllipsize(effectiveEllipsize)
                builder.setEllipsize(effectiveEllipsize)
                        .setEllipsizedWidth(ellipsisWidth);
                        .setEllipsizedWidth(ellipsisWidth);
@@ -11231,6 +11244,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
    }
    }
    private static int desired(Layout layout, boolean useBoundsForWidth) {
    private static int desired(Layout layout, boolean useBoundsForWidth) {
        if (com.android.text.flags.Flags.fixShiftDrawingAmount() && useBoundsForWidth) {
            return -1;
        }
        int n = layout.getLineCount();
        int n = layout.getLineCount();
        CharSequence text = layout.getText();
        CharSequence text = layout.getText();
        float max = 0;
        float max = 0;
@@ -11248,7 +11264,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            max = Math.max(max, layout.getLineMax(i));
            max = Math.max(max, layout.getLineMax(i));
        }
        }
        if (useBoundsForWidth) {
        if (!com.android.text.flags.Flags.fixShiftDrawingAmount() && useBoundsForWidth) {
            max = Math.max(max, layout.computeDrawingBoundingBox().width());
            max = Math.max(max, layout.computeDrawingBoundingBox().width());
        }
        }
@@ -11584,6 +11600,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                .setUseBoundsForWidth(mUseBoundsForWidth)
                .setUseBoundsForWidth(mUseBoundsForWidth)
                .setMinimumFontMetrics(getResolvedMinimumFontMetrics());
                .setMinimumFontMetrics(getResolvedMinimumFontMetrics());
        if (com.android.text.flags.Flags.fixShiftDrawingAmount()) {
            layoutBuilder.setShiftDrawingOffsetForStartOverhang(
                    mShiftDrawingOffsetForStartOverhang);
        }
        final StaticLayout layout = layoutBuilder.build();
        final StaticLayout layout = layoutBuilder.build();
        // Lines overflow.
        // Lines overflow.