android.text.style.ParagraphStyle Java Examples

The following examples show how to use android.text.style.ParagraphStyle. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source Project: memoir   Author: ronak-manglani   File: ClonedSpannableString.java    License: Apache License 2.0 6 votes vote down vote up
private void init(CharSequence source, int start, int end) {
    int initial = 20;
    mSpans = new Object[initial];
    mSpanData = new int[initial * 3];

    if (source instanceof Spanned) {
        Spanned sp = (Spanned) source;
        for (Object span : sp.getSpans(start, end, Object.class)) {
            if (span instanceof CharacterStyle || span instanceof ParagraphStyle) {
                int st = sp.getSpanStart(span);
                int en = sp.getSpanEnd(span);
                int fl = sp.getSpanFlags(span);

                if (st < start) st = start;
                if (en > end) en = end;

                setSpan(span, st - start, en - start, fl);
            }
        }
    }
}
 
Example #2
Source Project: memoir   Author: ronak-manglani   File: ClonedSpannableString.java    License: Apache License 2.0 6 votes vote down vote up
private void init(CharSequence source, int start, int end) {
    int initial = 20;
    mSpans = new Object[initial];
    mSpanData = new int[initial * 3];

    if (source instanceof Spanned) {
        Spanned sp = (Spanned) source;
        for (Object span : sp.getSpans(start, end, Object.class)) {
            if (span instanceof CharacterStyle || span instanceof ParagraphStyle) {
                int st = sp.getSpanStart(span);
                int en = sp.getSpanEnd(span);
                int fl = sp.getSpanFlags(span);

                if (st < start) st = start;
                if (en > end) en = end;

                setSpan(span, st - start, en - start, fl);
            }
        }
    }
}
 
Example #3
Source Project: Android-RTEditor   Author: 1gravity   File: RTEditText.java    License: Apache License 2.0 6 votes vote down vote up
@Override
/* SpanWatcher */
public void onSpanAdded(Spannable text, Object what, int start, int end) {
    mTextChanged = true;
    // we need to keep track of ordered list spans
    if (what instanceof BulletSpan) {
        mIsBulletSpanSelected = true;
        // if text was empty then append zero width char
        // in order for the bullet to be shown when the span is selected
        if (text.toString().isEmpty()) {
            this.append("\u200B");
        }
    } else if (what instanceof NumberSpan) {
        mIsNumberSpanSelected = true;
        // if text was empty then append zero width char
        // in order for the number to be shown when the span is selected
        if (text.toString().isEmpty()) {
            this.append("\u200B");
        }
    }

    if (what instanceof RTSpan && what instanceof ParagraphStyle) {
        setParagraphsAreUp2Date(false);
    }
}
 
Example #4
Source Project: Android-RTEditor   Author: 1gravity   File: ClonedSpannableString.java    License: Apache License 2.0 6 votes vote down vote up
private void init(CharSequence source, int start, int end) {
    int initial = 20;
    mSpans = new Object[initial];
    mSpanData = new int[initial * 3];

    if (source instanceof Spanned) {
        Spanned sp = (Spanned) source;
        for (Object span : sp.getSpans(start, end, Object.class)) {
            if (span instanceof CharacterStyle || span instanceof ParagraphStyle) {
                int st = sp.getSpanStart(span);
                int en = sp.getSpanEnd(span);
                int fl = sp.getSpanFlags(span);

                if (st < start) st = start;
                if (en > end) en = end;

                setSpan(span, st - start, en - start, fl);
            }
        }
    }
}
 
Example #5
Source Project: android_9.0.0_r45   Author: lulululbj   File: TextUtils.java    License: Apache License 2.0 5 votes vote down vote up
/**
 * Returns whether or not the specified spanned text has a style span.
 * @hide
 */
public static boolean hasStyleSpan(@NonNull Spanned spanned) {
    Preconditions.checkArgument(spanned != null);
    final Class<?>[] styleClasses = {
            CharacterStyle.class, ParagraphStyle.class, UpdateAppearance.class};
    for (Class<?> clazz : styleClasses) {
        if (spanned.nextSpanTransition(-1, spanned.length(), clazz) < spanned.length()) {
            return true;
        }
    }
    return false;
}
 
Example #6
Source Project: android_9.0.0_r45   Author: lulululbj   File: Html.java    License: Apache License 2.0 5 votes vote down vote up
private static void encodeTextAlignmentByDiv(StringBuilder out, Spanned text, int option) {
    int len = text.length();

    int next;
    for (int i = 0; i < len; i = next) {
        next = text.nextSpanTransition(i, len, ParagraphStyle.class);
        ParagraphStyle[] style = text.getSpans(i, next, ParagraphStyle.class);
        String elements = " ";
        boolean needDiv = false;

        for(int j = 0; j < style.length; j++) {
            if (style[j] instanceof AlignmentSpan) {
                Layout.Alignment align =
                    ((AlignmentSpan) style[j]).getAlignment();
                needDiv = true;
                if (align == Layout.Alignment.ALIGN_CENTER) {
                    elements = "align=\"center\" " + elements;
                } else if (align == Layout.Alignment.ALIGN_OPPOSITE) {
                    elements = "align=\"right\" " + elements;
                } else {
                    elements = "align=\"left\" " + elements;
                }
            }
        }
        if (needDiv) {
            out.append("<div ").append(elements).append(">");
        }

        withinDiv(out, text, i, next, option);

        if (needDiv) {
            out.append("</div>");
        }
    }
}
 
Example #7
Source Project: android_9.0.0_r45   Author: lulululbj   File: BoringLayout.java    License: Apache License 2.0 5 votes vote down vote up
/**
 * Returns null if not boring; the width, ascent, and descent in the
 * provided Metrics object (or a new one if the provided one was null)
 * if boring.
 * @hide
 */
public static Metrics isBoring(CharSequence text, TextPaint paint,
        TextDirectionHeuristic textDir, Metrics metrics) {
    final int textLength = text.length();
    if (hasAnyInterestingChars(text, textLength)) {
       return null;  // There are some interesting characters. Not boring.
    }
    if (textDir != null && textDir.isRtl(text, 0, textLength)) {
       return null;  // The heuristic considers the whole text RTL. Not boring.
    }
    if (text instanceof Spanned) {
        Spanned sp = (Spanned) text;
        Object[] styles = sp.getSpans(0, textLength, ParagraphStyle.class);
        if (styles.length > 0) {
            return null;  // There are some PargraphStyle spans. Not boring.
        }
    }

    Metrics fm = metrics;
    if (fm == null) {
        fm = new Metrics();
    } else {
        fm.reset();
    }

    TextLine line = TextLine.obtain();
    line.set(paint, text, 0, textLength, Layout.DIR_LEFT_TO_RIGHT,
            Layout.DIRS_ALL_LEFT_TO_RIGHT, false, null);
    fm.width = (int) Math.ceil(line.metrics(fm));
    TextLine.recycle(line);

    return fm;
}
 
Example #8
Source Project: MHViewer   Author: axlecho   File: Html.java    License: Apache License 2.0 5 votes vote down vote up
private static void withinHtml(StringBuilder out, Spanned text) {
    int len = text.length();

    int next;
    for (int i = 0; i < text.length(); i = next) {
        next = text.nextSpanTransition(i, len, ParagraphStyle.class);
        ParagraphStyle[] style = text.getSpans(i, next, ParagraphStyle.class);
        String elements = " ";
        boolean needDiv = false;

        for(int j = 0; j < style.length; j++) {
            if (style[j] instanceof AlignmentSpan) {
                Layout.Alignment align =
                        ((AlignmentSpan) style[j]).getAlignment();
                needDiv = true;
                if (align == Layout.Alignment.ALIGN_CENTER) {
                    elements = "align=\"center\" " + elements;
                } else if (align == Layout.Alignment.ALIGN_OPPOSITE) {
                    elements = "align=\"right\" " + elements;
                } else {
                    elements = "align=\"left\" " + elements;
                }
            }
        }
        if (needDiv) {
            out.append("<div ").append(elements).append(">");
        }

        withinDiv(out, text, i, next);

        if (needDiv) {
            out.append("</div>");
        }
    }
}
 
Example #9
Source Project: FairEmail   Author: M66B   File: HtmlEx.java    License: GNU General Public License v3.0 5 votes vote down vote up
private /* static */ void encodeTextAlignmentByDiv(StringBuilder out, Spanned text, int option) {
    int len = text.length();

    int next;
    for (int i = 0; i < len; i = next) {
        next = text.nextSpanTransition(i, len, ParagraphStyle.class);
        ParagraphStyle[] style = text.getSpans(i, next, ParagraphStyle.class);
        String elements = " ";
        boolean needDiv = false;

        for(int j = 0; j < style.length; j++) {
            if (style[j] instanceof AlignmentSpan) {
                Layout.Alignment align =
                        ((AlignmentSpan) style[j]).getAlignment();
                needDiv = true;
                if (align == Layout.Alignment.ALIGN_CENTER) {
                    elements = "align=\"center\" " + elements;
                } else if (align == Layout.Alignment.ALIGN_OPPOSITE) {
                    elements = "align=\"right\" " + elements;
                } else {
                    elements = "align=\"left\" " + elements;
                }
            }
        }
        if (needDiv) {
            out.append("<div ").append(elements).append(">");
        }

        withinDiv(out, text, i, next, option);

        if (needDiv) {
            out.append("</div>");
        }
    }
}
 
Example #10
Source Project: HtmlCompat   Author: Pixplicity   File: HtmlCompat.java    License: Apache License 2.0 5 votes vote down vote up
private static void encodeTextAlignmentByDiv(Context context, StringBuilder out, Spanned text, int option) {
    int len = text.length();
    int next;
    for (int i = 0; i < len; i = next) {
        next = text.nextSpanTransition(i, len, ParagraphStyle.class);
        ParagraphStyle[] styles = text.getSpans(i, next, ParagraphStyle.class);
        String elements = " ";
        boolean needDiv = false;
        for (ParagraphStyle style : styles) {
            if (style instanceof AlignmentSpan) {
                Layout.Alignment align =
                        ((AlignmentSpan) style).getAlignment();
                needDiv = true;
                if (align == Layout.Alignment.ALIGN_CENTER) {
                    elements = "align=\"center\" " + elements;
                } else if (align == Layout.Alignment.ALIGN_OPPOSITE) {
                    elements = "align=\"right\" " + elements;
                } else {
                    elements = "align=\"left\" " + elements;
                }
            }
        }
        if (needDiv) {
            out.append("<div ").append(elements).append(">");
        }
        withinDiv(context, out, text, i, next, option);
        if (needDiv) {
            out.append("</div>");
        }
    }
}
 
Example #11
Source Project: ForPDA   Author: RadiationX   File: Html.java    License: GNU General Public License v3.0 5 votes vote down vote up
private static void encodeTextAlignmentByDiv(StringBuilder out, Spanned text, int option) {
    int len = text.length();
    int next;
    for (int i = 0; i < len; i = next) {
        next = text.nextSpanTransition(i, len, ParagraphStyle.class);
        ParagraphStyle[] style = text.getSpans(i, next, ParagraphStyle.class);
        String elements = " ";
        boolean needDiv = false;
        for (int j = 0; j < style.length; j++) {
            if (style[j] instanceof AlignmentSpan) {
                Layout.Alignment align =
                        ((AlignmentSpan) style[j]).getAlignment();
                needDiv = true;
                if (align == Layout.Alignment.ALIGN_CENTER) {
                    elements = "align=\"center\" " + elements;
                } else if (align == Layout.Alignment.ALIGN_OPPOSITE) {
                    elements = "align=\"right\" " + elements;
                } else {
                    elements = "align=\"left\" " + elements;
                }
            }
        }
        if (needDiv) {
            out.append("<div ").append(elements).append(">");
        }
        withinDiv(out, text, i, next, option);
        if (needDiv) {
            out.append("</div>");
        }
    }
}
 
Example #12
Source Project: memoir   Author: ronak-manglani   File: ConverterSpannedToHtml.java    License: Apache License 2.0 5 votes vote down vote up
private Set<SingleParagraphStyle> getParagraphStyles(final Spanned text, Selection selection) {
    Set<SingleParagraphStyle> styles = new HashSet<>();

    for (ParagraphStyle style : text.getSpans(selection.start(), selection.end(), ParagraphStyle.class)) {
        ParagraphType type = ParagraphType.getInstance(style);
        if (type != null) {
            styles.add(new SingleParagraphStyle(type, style));
        }
    }

    return styles;
}
 
Example #13
Source Project: memoir   Author: ronak-manglani   File: RTEditText.java    License: Apache License 2.0 5 votes vote down vote up
@Override
/* SpanWatcher */
public void onSpanAdded(Spannable text, Object what, int start, int end) {
    mTextChanged = true;
    if (what instanceof RTSpan && what instanceof ParagraphStyle) {
        setParagraphsAreUp2Date(false);
    }
}
 
Example #14
Source Project: memoir   Author: ronak-manglani   File: RTEditText.java    License: Apache License 2.0 5 votes vote down vote up
@Override
/* SpanWatcher */
public void onSpanChanged(Spannable text, Object what, int ostart, int oend, int nstart, int nend) {
    mTextChanged = true;
    if (what instanceof RTSpan && what instanceof ParagraphStyle) {
        setParagraphsAreUp2Date(false);
    }
}
 
Example #15
Source Project: memoir   Author: ronak-manglani   File: RTEditText.java    License: Apache License 2.0 5 votes vote down vote up
@Override
/* SpanWatcher */
public void onSpanRemoved(Spannable text, Object what, int start, int end) {
    mTextChanged = true;
    if (what instanceof RTSpan && what instanceof ParagraphStyle) {
        setParagraphsAreUp2Date(false);
    }
}
 
Example #16
Source Project: memoir   Author: ronak-manglani   File: ConverterSpannedToHtml.java    License: Apache License 2.0 5 votes vote down vote up
private Set<SingleParagraphStyle> getParagraphStyles(final Spanned text, Selection selection) {
    Set<SingleParagraphStyle> styles = new HashSet<SingleParagraphStyle>();

    for (ParagraphStyle style : text.getSpans(selection.start(), selection.end(), ParagraphStyle.class)) {
        ParagraphType type = ParagraphType.getInstance(style);
        if (type != null) {
            styles.add(new SingleParagraphStyle(type, style));
        }
    }

    return styles;
}
 
Example #17
Source Project: memoir   Author: ronak-manglani   File: RTEditText.java    License: Apache License 2.0 5 votes vote down vote up
@Override
/* SpanWatcher */
public void onSpanAdded(Spannable text, Object what, int start, int end) {
    mTextChanged = true;
    if (what instanceof RTSpan && what instanceof ParagraphStyle) {
        setParagraphsAreUp2Date(false);
    }
}
 
Example #18
Source Project: memoir   Author: ronak-manglani   File: RTEditText.java    License: Apache License 2.0 5 votes vote down vote up
@Override
/* SpanWatcher */
public void onSpanChanged(Spannable text, Object what, int ostart, int oend, int nstart, int nend) {
    mTextChanged = true;
    if (what instanceof RTSpan && what instanceof ParagraphStyle) {
        setParagraphsAreUp2Date(false);
    }
}
 
Example #19
Source Project: memoir   Author: ronak-manglani   File: RTEditText.java    License: Apache License 2.0 5 votes vote down vote up
@Override
/* SpanWatcher */
public void onSpanRemoved(Spannable text, Object what, int start, int end) {
    mTextChanged = true;
    if (what instanceof RTSpan && what instanceof ParagraphStyle) {
        setParagraphsAreUp2Date(false);
    }
}
 
Example #20
Source Project: nono-android   Author: tianyuan168326   File: MyHtml.java    License: GNU General Public License v3.0 5 votes vote down vote up
private static void withinHtml(StringBuilder out, Spanned text) {
    int len = text.length();

    int next;
    for (int i = 0; i < text.length(); i = next) {
        next = text.nextSpanTransition(i, len, ParagraphStyle.class);
        ParagraphStyle[] style = text.getSpans(i, next, ParagraphStyle.class);
        String elements = " ";
        boolean needDiv = false;

        for(int j = 0; j < style.length; j++) {
            if (style[j] instanceof AlignmentSpan) {
                Layout.Alignment align =
                        ((AlignmentSpan) style[j]).getAlignment();
                needDiv = true;
                if (align == Layout.Alignment.ALIGN_CENTER) {
                    elements = "align=\"center\" " + elements;
                } else if (align == Layout.Alignment.ALIGN_OPPOSITE) {
                    elements = "align=\"right\" " + elements;
                } else {
                    elements = "align=\"left\" " + elements;
                }
            }
        }
        if (needDiv) {
            out.append("<div ").append(elements).append(">");
        }

        withinDiv(out, text, i, next);

        if (needDiv) {
            out.append("</div>");
        }
    }
}
 
Example #21
Source Project: Nimingban   Author: seven332   File: Html.java    License: Apache License 2.0 5 votes vote down vote up
private static void withinHtml(StringBuilder out, Spanned text) {
    int len = text.length();

    int next;
    for (int i = 0; i < text.length(); i = next) {
        next = text.nextSpanTransition(i, len, ParagraphStyle.class);
        ParagraphStyle[] style = text.getSpans(i, next, ParagraphStyle.class);
        String elements = " ";
        boolean needDiv = false;

        for(int j = 0; j < style.length; j++) {
            if (style[j] instanceof AlignmentSpan) {
                Layout.Alignment align =
                        ((AlignmentSpan) style[j]).getAlignment();
                needDiv = true;
                if (align == Layout.Alignment.ALIGN_CENTER) {
                    elements = "align=\"center\" " + elements;
                } else if (align == Layout.Alignment.ALIGN_OPPOSITE) {
                    elements = "align=\"right\" " + elements;
                } else {
                    elements = "align=\"left\" " + elements;
                }
            }
        }
        if (needDiv) {
            out.append("<div ").append(elements).append(">");
        }

        withinDiv(out, text, i, next);

        if (needDiv) {
            out.append("</div>");
        }
    }
}
 
Example #22
Source Project: Nimingban   Author: seven332   File: Html.java    License: Apache License 2.0 5 votes vote down vote up
public SpannableStringBuilder convert() {

        mReader.setContentHandler(this);
        try {
            mReader.parse(new InputSource(new StringReader(mSource)));
        } catch (IOException | SAXException e) {
            // We are reading from a string. There should not be IO problems.
            throw new RuntimeException(e);
        }

        // Fix flags and range for paragraph-type markup.
        Object[] obj = mSpannableStringBuilder.getSpans(0, mSpannableStringBuilder.length(), ParagraphStyle.class);
        for (int i = 0; i < obj.length; i++) {
            int start = mSpannableStringBuilder.getSpanStart(obj[i]);
            int end = mSpannableStringBuilder.getSpanEnd(obj[i]);

            // If the last line of the range is blank, back off by one.
            if (end - 2 >= 0) {
                if (mSpannableStringBuilder.charAt(end - 1) == '\n' &&
                        mSpannableStringBuilder.charAt(end - 2) == '\n') {
                    end--;
                }
            }

            if (end == start) {
                mSpannableStringBuilder.removeSpan(obj[i]);
            } else {
                mSpannableStringBuilder.setSpan(obj[i], start, end, Spannable.SPAN_PARAGRAPH);
            }
        }

        return mSpannableStringBuilder;
    }
 
Example #23
Source Project: Android-RTEditor   Author: 1gravity   File: ConverterSpannedToHtml.java    License: Apache License 2.0 5 votes vote down vote up
private Set<SingleParagraphStyle> getParagraphStyles(final Spanned text, Selection selection) {
    Set<SingleParagraphStyle> styles = new HashSet<SingleParagraphStyle>();

    for (ParagraphStyle style : text.getSpans(selection.start(), selection.end(), ParagraphStyle.class)) {
        ParagraphType type = ParagraphType.getInstance(style);
        if (type != null) {
            styles.add(new SingleParagraphStyle(type, style));
        }
    }

    return styles;
}
 
Example #24
Source Project: Android-RTEditor   Author: 1gravity   File: RTEditText.java    License: Apache License 2.0 5 votes vote down vote up
@Override
/* SpanWatcher */
public void onSpanChanged(Spannable text, Object what, int ostart, int oend, int nstart, int nend) {
    mTextChanged = true;
    if (what instanceof RTSpan && what instanceof ParagraphStyle) {
        setParagraphsAreUp2Date(false);
    }
}
 
Example #25
Source Project: Android-RTEditor   Author: 1gravity   File: RTEditText.java    License: Apache License 2.0 5 votes vote down vote up
@Override
/* SpanWatcher */
public void onSpanRemoved(Spannable text, Object what, int start, int end) {
    mTextChanged = true;
    // we need to keep track of ordered list spans
    if (what instanceof BulletSpan) {
        mIsBulletSpanSelected = false;
    } else if (what instanceof NumberSpan) {
        mIsNumberSpanSelected = false;
    }

    if (what instanceof RTSpan && what instanceof ParagraphStyle) {
        setParagraphsAreUp2Date(false);
    }
}
 
Example #26
Source Project: zulip-android   Author: zulip   File: CustomHtmlToSpannedConverter.java    License: Apache License 2.0 5 votes vote down vote up
public Spanned convert() {

        mReader.setContentHandler(this);
        try {
            mReader.parse(new InputSource(new StringReader(mSource)));
        } catch (IOException | SAXException e) {
            // We are reading from a string. There should not be IO problems.
            throw new RuntimeException(e);
        }

        // Fix flags and range for paragraph-type markup.
        Object[] obj = mSpannableStringBuilder.getSpans(0,
                mSpannableStringBuilder.length(), ParagraphStyle.class);
        for (int i = 0; i < obj.length; i++) {
            int start = mSpannableStringBuilder.getSpanStart(obj[i]);
            int end = mSpannableStringBuilder.getSpanEnd(obj[i]);

            // If the last line of the range is blank, back off by one.
            if (end - 2 >= 0
                    && mSpannableStringBuilder.charAt(end - 1) == '\n'
                    && mSpannableStringBuilder.charAt(end - 2) == '\n') {
                end--;
            }

            if (end == start) {
                mSpannableStringBuilder.removeSpan(obj[i]);
            } else {
                mSpannableStringBuilder.setSpan(obj[i], start, end,
                        Spannable.SPAN_PARAGRAPH);
            }
        }

        return mSpannableStringBuilder;
    }
 
Example #27
Source Project: RichEditText   Author: chen-xiao-dong   File: EmailHtmlUtil.java    License: Apache License 2.0 5 votes vote down vote up
private static void withinHtml(StringBuilder out, Spanned text ) {
	int len = text.length();

	int next;
	for (int i = 0; i < text.length(); i = next) {
		next = text.nextSpanTransition(i, len, ParagraphStyle.class);
		ParagraphStyle[] style = text.getSpans(i, next,
				ParagraphStyle.class);
		String elements = " ";
		boolean needDiv = false;

		for (int j = 0; j < style.length; j++) {
			if (style[j] instanceof AlignmentSpan) {
				Layout.Alignment align = ((AlignmentSpan) style[j])
						.getAlignment();
				needDiv = true;
				if (align == Layout.Alignment.ALIGN_CENTER) {
					elements = "align=\"center\" " + elements;
				} else if (align == Layout.Alignment.ALIGN_OPPOSITE) {
					elements = "align=\"right\" " + elements;
				} else {
					elements = "align=\"left\" " + elements;
				}
			}
		}
		if (needDiv) {
			out.append("<div " + elements + ">");
		}

		withinDiv(out, text, i, next);

		if (needDiv) {
			out.append("</div>");
		}
	}
}
 
Example #28
Source Project: 365browser   Author: mogoweb   File: SelectionPopupController.java    License: Apache License 2.0 5 votes vote down vote up
private boolean hasStyleSpan(Spanned spanned) {
    // Only check against those three classes below, which could affect text appearance, since
    // there are other kind of classes won't affect appearance.
    Class<?>[] styleClasses = {
            CharacterStyle.class, ParagraphStyle.class, UpdateAppearance.class};
    for (Class<?> clazz : styleClasses) {
        if (spanned.nextSpanTransition(-1, spanned.length(), clazz) < spanned.length()) {
            return true;
        }
    }
    return false;
}
 
Example #29
Source Project: 365browser   Author: mogoweb   File: Clipboard.java    License: Apache License 2.0 5 votes vote down vote up
private boolean hasStyleSpan(Spanned spanned) {
    Class<?>[] styleClasses = {
            CharacterStyle.class, ParagraphStyle.class, UpdateAppearance.class};
    for (Class<?> clazz : styleClasses) {
        if (spanned.nextSpanTransition(-1, spanned.length(), clazz) < spanned.length()) {
            return true;
        }
    }
    return false;
}
 
Example #30
Source Project: Knife   Author: mthli   File: KnifeParser.java    License: Apache License 2.0 5 votes vote down vote up
private static void withinHtml(StringBuilder out, Spanned text) {
    int next;

    for (int i = 0; i < text.length(); i = next) {
        next = text.nextSpanTransition(i, text.length(), ParagraphStyle.class);

        ParagraphStyle[] styles = text.getSpans(i, next, ParagraphStyle.class);
        if (styles.length == 2) {
            if (styles[0] instanceof BulletSpan && styles[1] instanceof QuoteSpan) {
                // Let a <br> follow the BulletSpan or QuoteSpan end, so next++
                withinBulletThenQuote(out, text, i, next++);
            } else if (styles[0] instanceof QuoteSpan && styles[1] instanceof BulletSpan) {
                withinQuoteThenBullet(out, text, i, next++);
            } else {
                withinContent(out, text, i, next);
            }
        } else if (styles.length == 1) {
            if (styles[0] instanceof BulletSpan) {
                withinBullet(out, text, i, next++);
            } else if (styles[0] instanceof QuoteSpan) {
                withinQuote(out, text, i, next++);
            } else {
                withinContent(out, text, i, next);
            }
        } else {
            withinContent(out, text, i, next);
        }
    }
}