Search in sources :

Example 16 with LeadingMarginSpan

use of android.text.style.LeadingMarginSpan in project platform_frameworks_base by android.

the class Layout method getParagraphLeadingMargin.

/**
     * Returns the effective leading margin (unsigned) for this line,
     * taking into account LeadingMarginSpan and LeadingMarginSpan2.
     * @param line the line index
     * @return the leading margin of this line
     */
private int getParagraphLeadingMargin(int line) {
    if (!mSpannedText) {
        return 0;
    }
    Spanned spanned = (Spanned) mText;
    int lineStart = getLineStart(line);
    int lineEnd = getLineEnd(line);
    int spanEnd = spanned.nextSpanTransition(lineStart, lineEnd, LeadingMarginSpan.class);
    LeadingMarginSpan[] spans = getParagraphSpans(spanned, lineStart, spanEnd, LeadingMarginSpan.class);
    if (spans.length == 0) {
        // no leading margin span;
        return 0;
    }
    int margin = 0;
    boolean isFirstParaLine = lineStart == 0 || spanned.charAt(lineStart - 1) == '\n';
    boolean useFirstLineMargin = isFirstParaLine;
    for (int i = 0; i < spans.length; i++) {
        if (spans[i] instanceof LeadingMarginSpan2) {
            int spStart = spanned.getSpanStart(spans[i]);
            int spanLine = getLineForOffset(spStart);
            int count = ((LeadingMarginSpan2) spans[i]).getLeadingMarginLineCount();
            // if there is more than one LeadingMarginSpan2, use the count that is greatest
            useFirstLineMargin |= line < spanLine + count;
        }
    }
    for (int i = 0; i < spans.length; i++) {
        LeadingMarginSpan span = spans[i];
        margin += span.getLeadingMargin(useFirstLineMargin);
    }
    return margin;
}
Also used : LeadingMarginSpan2(android.text.style.LeadingMarginSpan.LeadingMarginSpan2) LeadingMarginSpan(android.text.style.LeadingMarginSpan) Paint(android.graphics.Paint)

Example 17 with LeadingMarginSpan

use of android.text.style.LeadingMarginSpan in project platform_frameworks_base by android.

the class StaticLayout method generate.

/* package */
void generate(Builder b, boolean includepad, boolean trackpad) {
    CharSequence source = b.mText;
    int bufStart = b.mStart;
    int bufEnd = b.mEnd;
    TextPaint paint = b.mPaint;
    int outerWidth = b.mWidth;
    TextDirectionHeuristic textDir = b.mTextDir;
    float spacingmult = b.mSpacingMult;
    float spacingadd = b.mSpacingAdd;
    float ellipsizedWidth = b.mEllipsizedWidth;
    TextUtils.TruncateAt ellipsize = b.mEllipsize;
    // TODO: move to builder to avoid allocation costs
    LineBreaks lineBreaks = new LineBreaks();
    // store span end locations
    int[] spanEndCache = new int[4];
    // store fontMetrics per span range
    // must be a multiple of 4 (and > 0) (store top, bottom, ascent, and descent per range)
    int[] fmCache = new int[4 * 4];
    // TODO: also respect LocaleSpan within the text
    b.setLocale(paint.getTextLocale());
    mLineCount = 0;
    int v = 0;
    boolean needMultiply = (spacingmult != 1 || spacingadd != 0);
    Paint.FontMetricsInt fm = b.mFontMetricsInt;
    int[] chooseHtv = null;
    MeasuredText measured = b.mMeasuredText;
    Spanned spanned = null;
    if (source instanceof Spanned)
        spanned = (Spanned) source;
    int paraEnd;
    for (int paraStart = bufStart; paraStart <= bufEnd; paraStart = paraEnd) {
        paraEnd = TextUtils.indexOf(source, CHAR_NEW_LINE, paraStart, bufEnd);
        if (paraEnd < 0)
            paraEnd = bufEnd;
        else
            paraEnd++;
        int firstWidthLineCount = 1;
        int firstWidth = outerWidth;
        int restWidth = outerWidth;
        LineHeightSpan[] chooseHt = null;
        if (spanned != null) {
            LeadingMarginSpan[] sp = getParagraphSpans(spanned, paraStart, paraEnd, LeadingMarginSpan.class);
            for (int i = 0; i < sp.length; i++) {
                LeadingMarginSpan lms = sp[i];
                firstWidth -= sp[i].getLeadingMargin(true);
                restWidth -= sp[i].getLeadingMargin(false);
                // leading margin spans, not just this particular one
                if (lms instanceof LeadingMarginSpan2) {
                    LeadingMarginSpan2 lms2 = (LeadingMarginSpan2) lms;
                    firstWidthLineCount = Math.max(firstWidthLineCount, lms2.getLeadingMarginLineCount());
                }
            }
            chooseHt = getParagraphSpans(spanned, paraStart, paraEnd, LineHeightSpan.class);
            if (chooseHt.length == 0) {
                // So that out() would not assume it has any contents
                chooseHt = null;
            } else {
                if (chooseHtv == null || chooseHtv.length < chooseHt.length) {
                    chooseHtv = ArrayUtils.newUnpaddedIntArray(chooseHt.length);
                }
                for (int i = 0; i < chooseHt.length; i++) {
                    int o = spanned.getSpanStart(chooseHt[i]);
                    if (o < paraStart) {
                        // starts in this layout, before the
                        // current paragraph
                        chooseHtv[i] = getLineTop(getLineForOffset(o));
                    } else {
                        // starts in this paragraph
                        chooseHtv[i] = v;
                    }
                }
            }
        }
        measured.setPara(source, paraStart, paraEnd, textDir, b);
        char[] chs = measured.mChars;
        float[] widths = measured.mWidths;
        byte[] chdirs = measured.mLevels;
        int dir = measured.mDir;
        boolean easy = measured.mEasy;
        // tab stop locations
        int[] variableTabStops = null;
        if (spanned != null) {
            TabStopSpan[] spans = getParagraphSpans(spanned, paraStart, paraEnd, TabStopSpan.class);
            if (spans.length > 0) {
                int[] stops = new int[spans.length];
                for (int i = 0; i < spans.length; i++) {
                    stops[i] = spans[i].getTabStop();
                }
                Arrays.sort(stops, 0, stops.length);
                variableTabStops = stops;
            }
        }
        nSetupParagraph(b.mNativePtr, chs, paraEnd - paraStart, firstWidth, firstWidthLineCount, restWidth, variableTabStops, TAB_INCREMENT, b.mBreakStrategy, b.mHyphenationFrequency);
        if (mLeftIndents != null || mRightIndents != null) {
            // TODO(raph) performance: it would be better to do this once per layout rather
            // than once per paragraph, but that would require a change to the native
            // interface.
            int leftLen = mLeftIndents == null ? 0 : mLeftIndents.length;
            int rightLen = mRightIndents == null ? 0 : mRightIndents.length;
            int indentsLen = Math.max(1, Math.max(leftLen, rightLen) - mLineCount);
            int[] indents = new int[indentsLen];
            for (int i = 0; i < indentsLen; i++) {
                int leftMargin = mLeftIndents == null ? 0 : mLeftIndents[Math.min(i + mLineCount, leftLen - 1)];
                int rightMargin = mRightIndents == null ? 0 : mRightIndents[Math.min(i + mLineCount, rightLen - 1)];
                indents[i] = leftMargin + rightMargin;
            }
            nSetIndents(b.mNativePtr, indents);
        }
        // measurement has to be done before performing line breaking
        // but we don't want to recompute fontmetrics or span ranges the
        // second time, so we cache those and then use those stored values
        int fmCacheCount = 0;
        int spanEndCacheCount = 0;
        for (int spanStart = paraStart, spanEnd; spanStart < paraEnd; spanStart = spanEnd) {
            if (fmCacheCount * 4 >= fmCache.length) {
                int[] grow = new int[fmCacheCount * 4 * 2];
                System.arraycopy(fmCache, 0, grow, 0, fmCacheCount * 4);
                fmCache = grow;
            }
            if (spanEndCacheCount >= spanEndCache.length) {
                int[] grow = new int[spanEndCacheCount * 2];
                System.arraycopy(spanEndCache, 0, grow, 0, spanEndCacheCount);
                spanEndCache = grow;
            }
            if (spanned == null) {
                spanEnd = paraEnd;
                int spanLen = spanEnd - spanStart;
                measured.addStyleRun(paint, spanLen, fm);
            } else {
                spanEnd = spanned.nextSpanTransition(spanStart, paraEnd, MetricAffectingSpan.class);
                int spanLen = spanEnd - spanStart;
                MetricAffectingSpan[] spans = spanned.getSpans(spanStart, spanEnd, MetricAffectingSpan.class);
                spans = TextUtils.removeEmptySpans(spans, spanned, MetricAffectingSpan.class);
                measured.addStyleRun(paint, spans, spanLen, fm);
            }
            // the order of storage here (top, bottom, ascent, descent) has to match the code below
            // where these values are retrieved
            fmCache[fmCacheCount * 4 + 0] = fm.top;
            fmCache[fmCacheCount * 4 + 1] = fm.bottom;
            fmCache[fmCacheCount * 4 + 2] = fm.ascent;
            fmCache[fmCacheCount * 4 + 3] = fm.descent;
            fmCacheCount++;
            spanEndCache[spanEndCacheCount] = spanEnd;
            spanEndCacheCount++;
        }
        nGetWidths(b.mNativePtr, widths);
        int breakCount = nComputeLineBreaks(b.mNativePtr, lineBreaks, lineBreaks.breaks, lineBreaks.widths, lineBreaks.flags, lineBreaks.breaks.length);
        int[] breaks = lineBreaks.breaks;
        float[] lineWidths = lineBreaks.widths;
        int[] flags = lineBreaks.flags;
        final int remainingLineCount = mMaximumVisibleLineCount - mLineCount;
        final boolean ellipsisMayBeApplied = ellipsize != null && (ellipsize == TextUtils.TruncateAt.END || (mMaximumVisibleLineCount == 1 && ellipsize != TextUtils.TruncateAt.MARQUEE));
        if (remainingLineCount > 0 && remainingLineCount < breakCount && ellipsisMayBeApplied) {
            // Calculate width and flag.
            float width = 0;
            int flag = 0;
            for (int i = remainingLineCount - 1; i < breakCount; i++) {
                if (i == breakCount - 1) {
                    width += lineWidths[i];
                } else {
                    for (int j = (i == 0 ? 0 : breaks[i - 1]); j < breaks[i]; j++) {
                        width += widths[j];
                    }
                }
                flag |= flags[i] & TAB_MASK;
            }
            // Treat the last line and overflowed lines as a single line.
            breaks[remainingLineCount - 1] = breaks[breakCount - 1];
            lineWidths[remainingLineCount - 1] = width;
            flags[remainingLineCount - 1] = flag;
            breakCount = remainingLineCount;
        }
        // here is the offset of the starting character of the line we are currently measuring
        int here = paraStart;
        int fmTop = 0, fmBottom = 0, fmAscent = 0, fmDescent = 0;
        int fmCacheIndex = 0;
        int spanEndCacheIndex = 0;
        int breakIndex = 0;
        for (int spanStart = paraStart, spanEnd; spanStart < paraEnd; spanStart = spanEnd) {
            // retrieve end of span
            spanEnd = spanEndCache[spanEndCacheIndex++];
            // retrieve cached metrics, order matches above
            fm.top = fmCache[fmCacheIndex * 4 + 0];
            fm.bottom = fmCache[fmCacheIndex * 4 + 1];
            fm.ascent = fmCache[fmCacheIndex * 4 + 2];
            fm.descent = fmCache[fmCacheIndex * 4 + 3];
            fmCacheIndex++;
            if (fm.top < fmTop) {
                fmTop = fm.top;
            }
            if (fm.ascent < fmAscent) {
                fmAscent = fm.ascent;
            }
            if (fm.descent > fmDescent) {
                fmDescent = fm.descent;
            }
            if (fm.bottom > fmBottom) {
                fmBottom = fm.bottom;
            }
            // skip breaks ending before current span range
            while (breakIndex < breakCount && paraStart + breaks[breakIndex] < spanStart) {
                breakIndex++;
            }
            while (breakIndex < breakCount && paraStart + breaks[breakIndex] <= spanEnd) {
                int endPos = paraStart + breaks[breakIndex];
                boolean moreChars = (endPos < bufEnd);
                v = out(source, here, endPos, fmAscent, fmDescent, fmTop, fmBottom, v, spacingmult, spacingadd, chooseHt, chooseHtv, fm, flags[breakIndex], needMultiply, chdirs, dir, easy, bufEnd, includepad, trackpad, chs, widths, paraStart, ellipsize, ellipsizedWidth, lineWidths[breakIndex], paint, moreChars);
                if (endPos < spanEnd) {
                    // preserve metrics for current span
                    fmTop = fm.top;
                    fmBottom = fm.bottom;
                    fmAscent = fm.ascent;
                    fmDescent = fm.descent;
                } else {
                    fmTop = fmBottom = fmAscent = fmDescent = 0;
                }
                here = endPos;
                breakIndex++;
                if (mLineCount >= mMaximumVisibleLineCount) {
                    return;
                }
            }
        }
        if (paraEnd == bufEnd)
            break;
    }
    if ((bufEnd == bufStart || source.charAt(bufEnd - 1) == CHAR_NEW_LINE) && mLineCount < mMaximumVisibleLineCount) {
        // Log.e("text", "output last " + bufEnd);
        measured.setPara(source, bufEnd, bufEnd, textDir, b);
        paint.getFontMetricsInt(fm);
        v = out(source, bufEnd, bufEnd, fm.ascent, fm.descent, fm.top, fm.bottom, v, spacingmult, spacingadd, null, null, fm, 0, needMultiply, measured.mLevels, measured.mDir, measured.mEasy, bufEnd, includepad, trackpad, null, null, bufStart, ellipsize, ellipsizedWidth, 0, paint, false);
    }
}
Also used : LineHeightSpan(android.text.style.LineHeightSpan) TabStopSpan(android.text.style.TabStopSpan) Paint(android.graphics.Paint) Paint(android.graphics.Paint) LeadingMarginSpan2(android.text.style.LeadingMarginSpan.LeadingMarginSpan2) LeadingMarginSpan(android.text.style.LeadingMarginSpan) MetricAffectingSpan(android.text.style.MetricAffectingSpan)

Example 18 with LeadingMarginSpan

use of android.text.style.LeadingMarginSpan in project android_frameworks_base by AOSPA.

the class StaticLayout method generate.

/* package */
void generate(Builder b, boolean includepad, boolean trackpad) {
    CharSequence source = b.mText;
    int bufStart = b.mStart;
    int bufEnd = b.mEnd;
    TextPaint paint = b.mPaint;
    int outerWidth = b.mWidth;
    TextDirectionHeuristic textDir = b.mTextDir;
    float spacingmult = b.mSpacingMult;
    float spacingadd = b.mSpacingAdd;
    float ellipsizedWidth = b.mEllipsizedWidth;
    TextUtils.TruncateAt ellipsize = b.mEllipsize;
    // TODO: move to builder to avoid allocation costs
    LineBreaks lineBreaks = new LineBreaks();
    // store span end locations
    int[] spanEndCache = new int[4];
    // store fontMetrics per span range
    // must be a multiple of 4 (and > 0) (store top, bottom, ascent, and descent per range)
    int[] fmCache = new int[4 * 4];
    // TODO: also respect LocaleSpan within the text
    b.setLocale(paint.getTextLocale());
    mLineCount = 0;
    int v = 0;
    boolean needMultiply = (spacingmult != 1 || spacingadd != 0);
    Paint.FontMetricsInt fm = b.mFontMetricsInt;
    int[] chooseHtv = null;
    MeasuredText measured = b.mMeasuredText;
    Spanned spanned = null;
    if (source instanceof Spanned)
        spanned = (Spanned) source;
    int paraEnd;
    for (int paraStart = bufStart; paraStart <= bufEnd; paraStart = paraEnd) {
        paraEnd = TextUtils.indexOf(source, CHAR_NEW_LINE, paraStart, bufEnd);
        if (paraEnd < 0)
            paraEnd = bufEnd;
        else
            paraEnd++;
        int firstWidthLineCount = 1;
        int firstWidth = outerWidth;
        int restWidth = outerWidth;
        LineHeightSpan[] chooseHt = null;
        if (spanned != null) {
            LeadingMarginSpan[] sp = getParagraphSpans(spanned, paraStart, paraEnd, LeadingMarginSpan.class);
            for (int i = 0; i < sp.length; i++) {
                LeadingMarginSpan lms = sp[i];
                firstWidth -= sp[i].getLeadingMargin(true);
                restWidth -= sp[i].getLeadingMargin(false);
                // leading margin spans, not just this particular one
                if (lms instanceof LeadingMarginSpan2) {
                    LeadingMarginSpan2 lms2 = (LeadingMarginSpan2) lms;
                    firstWidthLineCount = Math.max(firstWidthLineCount, lms2.getLeadingMarginLineCount());
                }
            }
            chooseHt = getParagraphSpans(spanned, paraStart, paraEnd, LineHeightSpan.class);
            if (chooseHt.length == 0) {
                // So that out() would not assume it has any contents
                chooseHt = null;
            } else {
                if (chooseHtv == null || chooseHtv.length < chooseHt.length) {
                    chooseHtv = ArrayUtils.newUnpaddedIntArray(chooseHt.length);
                }
                for (int i = 0; i < chooseHt.length; i++) {
                    int o = spanned.getSpanStart(chooseHt[i]);
                    if (o < paraStart) {
                        // starts in this layout, before the
                        // current paragraph
                        chooseHtv[i] = getLineTop(getLineForOffset(o));
                    } else {
                        // starts in this paragraph
                        chooseHtv[i] = v;
                    }
                }
            }
        }
        measured.setPara(source, paraStart, paraEnd, textDir, b);
        char[] chs = measured.mChars;
        float[] widths = measured.mWidths;
        byte[] chdirs = measured.mLevels;
        int dir = measured.mDir;
        boolean easy = measured.mEasy;
        // tab stop locations
        int[] variableTabStops = null;
        if (spanned != null) {
            TabStopSpan[] spans = getParagraphSpans(spanned, paraStart, paraEnd, TabStopSpan.class);
            if (spans.length > 0) {
                int[] stops = new int[spans.length];
                for (int i = 0; i < spans.length; i++) {
                    stops[i] = spans[i].getTabStop();
                }
                Arrays.sort(stops, 0, stops.length);
                variableTabStops = stops;
            }
        }
        nSetupParagraph(b.mNativePtr, chs, paraEnd - paraStart, firstWidth, firstWidthLineCount, restWidth, variableTabStops, TAB_INCREMENT, b.mBreakStrategy, b.mHyphenationFrequency);
        if (mLeftIndents != null || mRightIndents != null) {
            // TODO(raph) performance: it would be better to do this once per layout rather
            // than once per paragraph, but that would require a change to the native
            // interface.
            int leftLen = mLeftIndents == null ? 0 : mLeftIndents.length;
            int rightLen = mRightIndents == null ? 0 : mRightIndents.length;
            int indentsLen = Math.max(1, Math.max(leftLen, rightLen) - mLineCount);
            int[] indents = new int[indentsLen];
            for (int i = 0; i < indentsLen; i++) {
                int leftMargin = mLeftIndents == null ? 0 : mLeftIndents[Math.min(i + mLineCount, leftLen - 1)];
                int rightMargin = mRightIndents == null ? 0 : mRightIndents[Math.min(i + mLineCount, rightLen - 1)];
                indents[i] = leftMargin + rightMargin;
            }
            nSetIndents(b.mNativePtr, indents);
        }
        // measurement has to be done before performing line breaking
        // but we don't want to recompute fontmetrics or span ranges the
        // second time, so we cache those and then use those stored values
        int fmCacheCount = 0;
        int spanEndCacheCount = 0;
        for (int spanStart = paraStart, spanEnd; spanStart < paraEnd; spanStart = spanEnd) {
            if (fmCacheCount * 4 >= fmCache.length) {
                int[] grow = new int[fmCacheCount * 4 * 2];
                System.arraycopy(fmCache, 0, grow, 0, fmCacheCount * 4);
                fmCache = grow;
            }
            if (spanEndCacheCount >= spanEndCache.length) {
                int[] grow = new int[spanEndCacheCount * 2];
                System.arraycopy(spanEndCache, 0, grow, 0, spanEndCacheCount);
                spanEndCache = grow;
            }
            if (spanned == null) {
                spanEnd = paraEnd;
                int spanLen = spanEnd - spanStart;
                measured.addStyleRun(paint, spanLen, fm);
            } else {
                spanEnd = spanned.nextSpanTransition(spanStart, paraEnd, MetricAffectingSpan.class);
                int spanLen = spanEnd - spanStart;
                MetricAffectingSpan[] spans = spanned.getSpans(spanStart, spanEnd, MetricAffectingSpan.class);
                spans = TextUtils.removeEmptySpans(spans, spanned, MetricAffectingSpan.class);
                measured.addStyleRun(paint, spans, spanLen, fm);
            }
            // the order of storage here (top, bottom, ascent, descent) has to match the code below
            // where these values are retrieved
            fmCache[fmCacheCount * 4 + 0] = fm.top;
            fmCache[fmCacheCount * 4 + 1] = fm.bottom;
            fmCache[fmCacheCount * 4 + 2] = fm.ascent;
            fmCache[fmCacheCount * 4 + 3] = fm.descent;
            fmCacheCount++;
            spanEndCache[spanEndCacheCount] = spanEnd;
            spanEndCacheCount++;
        }
        nGetWidths(b.mNativePtr, widths);
        int breakCount = nComputeLineBreaks(b.mNativePtr, lineBreaks, lineBreaks.breaks, lineBreaks.widths, lineBreaks.flags, lineBreaks.breaks.length);
        int[] breaks = lineBreaks.breaks;
        float[] lineWidths = lineBreaks.widths;
        int[] flags = lineBreaks.flags;
        final int remainingLineCount = mMaximumVisibleLineCount - mLineCount;
        final boolean ellipsisMayBeApplied = ellipsize != null && (ellipsize == TextUtils.TruncateAt.END || (mMaximumVisibleLineCount == 1 && ellipsize != TextUtils.TruncateAt.MARQUEE));
        if (remainingLineCount > 0 && remainingLineCount < breakCount && ellipsisMayBeApplied) {
            // Calculate width and flag.
            float width = 0;
            int flag = 0;
            for (int i = remainingLineCount - 1; i < breakCount; i++) {
                if (i == breakCount - 1) {
                    width += lineWidths[i];
                } else {
                    for (int j = (i == 0 ? 0 : breaks[i - 1]); j < breaks[i]; j++) {
                        width += widths[j];
                    }
                }
                flag |= flags[i] & TAB_MASK;
            }
            // Treat the last line and overflowed lines as a single line.
            breaks[remainingLineCount - 1] = breaks[breakCount - 1];
            lineWidths[remainingLineCount - 1] = width;
            flags[remainingLineCount - 1] = flag;
            breakCount = remainingLineCount;
        }
        // here is the offset of the starting character of the line we are currently measuring
        int here = paraStart;
        int fmTop = 0, fmBottom = 0, fmAscent = 0, fmDescent = 0;
        int fmCacheIndex = 0;
        int spanEndCacheIndex = 0;
        int breakIndex = 0;
        for (int spanStart = paraStart, spanEnd; spanStart < paraEnd; spanStart = spanEnd) {
            // retrieve end of span
            spanEnd = spanEndCache[spanEndCacheIndex++];
            // retrieve cached metrics, order matches above
            fm.top = fmCache[fmCacheIndex * 4 + 0];
            fm.bottom = fmCache[fmCacheIndex * 4 + 1];
            fm.ascent = fmCache[fmCacheIndex * 4 + 2];
            fm.descent = fmCache[fmCacheIndex * 4 + 3];
            fmCacheIndex++;
            if (fm.top < fmTop) {
                fmTop = fm.top;
            }
            if (fm.ascent < fmAscent) {
                fmAscent = fm.ascent;
            }
            if (fm.descent > fmDescent) {
                fmDescent = fm.descent;
            }
            if (fm.bottom > fmBottom) {
                fmBottom = fm.bottom;
            }
            // skip breaks ending before current span range
            while (breakIndex < breakCount && paraStart + breaks[breakIndex] < spanStart) {
                breakIndex++;
            }
            while (breakIndex < breakCount && paraStart + breaks[breakIndex] <= spanEnd) {
                int endPos = paraStart + breaks[breakIndex];
                boolean moreChars = (endPos < bufEnd);
                v = out(source, here, endPos, fmAscent, fmDescent, fmTop, fmBottom, v, spacingmult, spacingadd, chooseHt, chooseHtv, fm, flags[breakIndex], needMultiply, chdirs, dir, easy, bufEnd, includepad, trackpad, chs, widths, paraStart, ellipsize, ellipsizedWidth, lineWidths[breakIndex], paint, moreChars);
                if (endPos < spanEnd) {
                    // preserve metrics for current span
                    fmTop = fm.top;
                    fmBottom = fm.bottom;
                    fmAscent = fm.ascent;
                    fmDescent = fm.descent;
                } else {
                    fmTop = fmBottom = fmAscent = fmDescent = 0;
                }
                here = endPos;
                breakIndex++;
                if (mLineCount >= mMaximumVisibleLineCount) {
                    return;
                }
            }
        }
        if (paraEnd == bufEnd)
            break;
    }
    if ((bufEnd == bufStart || source.charAt(bufEnd - 1) == CHAR_NEW_LINE) && mLineCount < mMaximumVisibleLineCount) {
        // Log.e("text", "output last " + bufEnd);
        measured.setPara(source, bufEnd, bufEnd, textDir, b);
        paint.getFontMetricsInt(fm);
        v = out(source, bufEnd, bufEnd, fm.ascent, fm.descent, fm.top, fm.bottom, v, spacingmult, spacingadd, null, null, fm, 0, needMultiply, measured.mLevels, measured.mDir, measured.mEasy, bufEnd, includepad, trackpad, null, null, bufStart, ellipsize, ellipsizedWidth, 0, paint, false);
    }
}
Also used : LineHeightSpan(android.text.style.LineHeightSpan) TabStopSpan(android.text.style.TabStopSpan) Paint(android.graphics.Paint) Paint(android.graphics.Paint) LeadingMarginSpan2(android.text.style.LeadingMarginSpan.LeadingMarginSpan2) LeadingMarginSpan(android.text.style.LeadingMarginSpan) MetricAffectingSpan(android.text.style.MetricAffectingSpan)

Example 19 with LeadingMarginSpan

use of android.text.style.LeadingMarginSpan in project android_frameworks_base by AOSPA.

the class Layout method getParagraphLeadingMargin.

/**
     * Returns the effective leading margin (unsigned) for this line,
     * taking into account LeadingMarginSpan and LeadingMarginSpan2.
     * @param line the line index
     * @return the leading margin of this line
     */
private int getParagraphLeadingMargin(int line) {
    if (!mSpannedText) {
        return 0;
    }
    Spanned spanned = (Spanned) mText;
    int lineStart = getLineStart(line);
    int lineEnd = getLineEnd(line);
    int spanEnd = spanned.nextSpanTransition(lineStart, lineEnd, LeadingMarginSpan.class);
    LeadingMarginSpan[] spans = getParagraphSpans(spanned, lineStart, spanEnd, LeadingMarginSpan.class);
    if (spans.length == 0) {
        // no leading margin span;
        return 0;
    }
    int margin = 0;
    boolean isFirstParaLine = lineStart == 0 || spanned.charAt(lineStart - 1) == '\n';
    boolean useFirstLineMargin = isFirstParaLine;
    for (int i = 0; i < spans.length; i++) {
        if (spans[i] instanceof LeadingMarginSpan2) {
            int spStart = spanned.getSpanStart(spans[i]);
            int spanLine = getLineForOffset(spStart);
            int count = ((LeadingMarginSpan2) spans[i]).getLeadingMarginLineCount();
            // if there is more than one LeadingMarginSpan2, use the count that is greatest
            useFirstLineMargin |= line < spanLine + count;
        }
    }
    for (int i = 0; i < spans.length; i++) {
        LeadingMarginSpan span = spans[i];
        margin += span.getLeadingMargin(useFirstLineMargin);
    }
    return margin;
}
Also used : LeadingMarginSpan2(android.text.style.LeadingMarginSpan.LeadingMarginSpan2) LeadingMarginSpan(android.text.style.LeadingMarginSpan) Paint(android.graphics.Paint)

Example 20 with LeadingMarginSpan

use of android.text.style.LeadingMarginSpan in project android_frameworks_base by AOSPA.

the class Layout method drawText.

/**
     * @hide
     */
public void drawText(Canvas canvas, int firstLine, int lastLine) {
    int previousLineBottom = getLineTop(firstLine);
    int previousLineEnd = getLineStart(firstLine);
    ParagraphStyle[] spans = NO_PARA_SPANS;
    int spanEnd = 0;
    TextPaint paint = mPaint;
    CharSequence buf = mText;
    Alignment paraAlign = mAlignment;
    TabStops tabStops = null;
    boolean tabStopsIsInitialized = false;
    TextLine tl = TextLine.obtain();
    // The baseline is the top of the following line minus the current line's descent.
    for (int lineNum = firstLine; lineNum <= lastLine; lineNum++) {
        int start = previousLineEnd;
        previousLineEnd = getLineStart(lineNum + 1);
        int end = getLineVisibleEnd(lineNum, start, previousLineEnd);
        int ltop = previousLineBottom;
        int lbottom = getLineTop(lineNum + 1);
        previousLineBottom = lbottom;
        int lbaseline = lbottom - getLineDescent(lineNum);
        int dir = getParagraphDirection(lineNum);
        int left = 0;
        int right = mWidth;
        if (mSpannedText) {
            Spanned sp = (Spanned) buf;
            int textLength = buf.length();
            boolean isFirstParaLine = (start == 0 || buf.charAt(start - 1) == '\n');
            // our problem.
            if (start >= spanEnd && (lineNum == firstLine || isFirstParaLine)) {
                spanEnd = sp.nextSpanTransition(start, textLength, ParagraphStyle.class);
                spans = getParagraphSpans(sp, start, spanEnd, ParagraphStyle.class);
                paraAlign = mAlignment;
                for (int n = spans.length - 1; n >= 0; n--) {
                    if (spans[n] instanceof AlignmentSpan) {
                        paraAlign = ((AlignmentSpan) spans[n]).getAlignment();
                        break;
                    }
                }
                tabStopsIsInitialized = false;
            }
            // Draw all leading margin spans.  Adjust left or right according
            // to the paragraph direction of the line.
            final int length = spans.length;
            boolean useFirstLineMargin = isFirstParaLine;
            for (int n = 0; n < length; n++) {
                if (spans[n] instanceof LeadingMarginSpan2) {
                    int count = ((LeadingMarginSpan2) spans[n]).getLeadingMarginLineCount();
                    int startLine = getLineForOffset(sp.getSpanStart(spans[n]));
                    // the count that is greatest
                    if (lineNum < startLine + count) {
                        useFirstLineMargin = true;
                        break;
                    }
                }
            }
            for (int n = 0; n < length; n++) {
                if (spans[n] instanceof LeadingMarginSpan) {
                    LeadingMarginSpan margin = (LeadingMarginSpan) spans[n];
                    if (dir == DIR_RIGHT_TO_LEFT) {
                        margin.drawLeadingMargin(canvas, paint, right, dir, ltop, lbaseline, lbottom, buf, start, end, isFirstParaLine, this);
                        right -= margin.getLeadingMargin(useFirstLineMargin);
                    } else {
                        margin.drawLeadingMargin(canvas, paint, left, dir, ltop, lbaseline, lbottom, buf, start, end, isFirstParaLine, this);
                        left += margin.getLeadingMargin(useFirstLineMargin);
                    }
                }
            }
        }
        boolean hasTab = getLineContainsTab(lineNum);
        // Can't tell if we have tabs for sure, currently
        if (hasTab && !tabStopsIsInitialized) {
            if (tabStops == null) {
                tabStops = new TabStops(TAB_INCREMENT, spans);
            } else {
                tabStops.reset(TAB_INCREMENT, spans);
            }
            tabStopsIsInitialized = true;
        }
        // Determine whether the line aligns to normal, opposite, or center.
        Alignment align = paraAlign;
        if (align == Alignment.ALIGN_LEFT) {
            align = (dir == DIR_LEFT_TO_RIGHT) ? Alignment.ALIGN_NORMAL : Alignment.ALIGN_OPPOSITE;
        } else if (align == Alignment.ALIGN_RIGHT) {
            align = (dir == DIR_LEFT_TO_RIGHT) ? Alignment.ALIGN_OPPOSITE : Alignment.ALIGN_NORMAL;
        }
        int x;
        if (align == Alignment.ALIGN_NORMAL) {
            if (dir == DIR_LEFT_TO_RIGHT) {
                x = left + getIndentAdjust(lineNum, Alignment.ALIGN_LEFT);
            } else {
                x = right + getIndentAdjust(lineNum, Alignment.ALIGN_RIGHT);
            }
        } else {
            int max = (int) getLineExtent(lineNum, tabStops, false);
            if (align == Alignment.ALIGN_OPPOSITE) {
                if (dir == DIR_LEFT_TO_RIGHT) {
                    x = right - max + getIndentAdjust(lineNum, Alignment.ALIGN_RIGHT);
                } else {
                    x = left - max + getIndentAdjust(lineNum, Alignment.ALIGN_LEFT);
                }
            } else {
                // Alignment.ALIGN_CENTER
                max = max & ~1;
                x = ((right + left - max) >> 1) + getIndentAdjust(lineNum, Alignment.ALIGN_CENTER);
            }
        }
        paint.setHyphenEdit(getHyphen(lineNum));
        Directions directions = getLineDirections(lineNum);
        if (directions == DIRS_ALL_LEFT_TO_RIGHT && !mSpannedText && !hasTab) {
            // XXX: assumes there's nothing additional to be done
            canvas.drawText(buf, start, end, x, lbaseline, paint);
        } else {
            tl.set(paint, buf, start, end, dir, directions, hasTab, tabStops);
            tl.draw(canvas, x, ltop, lbaseline, lbottom);
        }
        paint.setHyphenEdit(0);
    }
    TextLine.recycle(tl);
}
Also used : AlignmentSpan(android.text.style.AlignmentSpan) ParagraphStyle(android.text.style.ParagraphStyle) Paint(android.graphics.Paint) LeadingMarginSpan2(android.text.style.LeadingMarginSpan.LeadingMarginSpan2) LeadingMarginSpan(android.text.style.LeadingMarginSpan)

Aggregations

LeadingMarginSpan (android.text.style.LeadingMarginSpan)28 Paint (android.graphics.Paint)27 LeadingMarginSpan2 (android.text.style.LeadingMarginSpan.LeadingMarginSpan2)21 TabStopSpan (android.text.style.TabStopSpan)12 AlignmentSpan (android.text.style.AlignmentSpan)8 LineHeightSpan (android.text.style.LineHeightSpan)7 MetricAffectingSpan (android.text.style.MetricAffectingSpan)7 ParagraphStyle (android.text.style.ParagraphStyle)7 Bitmap (android.graphics.Bitmap)2 TextPaint (android.text.TextPaint)2 Spannable (android.text.Spannable)1 StaticLayout (android.text.StaticLayout)1 BulletSpan (android.text.style.BulletSpan)1 LineBackgroundSpan (android.text.style.LineBackgroundSpan)1 StrikethroughSpan (android.text.style.StrikethroughSpan)1 TypefaceSpan (android.text.style.TypefaceSpan)1 DirectionSpan (com.bluejamesbond.text.style.DirectionSpan)1 TextAlignment (com.bluejamesbond.text.style.TextAlignment)1 TextAlignmentSpan (com.bluejamesbond.text.style.TextAlignmentSpan)1 HashMap (java.util.HashMap)1