Search in sources :

Example 6 with LeadingMarginSpan

use of android.text.style.LeadingMarginSpan in project XobotOS by xamarin.

the class StaticLayout method generate.

/* package */
void generate(CharSequence source, int bufStart, int bufEnd, TextPaint paint, int outerWidth, Alignment align, TextDirectionHeuristic textDir, float spacingmult, float spacingadd, boolean includepad, boolean trackpad, float ellipsizedWidth, TextUtils.TruncateAt ellipsize) {
    mLineCount = 0;
    int v = 0;
    boolean needMultiply = (spacingmult != 1 || spacingadd != 0);
    Paint.FontMetricsInt fm = mFontMetricsInt;
    int[] chooseHtv = null;
    MeasuredText measured = mMeasured;
    Spanned spanned = null;
    if (source instanceof Spanned)
        spanned = (Spanned) source;
    // XXX
    int DEFAULT_DIR = DIR_LEFT_TO_RIGHT;
    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 firstWidthLineLimit = mLineCount + 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);
                // paragraph.
                if (lms instanceof LeadingMarginSpan2) {
                    LeadingMarginSpan2 lms2 = (LeadingMarginSpan2) lms;
                    int lmsFirstLine = getLineForOffset(spanned.getSpanStart(lms2));
                    firstWidthLineLimit = lmsFirstLine + lms2.getLeadingMarginLineCount();
                }
            }
            chooseHt = getParagraphSpans(spanned, paraStart, paraEnd, LineHeightSpan.class);
            if (chooseHt.length != 0) {
                if (chooseHtv == null || chooseHtv.length < chooseHt.length) {
                    chooseHtv = new int[ArrayUtils.idealIntArraySize(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);
        char[] chs = measured.mChars;
        float[] widths = measured.mWidths;
        byte[] chdirs = measured.mLevels;
        int dir = measured.mDir;
        boolean easy = measured.mEasy;
        int width = firstWidth;
        float w = 0;
        int here = paraStart;
        int ok = paraStart;
        float okWidth = w;
        int okAscent = 0, okDescent = 0, okTop = 0, okBottom = 0;
        int fit = paraStart;
        float fitWidth = w;
        int fitAscent = 0, fitDescent = 0, fitTop = 0, fitBottom = 0;
        boolean hasTabOrEmoji = false;
        boolean hasTab = false;
        TabStops tabStops = null;
        for (int spanStart = paraStart, spanEnd = spanStart, nextSpanStart; spanStart < paraEnd; spanStart = nextSpanStart) {
            if (spanStart == spanEnd) {
                if (spanned == null)
                    spanEnd = paraEnd;
                else
                    spanEnd = spanned.nextSpanTransition(spanStart, paraEnd, MetricAffectingSpan.class);
                int spanLen = spanEnd - spanStart;
                if (spanned == null) {
                    measured.addStyleRun(paint, spanLen, fm);
                } else {
                    MetricAffectingSpan[] spans = spanned.getSpans(spanStart, spanEnd, MetricAffectingSpan.class);
                    spans = TextUtils.removeEmptySpans(spans, spanned, MetricAffectingSpan.class);
                    measured.addStyleRun(paint, spans, spanLen, fm);
                }
            }
            nextSpanStart = spanEnd;
            int fmTop = fm.top;
            int fmBottom = fm.bottom;
            int fmAscent = fm.ascent;
            int fmDescent = fm.descent;
            for (int j = spanStart; j < spanEnd; j++) {
                char c = chs[j - paraStart];
                if (c == CHAR_NEW_LINE) {
                // intentionally left empty
                } else if (c == CHAR_TAB) {
                    if (hasTab == false) {
                        hasTab = true;
                        hasTabOrEmoji = true;
                        if (spanned != null) {
                            // First tab this para, check for tabstops
                            TabStopSpan[] spans = getParagraphSpans(spanned, paraStart, paraEnd, TabStopSpan.class);
                            if (spans.length > 0) {
                                tabStops = new TabStops(TAB_INCREMENT, spans);
                            }
                        }
                    }
                    if (tabStops != null) {
                        w = tabStops.nextTab(w);
                    } else {
                        w = TabStops.nextDefaultStop(w, TAB_INCREMENT);
                    }
                } else if (c >= CHAR_FIRST_HIGH_SURROGATE && c <= CHAR_LAST_LOW_SURROGATE && j + 1 < spanEnd) {
                    int emoji = Character.codePointAt(chs, j - paraStart);
                    if (emoji >= MIN_EMOJI && emoji <= MAX_EMOJI) {
                        Bitmap bm = EMOJI_FACTORY.getBitmapFromAndroidPua(emoji);
                        if (bm != null) {
                            Paint whichPaint;
                            if (spanned == null) {
                                whichPaint = paint;
                            } else {
                                whichPaint = mWorkPaint;
                            }
                            float wid = bm.getWidth() * -whichPaint.ascent() / bm.getHeight();
                            w += wid;
                            hasTabOrEmoji = true;
                            j++;
                        } else {
                            w += widths[j - paraStart];
                        }
                    } else {
                        w += widths[j - paraStart];
                    }
                } else {
                    w += widths[j - paraStart];
                }
                if (w <= width) {
                    fitWidth = w;
                    fit = j + 1;
                    if (fmTop < fitTop)
                        fitTop = fmTop;
                    if (fmAscent < fitAscent)
                        fitAscent = fmAscent;
                    if (fmDescent > fitDescent)
                        fitDescent = fmDescent;
                    if (fmBottom > fitBottom)
                        fitBottom = fmBottom;
                    if (c == CHAR_SPACE || c == CHAR_TAB || ((c == CHAR_DOT || c == CHAR_COMMA || c == CHAR_COLON || c == CHAR_SEMICOLON) && (j - 1 < here || !Character.isDigit(chs[j - 1 - paraStart])) && (j + 1 >= spanEnd || !Character.isDigit(chs[j + 1 - paraStart]))) || ((c == CHAR_SLASH || c == CHAR_HYPHEN) && (j + 1 >= spanEnd || !Character.isDigit(chs[j + 1 - paraStart]))) || (c >= CHAR_FIRST_CJK && isIdeographic(c, true) && j + 1 < spanEnd && isIdeographic(chs[j + 1 - paraStart], false))) {
                        okWidth = w;
                        ok = j + 1;
                        if (fitTop < okTop)
                            okTop = fitTop;
                        if (fitAscent < okAscent)
                            okAscent = fitAscent;
                        if (fitDescent > okDescent)
                            okDescent = fitDescent;
                        if (fitBottom > okBottom)
                            okBottom = fitBottom;
                    }
                } else {
                    final boolean moreChars = (j + 1 < spanEnd);
                    if (ok != here) {
                        while (ok < spanEnd && chs[ok - paraStart] == CHAR_SPACE) {
                            ok++;
                        }
                        v = out(source, here, ok, okAscent, okDescent, okTop, okBottom, v, spacingmult, spacingadd, chooseHt, chooseHtv, fm, hasTabOrEmoji, needMultiply, paraStart, chdirs, dir, easy, ok == bufEnd, includepad, trackpad, chs, widths, paraStart, ellipsize, ellipsizedWidth, okWidth, paint, moreChars);
                        here = ok;
                    } else if (fit != here) {
                        // Log.e("text", "output fit " + here + " to " +fit);
                        v = out(source, here, fit, fitAscent, fitDescent, fitTop, fitBottom, v, spacingmult, spacingadd, chooseHt, chooseHtv, fm, hasTabOrEmoji, needMultiply, paraStart, chdirs, dir, easy, fit == bufEnd, includepad, trackpad, chs, widths, paraStart, ellipsize, ellipsizedWidth, fitWidth, paint, moreChars);
                        here = fit;
                    } else {
                        // Log.e("text", "output one " + here + " to " +(here + 1));
                        // XXX not sure why the existing fm wasn't ok.
                        // measureText(paint, mWorkPaint,
                        //             source, here, here + 1, fm, tab,
                        //             null);
                        v = out(source, here, here + 1, fm.ascent, fm.descent, fm.top, fm.bottom, v, spacingmult, spacingadd, chooseHt, chooseHtv, fm, hasTabOrEmoji, needMultiply, paraStart, chdirs, dir, easy, here + 1 == bufEnd, includepad, trackpad, chs, widths, paraStart, ellipsize, ellipsizedWidth, widths[here - paraStart], paint, moreChars);
                        here = here + 1;
                    }
                    if (here < spanStart) {
                        // didn't output all the text for this span
                        // we've measured the raw widths, though, so
                        // just reset the start point
                        j = nextSpanStart = here;
                    } else {
                        // continue looping
                        j = here - 1;
                    }
                    ok = fit = here;
                    w = 0;
                    fitAscent = fitDescent = fitTop = fitBottom = 0;
                    okAscent = okDescent = okTop = okBottom = 0;
                    if (--firstWidthLineLimit <= 0) {
                        width = restWidth;
                    }
                }
                if (mLineCount >= mMaximumVisibleLineCount) {
                    break;
                }
            }
        }
        if (paraEnd != here && mLineCount < mMaximumVisibleLineCount) {
            if ((fitTop | fitBottom | fitDescent | fitAscent) == 0) {
                paint.getFontMetricsInt(fm);
                fitTop = fm.top;
                fitBottom = fm.bottom;
                fitAscent = fm.ascent;
                fitDescent = fm.descent;
            }
            // Log.e("text", "output rest " + here + " to " + end);
            v = out(source, here, paraEnd, fitAscent, fitDescent, fitTop, fitBottom, v, spacingmult, spacingadd, chooseHt, chooseHtv, fm, hasTabOrEmoji, needMultiply, paraStart, chdirs, dir, easy, paraEnd == bufEnd, includepad, trackpad, chs, widths, paraStart, ellipsize, ellipsizedWidth, w, paint, paraEnd != bufEnd);
        }
        paraStart = paraEnd;
        if (paraEnd == bufEnd)
            break;
    }
    if ((bufEnd == bufStart || source.charAt(bufEnd - 1) == CHAR_NEW_LINE) && mLineCount < mMaximumVisibleLineCount) {
        // Log.e("text", "output last " + bufEnd);
        paint.getFontMetricsInt(fm);
        v = out(source, bufEnd, bufEnd, fm.ascent, fm.descent, fm.top, fm.bottom, v, spacingmult, spacingadd, null, null, fm, false, needMultiply, bufEnd, null, DEFAULT_DIR, true, true, includepad, trackpad, null, null, bufStart, ellipsize, ellipsizedWidth, 0, paint, false);
    }
}
Also used : TabStopSpan(android.text.style.TabStopSpan) LineHeightSpan(android.text.style.LineHeightSpan) Paint(android.graphics.Paint) Paint(android.graphics.Paint) LeadingMarginSpan2(android.text.style.LeadingMarginSpan.LeadingMarginSpan2) Bitmap(android.graphics.Bitmap) LeadingMarginSpan(android.text.style.LeadingMarginSpan) MetricAffectingSpan(android.text.style.MetricAffectingSpan)

Example 7 with LeadingMarginSpan

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

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)

Example 8 with LeadingMarginSpan

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

the class Layout method measurePara.

/* package */
static float measurePara(TextPaint paint, CharSequence text, int start, int end) {
    MeasuredText mt = MeasuredText.obtain();
    TextLine tl = TextLine.obtain();
    try {
        mt.setPara(text, start, end, TextDirectionHeuristics.LTR, null);
        Directions directions;
        int dir;
        if (mt.mEasy) {
            directions = DIRS_ALL_LEFT_TO_RIGHT;
            dir = Layout.DIR_LEFT_TO_RIGHT;
        } else {
            directions = AndroidBidi.directions(mt.mDir, mt.mLevels, 0, mt.mChars, 0, mt.mLen);
            dir = mt.mDir;
        }
        char[] chars = mt.mChars;
        int len = mt.mLen;
        boolean hasTabs = false;
        TabStops tabStops = null;
        // leading margins should be taken into account when measuring a paragraph
        int margin = 0;
        if (text instanceof Spanned) {
            Spanned spanned = (Spanned) text;
            LeadingMarginSpan[] spans = getParagraphSpans(spanned, start, end, LeadingMarginSpan.class);
            for (LeadingMarginSpan lms : spans) {
                margin += lms.getLeadingMargin(true);
            }
        }
        for (int i = 0; i < len; ++i) {
            if (chars[i] == '\t') {
                hasTabs = true;
                if (text instanceof Spanned) {
                    Spanned spanned = (Spanned) text;
                    int spanEnd = spanned.nextSpanTransition(start, end, TabStopSpan.class);
                    TabStopSpan[] spans = getParagraphSpans(spanned, start, spanEnd, TabStopSpan.class);
                    if (spans.length > 0) {
                        tabStops = new TabStops(TAB_INCREMENT, spans);
                    }
                }
                break;
            }
        }
        tl.set(paint, text, start, end, dir, directions, hasTabs, tabStops);
        return margin + tl.metrics(null);
    } finally {
        TextLine.recycle(tl);
        MeasuredText.recycle(mt);
    }
}
Also used : TabStopSpan(android.text.style.TabStopSpan) LeadingMarginSpan(android.text.style.LeadingMarginSpan) Paint(android.graphics.Paint)

Example 9 with LeadingMarginSpan

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

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 10 with LeadingMarginSpan

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

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