Search in sources :

Example 6 with DynamicLayout

use of android.text.DynamicLayout in project android_frameworks_base by DirtyUnicorns.

the class TextView method makeSingleLayout.

/**
     * @hide
     */
protected Layout makeSingleLayout(int wantWidth, BoringLayout.Metrics boring, int ellipsisWidth, Layout.Alignment alignment, boolean shouldEllipsize, TruncateAt effectiveEllipsize, boolean useSaved) {
    Layout result = null;
    if (mText instanceof Spannable) {
        result = new DynamicLayout(mText, mTransformed, mTextPaint, wantWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd, mIncludePad, mBreakStrategy, mHyphenationFrequency, getKeyListener() == null ? effectiveEllipsize : null, ellipsisWidth);
    } else {
        if (boring == UNKNOWN_BORING) {
            boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir, mBoring);
            if (boring != null) {
                mBoring = boring;
            }
        }
        if (boring != null) {
            if (boring.width <= wantWidth && (effectiveEllipsize == null || boring.width <= ellipsisWidth)) {
                if (useSaved && mSavedLayout != null) {
                    result = mSavedLayout.replaceOrMake(mTransformed, mTextPaint, wantWidth, alignment, mSpacingMult, mSpacingAdd, boring, mIncludePad);
                } else {
                    result = BoringLayout.make(mTransformed, mTextPaint, wantWidth, alignment, mSpacingMult, mSpacingAdd, boring, mIncludePad);
                }
                if (useSaved) {
                    mSavedLayout = (BoringLayout) result;
                }
            } else if (shouldEllipsize && boring.width <= wantWidth) {
                if (useSaved && mSavedLayout != null) {
                    result = mSavedLayout.replaceOrMake(mTransformed, mTextPaint, wantWidth, alignment, mSpacingMult, mSpacingAdd, boring, mIncludePad, effectiveEllipsize, ellipsisWidth);
                } else {
                    result = BoringLayout.make(mTransformed, mTextPaint, wantWidth, alignment, mSpacingMult, mSpacingAdd, boring, mIncludePad, effectiveEllipsize, ellipsisWidth);
                }
            }
        }
    }
    if (result == null) {
        StaticLayout.Builder builder = StaticLayout.Builder.obtain(mTransformed, 0, mTransformed.length(), mTextPaint, wantWidth).setAlignment(alignment).setTextDirection(mTextDir).setLineSpacing(mSpacingAdd, mSpacingMult).setIncludePad(mIncludePad).setBreakStrategy(mBreakStrategy).setHyphenationFrequency(mHyphenationFrequency);
        if (shouldEllipsize) {
            builder.setEllipsize(effectiveEllipsize).setEllipsizedWidth(ellipsisWidth).setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
        }
        // TODO: explore always setting maxLines
        result = builder.build();
    }
    return result;
}
Also used : BoringLayout(android.text.BoringLayout) Layout(android.text.Layout) StaticLayout(android.text.StaticLayout) DynamicLayout(android.text.DynamicLayout) StaticLayout(android.text.StaticLayout) DynamicLayout(android.text.DynamicLayout) Spannable(android.text.Spannable)

Example 7 with DynamicLayout

use of android.text.DynamicLayout in project android_frameworks_base by AOSPA.

the class Editor method drawHardwareAccelerated.

private void drawHardwareAccelerated(Canvas canvas, Layout layout, Path highlight, Paint highlightPaint, int cursorOffsetVertical) {
    final long lineRange = layout.getLineRangeForDraw(canvas);
    int firstLine = TextUtils.unpackRangeStartFromLong(lineRange);
    int lastLine = TextUtils.unpackRangeEndFromLong(lineRange);
    if (lastLine < 0)
        return;
    layout.drawBackground(canvas, highlight, highlightPaint, cursorOffsetVertical, firstLine, lastLine);
    if (layout instanceof DynamicLayout) {
        if (mTextRenderNodes == null) {
            mTextRenderNodes = ArrayUtils.emptyArray(TextRenderNode.class);
        }
        DynamicLayout dynamicLayout = (DynamicLayout) layout;
        int[] blockEndLines = dynamicLayout.getBlockEndLines();
        int[] blockIndices = dynamicLayout.getBlockIndices();
        final int numberOfBlocks = dynamicLayout.getNumberOfBlocks();
        final int indexFirstChangedBlock = dynamicLayout.getIndexFirstChangedBlock();
        int endOfPreviousBlock = -1;
        int searchStartIndex = 0;
        for (int i = 0; i < numberOfBlocks; i++) {
            int blockEndLine = blockEndLines[i];
            int blockIndex = blockIndices[i];
            final boolean blockIsInvalid = blockIndex == DynamicLayout.INVALID_BLOCK_INDEX;
            if (blockIsInvalid) {
                blockIndex = getAvailableDisplayListIndex(blockIndices, numberOfBlocks, searchStartIndex);
                // Note how dynamic layout's internal block indices get updated from Editor
                blockIndices[i] = blockIndex;
                if (mTextRenderNodes[blockIndex] != null) {
                    mTextRenderNodes[blockIndex].isDirty = true;
                }
                searchStartIndex = blockIndex + 1;
            }
            if (mTextRenderNodes[blockIndex] == null) {
                mTextRenderNodes[blockIndex] = new TextRenderNode("Text " + blockIndex);
            }
            final boolean blockDisplayListIsInvalid = mTextRenderNodes[blockIndex].needsRecord();
            RenderNode blockDisplayList = mTextRenderNodes[blockIndex].renderNode;
            if (i >= indexFirstChangedBlock || blockDisplayListIsInvalid) {
                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);
                }
                // Rebuild display list if it is invalid
                if (blockDisplayListIsInvalid) {
                    final DisplayListCanvas displayListCanvas = blockDisplayList.start(right - left, bottom - top);
                    try {
                        // drawText is always relative to TextView's origin, this translation
                        // brings this range of text back to the top left corner of the viewport
                        displayListCanvas.translate(-left, -top);
                        layout.drawText(displayListCanvas, blockBeginLine, blockEndLine);
                        mTextRenderNodes[blockIndex].isDirty = false;
                    // No need to untranslate, previous context is popped after
                    // drawDisplayList
                    } finally {
                        blockDisplayList.end(displayListCanvas);
                        // Same as drawDisplayList below, handled by our TextView's parent
                        blockDisplayList.setClipToBounds(false);
                    }
                }
                // Valid disply list whose index is >= indexFirstChangedBlock
                // only needs to update its drawing location.
                blockDisplayList.setLeftTopRightBottom(left, top, right, bottom);
            }
            ((DisplayListCanvas) canvas).drawRenderNode(blockDisplayList);
            endOfPreviousBlock = blockEndLine;
        }
        dynamicLayout.setIndexFirstChangedBlock(numberOfBlocks);
    } else {
        // Boring layout is used for empty and hint text
        layout.drawText(canvas, firstLine, lastLine);
    }
}
Also used : RenderNode(android.view.RenderNode) DisplayListCanvas(android.view.DisplayListCanvas) DynamicLayout(android.text.DynamicLayout) Paint(android.graphics.Paint)

Example 8 with DynamicLayout

use of android.text.DynamicLayout in project android_frameworks_base by AOSPA.

the class TextView method makeSingleLayout.

/**
     * @hide
     */
protected Layout makeSingleLayout(int wantWidth, BoringLayout.Metrics boring, int ellipsisWidth, Layout.Alignment alignment, boolean shouldEllipsize, TruncateAt effectiveEllipsize, boolean useSaved) {
    Layout result = null;
    if (mText instanceof Spannable) {
        result = new DynamicLayout(mText, mTransformed, mTextPaint, wantWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd, mIncludePad, mBreakStrategy, mHyphenationFrequency, getKeyListener() == null ? effectiveEllipsize : null, ellipsisWidth);
    } else {
        if (boring == UNKNOWN_BORING) {
            boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir, mBoring);
            if (boring != null) {
                mBoring = boring;
            }
        }
        if (boring != null) {
            if (boring.width <= wantWidth && (effectiveEllipsize == null || boring.width <= ellipsisWidth)) {
                if (useSaved && mSavedLayout != null) {
                    result = mSavedLayout.replaceOrMake(mTransformed, mTextPaint, wantWidth, alignment, mSpacingMult, mSpacingAdd, boring, mIncludePad);
                } else {
                    result = BoringLayout.make(mTransformed, mTextPaint, wantWidth, alignment, mSpacingMult, mSpacingAdd, boring, mIncludePad);
                }
                if (useSaved) {
                    mSavedLayout = (BoringLayout) result;
                }
            } else if (shouldEllipsize && boring.width <= wantWidth) {
                if (useSaved && mSavedLayout != null) {
                    result = mSavedLayout.replaceOrMake(mTransformed, mTextPaint, wantWidth, alignment, mSpacingMult, mSpacingAdd, boring, mIncludePad, effectiveEllipsize, ellipsisWidth);
                } else {
                    result = BoringLayout.make(mTransformed, mTextPaint, wantWidth, alignment, mSpacingMult, mSpacingAdd, boring, mIncludePad, effectiveEllipsize, ellipsisWidth);
                }
            }
        }
    }
    if (result == null) {
        StaticLayout.Builder builder = StaticLayout.Builder.obtain(mTransformed, 0, mTransformed.length(), mTextPaint, wantWidth).setAlignment(alignment).setTextDirection(mTextDir).setLineSpacing(mSpacingAdd, mSpacingMult).setIncludePad(mIncludePad).setBreakStrategy(mBreakStrategy).setHyphenationFrequency(mHyphenationFrequency);
        if (shouldEllipsize) {
            builder.setEllipsize(effectiveEllipsize).setEllipsizedWidth(ellipsisWidth).setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
        }
        // TODO: explore always setting maxLines
        result = builder.build();
    }
    return result;
}
Also used : BoringLayout(android.text.BoringLayout) Layout(android.text.Layout) StaticLayout(android.text.StaticLayout) DynamicLayout(android.text.DynamicLayout) StaticLayout(android.text.StaticLayout) DynamicLayout(android.text.DynamicLayout) Spannable(android.text.Spannable)

Example 9 with DynamicLayout

use of android.text.DynamicLayout in project android_frameworks_base by ResurrectionRemix.

the class Editor method drawHardwareAccelerated.

private void drawHardwareAccelerated(Canvas canvas, Layout layout, Path highlight, Paint highlightPaint, int cursorOffsetVertical) {
    final long lineRange = layout.getLineRangeForDraw(canvas);
    int firstLine = TextUtils.unpackRangeStartFromLong(lineRange);
    int lastLine = TextUtils.unpackRangeEndFromLong(lineRange);
    if (lastLine < 0)
        return;
    layout.drawBackground(canvas, highlight, highlightPaint, cursorOffsetVertical, firstLine, lastLine);
    if (layout instanceof DynamicLayout) {
        if (mTextRenderNodes == null) {
            mTextRenderNodes = ArrayUtils.emptyArray(TextRenderNode.class);
        }
        DynamicLayout dynamicLayout = (DynamicLayout) layout;
        int[] blockEndLines = dynamicLayout.getBlockEndLines();
        int[] blockIndices = dynamicLayout.getBlockIndices();
        final int numberOfBlocks = dynamicLayout.getNumberOfBlocks();
        final int indexFirstChangedBlock = dynamicLayout.getIndexFirstChangedBlock();
        int endOfPreviousBlock = -1;
        int searchStartIndex = 0;
        for (int i = 0; i < numberOfBlocks; i++) {
            int blockEndLine = blockEndLines[i];
            int blockIndex = blockIndices[i];
            final boolean blockIsInvalid = blockIndex == DynamicLayout.INVALID_BLOCK_INDEX;
            if (blockIsInvalid) {
                blockIndex = getAvailableDisplayListIndex(blockIndices, numberOfBlocks, searchStartIndex);
                // Note how dynamic layout's internal block indices get updated from Editor
                blockIndices[i] = blockIndex;
                if (mTextRenderNodes[blockIndex] != null) {
                    mTextRenderNodes[blockIndex].isDirty = true;
                }
                searchStartIndex = blockIndex + 1;
            }
            if (mTextRenderNodes[blockIndex] == null) {
                mTextRenderNodes[blockIndex] = new TextRenderNode("Text " + blockIndex);
            }
            final boolean blockDisplayListIsInvalid = mTextRenderNodes[blockIndex].needsRecord();
            RenderNode blockDisplayList = mTextRenderNodes[blockIndex].renderNode;
            if (i >= indexFirstChangedBlock || blockDisplayListIsInvalid) {
                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);
                }
                // Rebuild display list if it is invalid
                if (blockDisplayListIsInvalid) {
                    final DisplayListCanvas displayListCanvas = blockDisplayList.start(right - left, bottom - top);
                    try {
                        // drawText is always relative to TextView's origin, this translation
                        // brings this range of text back to the top left corner of the viewport
                        displayListCanvas.translate(-left, -top);
                        layout.drawText(displayListCanvas, blockBeginLine, blockEndLine);
                        mTextRenderNodes[blockIndex].isDirty = false;
                    // No need to untranslate, previous context is popped after
                    // drawDisplayList
                    } finally {
                        blockDisplayList.end(displayListCanvas);
                        // Same as drawDisplayList below, handled by our TextView's parent
                        blockDisplayList.setClipToBounds(false);
                    }
                }
                // Valid disply list whose index is >= indexFirstChangedBlock
                // only needs to update its drawing location.
                blockDisplayList.setLeftTopRightBottom(left, top, right, bottom);
            }
            ((DisplayListCanvas) canvas).drawRenderNode(blockDisplayList);
            endOfPreviousBlock = blockEndLine;
        }
        dynamicLayout.setIndexFirstChangedBlock(numberOfBlocks);
    } else {
        // Boring layout is used for empty and hint text
        layout.drawText(canvas, firstLine, lastLine);
    }
}
Also used : RenderNode(android.view.RenderNode) DisplayListCanvas(android.view.DisplayListCanvas) DynamicLayout(android.text.DynamicLayout) Paint(android.graphics.Paint)

Example 10 with DynamicLayout

use of android.text.DynamicLayout in project android_frameworks_base by crdroidandroid.

the class Editor method invalidateTextDisplayList.

/**
     * Invalidates all the sub-display lists that overlap the specified character range
     */
void invalidateTextDisplayList(Layout layout, int start, int end) {
    if (mTextRenderNodes != null && layout instanceof DynamicLayout) {
        final int firstLine = layout.getLineForOffset(start);
        final int lastLine = layout.getLineForOffset(end);
        DynamicLayout dynamicLayout = (DynamicLayout) layout;
        int[] blockEndLines = dynamicLayout.getBlockEndLines();
        int[] blockIndices = dynamicLayout.getBlockIndices();
        final int numberOfBlocks = dynamicLayout.getNumberOfBlocks();
        int i = 0;
        // Skip the blocks before firstLine
        while (i < numberOfBlocks) {
            if (blockEndLines[i] >= firstLine)
                break;
            i++;
        }
        // Invalidate all subsequent blocks until lastLine is passed
        while (i < numberOfBlocks) {
            final int blockIndex = blockIndices[i];
            if (blockIndex != DynamicLayout.INVALID_BLOCK_INDEX) {
                mTextRenderNodes[blockIndex].isDirty = true;
            }
            if (blockEndLines[i] >= lastLine)
                break;
            i++;
        }
    }
}
Also used : DynamicLayout(android.text.DynamicLayout) Paint(android.graphics.Paint)

Aggregations

DynamicLayout (android.text.DynamicLayout)22 Paint (android.graphics.Paint)13 BoringLayout (android.text.BoringLayout)5 Layout (android.text.Layout)5 Spannable (android.text.Spannable)5 StaticLayout (android.text.StaticLayout)5 DisplayListCanvas (android.view.DisplayListCanvas)5 RenderNode (android.view.RenderNode)5 TextPaint (android.text.TextPaint)3 SpannableStringBuilder (android.text.SpannableStringBuilder)2 SuppressLint (android.annotation.SuppressLint)1 DisplayList (android.view.DisplayList)1 HardwareCanvas (android.view.HardwareCanvas)1