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

Commit fd5bc01f authored by Gilles Debunne's avatar Gilles Debunne
Browse files

Better horizontal internal scroll handling in Text.

Bug 6378843

Corrects CL 183460, which would clip text with a width greater than
twice the TextView's width.

Internal horizontal translation is now handled in a similar way to
vertical scrolling.

Internal scrolling is indeed handled by the TextView, which translates
the canvas and sets the clipping bounds accordingly.

When drawing the internal DL, we tighten the horizontal bounds like we
did for the vertical bounds using top and bottom. As in Touch.java, we
use the getHorizontallyScrolling() method to know if we indeed have to
measure the actual text width.  If there is no horizontal scrolling we
use the TextView's width as a safe upper estimate in order to avoid an
actual computation. Note that horizontal scrolling is typically only
used for long single-lined text, so that the measurement loop is quick.

As a result, the internal DLs represent the entire text, and there is no
need to invalidate them when an internal scrolling takes place. This
behavior replaces the draw-only-what-is-needed we had before, but is
more consistent with what we do for long texts inside of a ScrollView
with no noticeable performance change, even on very long text.

Change-Id: I47c24c0ae988547d4f1e9f87d136225c93a3056d
parent c9ca7f38
Loading
Loading
Loading
Loading
+19 −16
Original line number Diff line number Diff line
@@ -1223,8 +1223,6 @@ public class Editor {

    private void drawHardwareAccelerated(Canvas canvas, Layout layout, Path highlight,
            Paint highlightPaint, int cursorOffsetVertical) {
        final int width = mTextView.getWidth();

        final long lineRange = layout.getLineRangeForDraw(canvas);
        int firstLine = TextUtils.unpackRangeStartFromLong(lineRange);
        int lastLine = TextUtils.unpackRangeEndFromLong(lineRange);
@@ -1243,10 +1241,6 @@ public class Editor {
            int[] blockIndices = dynamicLayout.getBlockIndices();
            final int numberOfBlocks = dynamicLayout.getNumberOfBlocks();

            final int scrollX = mTextView.getScrollX();
            final int scrollY = mTextView.getScrollY();
            canvas.translate(scrollX, scrollY);
            
            int endOfPreviousBlock = -1;
            int searchStartIndex = 0;
            for (int i = 0; i < numberOfBlocks; i++) {
@@ -1274,34 +1268,43 @@ public class Editor {
                    final int blockBeginLine = endOfPreviousBlock + 1;
                    final int top = layout.getLineTop(blockBeginLine);
                    final int bottom = layout.getLineBottom(blockEndLine);
                    int left = 0;
                    int right = mTextView.getWidth();
                    if (mTextView.getHorizontallyScrolling()) {
                        float min = Float.MAX_VALUE;
                        float max = Float.MIN_VALUE;
                        for (int line = blockBeginLine; line <= blockEndLine; line++) {
                            min = Math.min(min, layout.getLineLeft(line));
                            max = Math.max(max, layout.getLineRight(line));
                        }
                        left = (int) min;
                        right = (int) (max + 0.5f);
                    }

                    final HardwareCanvas hardwareCanvas = blockDisplayList.start();
                    try {
                        hardwareCanvas.setViewport(width, bottom - top);
                        // Tighten the bounds of the viewport to the actual text size
                        hardwareCanvas.setViewport(right - left, bottom - top);
                        // The dirty rect should always be null for a display list
                        hardwareCanvas.onPreDraw(null);
                        // drawText is always relative to TextView's origin, this translation brings
                        // this range of text back to the top of the viewport
                        hardwareCanvas.translate(-scrollX, -top);
                        // this range of text back to the top left corner of the viewport
                        hardwareCanvas.translate(-left, -top);
                        layout.drawText(hardwareCanvas, blockBeginLine, blockEndLine);
                        hardwareCanvas.translate(scrollX, top);
                        // No need to untranslate, previous context is popped after drawDisplayList
                    } finally {
                        hardwareCanvas.onPostDraw();
                        blockDisplayList.end();
                        blockDisplayList.setLeftTopRightBottom(0, top, width, bottom);
                        blockDisplayList.setLeftTopRightBottom(left, top, right, bottom);
                        // Same as drawDisplayList below, handled by our TextView's parent
                        blockDisplayList.setClipChildren(false);
                    }
                }

                // TODO When View.USE_DISPLAY_LIST_PROPERTIES is the only code path, the
                // width and height parameters should be removed and the bounds set above in
                // setLeftTopRightBottom should be used instead for quick rejection.
                ((HardwareCanvas) canvas).drawDisplayList(blockDisplayList, null,
                        0 /* no child clipping, our TextView parent enforces it */);
                endOfPreviousBlock = blockEndLine;

                canvas.translate(-scrollX, -scrollY);
                endOfPreviousBlock = blockEndLine;
            }
        } else {
            // Boring layout is used for empty and hint text