private void handleOLTag(Editable output) { if(output.length() > 0 && output.charAt(output.length() - 1) != '\n') { output.append("\n"); } int numberMargin = mListIndent * (mLists.size() - 1); if(mLists.size() > 2) { // Counter effect of nested spans numberMargin -= (mLists.size() - 2) * mListIndent; } if(mLists.peek().second) { end(output, Ol.class, false, new LeadingMarginSpan.Standard(numberMargin), new ListNumberSpan(mTextPaint, mOlIndices.lastElement().first - 1, mLists.peek().third ) ); } else { end(output, Ol.class, false, new LeadingMarginSpan.Standard(numberMargin) ); } }
public static void calculateTag2(TextView tag, TextView title, final String text) { ViewTreeObserver observer = tag.getViewTreeObserver(); observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { SpannableString spannableString = new SpannableString(text); LeadingMarginSpan.Standard what = new LeadingMarginSpan.Standard(tag.getWidth() + dip2px(tag.getContext(), 10), 0); spannableString.setSpan(what, 0, spannableString.length(), SpannableString.SPAN_INCLUSIVE_INCLUSIVE); title.setText(spannableString); tag.getViewTreeObserver().removeOnPreDrawListener( this); return false; } }); }
@Override public void setIndent(int indent) { if(indent < 0) return; int currentValue = -1; if(indentStack.isEmpty() || indent > (currentValue = indentStack.peek().value)){ indentStack.push(new IndentValue(indent)); return; } while(indent < currentValue){ // decreasing indent IndentValue pop = indentStack.pop(); setSpan(new LeadingMarginSpan.Standard(INDENT_SIZE *pop.value), pop.start); if(indentStack.isEmpty()) break; currentValue = indentStack.peek().value; } }
@Override protected Object[] getReplaces(final Editable text, final int indentation) { // Nested BulletSpans increases distance between BULLET_SPAN and text, so we must prevent it. int bulletMargin = INDENT_PX; if (indentation > 1) { bulletMargin = INDENT_PX - BULLET_SPAN.getLeadingMargin(true); if (indentation > 2) { // This get's more complicated when we add a LeadingMarginSpan into the same line: // we have also counter it's effect to BulletSpan bulletMargin -= (indentation - 2) * LIST_ITEM_INDENT_PX; } } return new Object[]{ new LeadingMarginSpan.Standard(LIST_ITEM_INDENT_PX * (indentation - 1)), new BulletSpan(bulletMargin) }; }
@Test public void testSubList() throws Exception { String content = "* item 1\n" + "* item 2\n" + " * sublist item 1\n" + " * sublist item 2\n"; Spanned result = Markdown.fromMarkdown(content); printSpans(result); Object[] spans = result.getSpans(0, result.length(), Object.class); assertEquals(8, spans.length); assertEquals(LeadingMarginSpan.Standard.class, spans[0].getClass()); assertEquals(BulletSpan.class, spans[1].getClass()); assertEquals(LeadingMarginSpan.Standard.class, spans[2].getClass()); assertEquals(BulletSpan.class, spans[3].getClass()); assertEquals(LeadingMarginSpan.Standard.class, spans[4].getClass()); assertEquals(BulletSpan.class, spans[5].getClass()); assertEquals(LeadingMarginSpan.Standard.class, spans[6].getClass()); assertEquals(BulletSpan.class, spans[7].getClass()); }
@Override public void changeSpanBeforeTextChanged(int start, int lengthBefore, int lengthAfter) { if (changeReplacement) {//add replacement will not change span return; } if (lengthBefore > lengthAfter) { LeadingMarginSpan richSpan = getAssignSpan(getSpanClass(), start + lengthBefore - 1, start + lengthBefore + 1); if (richSpan == null) { return; } int sStart = getEditableText().getSpanStart(richSpan); if (sStart == start && lengthAfter == 0) { spanDeletedIndex = start; } } }
@Override public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) { switch (tag) { case "pre": case "PRE": ensureParagraphBoundary(output); break; // Unfortunately the following code will be ignored in API 24+ and the native rendering is inferior case "li": case "LI": if (opening) { liStarts.addLast(ensureParagraphBoundary(output)); } else if (!liStarts.isEmpty()) { int start = liStarts.popLast(); trimStart(output, start); int end = ensureParagraphBoundary(output); // Add leading margin to ensure the bullet is not cut off output.setSpan(new LeadingMarginSpan.Standard(leadingMargin), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); output.setSpan(new BulletSpan(bulletGapWidth), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); } break; } }
public LeadingMarginSpanDrawParameters(LeadingMarginSpan span, int x, int dir, int top, int baseline, int bottom, int start, int end, boolean first) { this.span = span; this.x = x; this.dir = dir; this.top = top; this.baseline = baseline; this.bottom = bottom; this.start = start; this.end = end; this.first = first; }
private void handleULTag(Editable output) { if(output.length() > 0 && output.charAt(output.length() - 1) != '\n') { output.append("\n"); } if(mLists.peek().second) { //Check for checkboxes if(output.length() > 2 && ((output.charAt(0) >= '\u2610' && output.charAt(0) <= '\u2612') || (output.charAt(1) >= '\u2610' && output .charAt(1) <= '\u2612') )) { end(output, Ul.class, false, new LeadingMarginSpan.Standard( mListIndent * (mLists.size() - 1)) ); } else { end(output, Ul.class, false, new LeadingMarginSpan.Standard( mListIndent * (mLists.size() - 1)), new BulletSpan(mSingleIndent) ); } } else { end(output, Ul.class, false, new LeadingMarginSpan.Standard(mListIndent * (mLists.size() - 1)) ); } }
/** * Get a SpannableString suitable for displaying in a TextView using the given {@code book}'s {@link RTag}s. * @param book Book whose tags to use. * @param maxLines Maximum number of lines to draw backgrounds for. * @return A SpannedString. */ public static SpannableString getSpannedTagString(RBook book, int maxLines) { Spanny spanny = new Spanny(); HashMap<String, Integer> colorMap = new HashMap<>(book.tags.size()); for (RTag tag : book.tags) { spanny.append(tag.name, new ForegroundColorSpan(tag.textColor)).append(TAG_SEP); colorMap.put(tag.name, tag.bgColor); } return Spanny.spanText(spanny, new LeadingMarginSpan.Standard((int) Minerva.d().TAG_CORNER_RADIUS), new TagBackgroundSpan(colorMap, maxLines)); }
@Override protected Object[] getReplaces(final Editable text, final int indentation) { int numberMargin = LIST_ITEM_INDENT_PX * (indentation - 1); if (indentation > 2) { // Same as in ordered lists: counter the effect of nested Spans numberMargin -= (indentation - 2) * LIST_ITEM_INDENT_PX; } return new Object[]{new LeadingMarginSpan.Standard(numberMargin)}; }
@Test public void testEnumeration() throws Exception { String content = " 1. item1\n" + " 1. item2"; Spanned result = Markdown.fromMarkdown(content); printSpans(result); Object[] spans = result.getSpans(0, result.length(), Object.class); assertEquals(2, spans.length); assertEquals(LeadingMarginSpan.Standard.class, spans[0].getClass()); assertEquals('1', result.charAt(0)); assertEquals(LeadingMarginSpan.Standard.class, spans[1].getClass()); assertEquals('2', result.charAt(9)); }
@Test public void testListAsterisk() throws Exception { String content = " * item1\n" + " * item2"; Spanned result = Markdown.fromMarkdown(content); printSpans(result); Object[] spans = result.getSpans(0, result.length(), Object.class); assertEquals(4, spans.length); assertEquals(LeadingMarginSpan.Standard.class, spans[0].getClass()); assertEquals(BulletSpan.class, spans[1].getClass()); assertEquals(LeadingMarginSpan.Standard.class, spans[2].getClass()); assertEquals(BulletSpan.class, spans[3].getClass()); }
@Test public void testListMinus() throws Exception { String content = " * item1\n" + " * item2"; Spanned result = Markdown.fromMarkdown(content); printSpans(result); Object[] spans = result.getSpans(0, result.length(), Object.class); assertEquals(4, spans.length); assertEquals(LeadingMarginSpan.Standard.class, spans[0].getClass()); assertEquals(BulletSpan.class, spans[1].getClass()); assertEquals(LeadingMarginSpan.Standard.class, spans[2].getClass()); assertEquals(BulletSpan.class, spans[3].getClass()); }
@Test public void testListPlus() throws Exception { String content = " * item1\n" + " * item2"; Spanned result = Markdown.fromMarkdown(content); printSpans(result); Object[] spans = result.getSpans(0, result.length(), Object.class); assertEquals(4, spans.length); assertEquals(LeadingMarginSpan.Standard.class, spans[0].getClass()); assertEquals(BulletSpan.class, spans[1].getClass()); assertEquals(LeadingMarginSpan.Standard.class, spans[2].getClass()); assertEquals(BulletSpan.class, spans[3].getClass()); }
protected void setSelectionTextSpan(boolean isValid, Class<? extends LeadingMarginSpan> clazz, int start, int end) { try { LeadingMarginSpan assignSpan = clazz.newInstance(); setSelectionTextSpan(isValid, assignSpan, start, end); } catch (Exception e) { Log.e(TAG, "can not instantiated " + clazz); e.printStackTrace(); } }
@Override public void enableSpan(boolean isEnable, TextSpanStatus state, int code) { int start = editor.getSelectionStart(); int end = editor.getSelectionEnd(); if (end < start) { start = start ^ end; end = start ^ end; start = start ^ end; } state.setTextSpanEnable(code, isEnable); if (start < end) { int quoteStart = getParagraphStart(start); int quoteEnd = getParagraphEnd(end); if (isEnable) { setSelectionTextSpan(true, getSpanClass(), quoteStart, quoteEnd); } else { removeSpan(getSpanClass(), quoteStart, quoteEnd); } } else { if (isEnable) { int sStart = getParagraphStart(start); int sEnd = getParagraphEnd(start); //if there is just a single line,insert a replacement span if (sStart == start && (getEditableText().length() == sStart || getEditableText().charAt(sStart) == '\n')) { insertReplacement(sStart); } else { //else set whole paragraph by quote span setSelectionTextSpan(true, getSpanClass(), sStart, sEnd); } } else { LeadingMarginSpan span = getAssignSpan(getSpanClass(), start, end); getEditableText().removeSpan(span); removeReplacementIfExist(start); } } }
@Override public boolean changeStatusBySelectionChanged(int start, int end) { HolderSpan[] holderSpans = getAssignSpans(HolderSpan.class, start - 1, start); for (HolderSpan span : holderSpans) { if (span.getInnerSpan().getClass().equals(getSpanClass())) { return true; } } LeadingMarginSpan[] spans = getEditableText().getSpans(start - 1, start, getSpanClass()); return (spans.length != 0 && isRangeInSpan(spans[0], start, end)); }
private void writeSingleParagraphStyle(ParagraphStyle style, DataOutputStream dos) throws IOException { Class clazz = style.getClass(); dos.writeInt(mString.getSpanStart(style)); dos.writeInt(mString.getSpanEnd(style)); dos.writeInt(mString.getSpanFlags(style)); if (mCharacterStylesTags.containsKey(clazz.getSimpleName())) { int tag = mCharacterStylesTags.get(clazz.getSimpleName()); if (mCharacterStylesTags.containsKey(clazz.getSimpleName())) { dos.writeInt(tag); } switch (tag) { case 24: // AligmentSpan.Standard AlignmentSpan.Standard as2 = (AlignmentSpan.Standard)style; dos.writeInt(as2.getAlignment().ordinal()); break; case 25: // BulletSpan BulletSpan bs = (BulletSpan)style; dos.writeInt(bs.getLeadingMargin(true)); dos.writeInt(bs.getLeadingMargin(false)); break; case 30: // LeadingMarginSpan.Sandard LeadingMarginSpan.Standard lms = (LeadingMarginSpan.Standard)style; dos.writeInt(lms.getLeadingMargin(true)); dos.writeInt(lms.getLeadingMargin(false)); break; case 34: // QuoteSpan QuoteSpan qs = (QuoteSpan)style; dos.writeInt(qs.getColor()); break; case 36: // TabStopSpan.Standard TabStopSpan.Standard tss = (TabStopSpan.Standard)style; dos.writeInt(tss.getTabStop()); break; default: } } else { write(style,dos); } }
private SpanPlacementInfo readSingleParagraph(DataInputStream dis) throws IOException { SpanPlacementInfo spi = new SpanPlacementInfo(); spi.start = dis.readInt(); spi.end = dis.readInt(); spi.mode = dis.readInt(); int tag = dis.readInt(); // mCharacterStylesTags.get(clazz.getSimpleName()); switch (tag) { case 24: // AligmentSpan.Standard spi.span = new AlignmentSpan.Standard(Alignment.values()[dis.readInt()]); break; case 25: // BulletSpan spi.span = new BulletSpan(dis.readInt()); dis.readInt(); // skip gap width for other lines break; case 30: // LeadingMarginSpan.Sandard spi.span = new LeadingMarginSpan.Standard(dis.readInt(),dis.readInt()); break; case 34: // QuoteSpan spi.span = new QuoteSpan(dis.readInt()); break; case 36: // TabStopSpan.Standard spi.span = new TabStopSpan.Standard(dis.readInt()); break; case 80: // RemoteDrawableSpan break; default: spi.span = read(tag,dis); } return spi; }
public TextLine(ReflowState state, int lineStartAt, LeadingMarginSpan leadingMarginSpan) { this.whitespaces = state.whitespaces; this.width = state.lineWidth; LineSpan span = state.carrierReturnSpan; // FIXME: after carrier return on span.ends state must eliminate carrierReturnSpan ? this.span = new WeakReference<LineSpan>(span); this.afterBreak = state.carrierReturnBreak == null ? null : new WeakReference<LineSpanBreak>(state.carrierReturnBreak); this.start = lineStartAt; this.height = state.height; // (int) (state.height + state.descent + state.leading * lineSpacingMultiplier + lineSpacingAdd); this.descent = state.descent; this.end = state.character + 1; if (state.character > lineStartAt) this.leadingMargin = leadingMarginSpan; }
@Override public void closeOrderedListItem(SpannableStringBuilder out) { OrderedList orderedList = getLast(out, OrderedList.class); if (orderedList != null) { int number = orderedList.getAndIncrement(); int where = out.getSpanStart(getLast(out, OrderedListItem.class)); out.insert(where, Integer.toString(number) + ". "); } //check BulletSpan2 end(out, OrderedListItem.class, new LeadingMarginSpan.LeadingMarginSpan2.Standard(leading)); }
public static Node leadingMargin(Integer every, Object... nodes) { return new SpanNode(new LeadingMarginSpan.Standard(every), nodes); }
public static Node leadingMargin(Integer first, Integer rest, Object... nodes) { return new SpanNode(new LeadingMarginSpan.Standard(first, rest), nodes); }
public void handleTagNode(TagNode node, SpannableStringBuilder builder, int start, int end) { builder.setSpan(new LeadingMarginSpan.Standard(30), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); this.appendNewLine(builder); }
public Printer tab() { return pushSpan(new LeadingMarginSpan.Standard(tabWidth)); }
@Override protected Class<? extends LeadingMarginSpan> getSpanClass() { return RichQuoteSpan.class; }
@Override protected Class<? extends LeadingMarginSpan> getSpanClass() { return RichBulletSpan.class; }
public HolderSpan(LeadingMarginSpan span) { this.span = span; }
public LeadingMarginSpan getInnerSpan() { return span; }
@Override public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader){ if (tag.equalsIgnoreCase("ul")){ if (opening){ lists.push(tag); } else { lists.pop(); } } else if (tag.equalsIgnoreCase("ol")){ if (opening){ lists.push(tag); olNextIndex.push(1); } else { lists.pop(); olNextIndex.pop(); } } else if (tag.equalsIgnoreCase("li")){ if (opening){ if (output.length() > 0 && output.charAt(output.length() - 1) != '\n'){ output.append("\n"); } String parentList = lists.peek(); if (parentList.equalsIgnoreCase("ol")){ start(output, new Ol()); output.append(olNextIndex.peek().toString()).append(". "); olNextIndex.push(olNextIndex.pop() + 1); } else if (parentList.equalsIgnoreCase("ul")){ start(output, new Ul()); } } else { if (lists.peek().equalsIgnoreCase("ul")){ if (output.charAt(output.length() - 1) != '\n'){ output.append("\n"); } // Nested BulletSpans increases distance between bullet and text, so we must prevent it. int bulletMargin = indent; if (lists.size() > 1){ bulletMargin = indent - bullet.getLeadingMargin(true); if (lists.size() > 2){ // This gets more complicated when we add a LeadingMarginSpan into the same line: // we have also counter it's effect to BulletSpan bulletMargin -= (lists.size() - 2) * listItemIndent; } } BulletSpan newBullet = new BulletSpan(bulletMargin); end(output, Ul.class, new LeadingMarginSpan.Standard(listItemIndent * (lists.size() - 1)), newBullet); } else if (lists.peek().equalsIgnoreCase("ol")){ if (output.charAt(output.length() - 1) != '\n'){ output.append("\n"); } int numberMargin = listItemIndent * (lists.size() - 1); if (lists.size() > 2){ // Same as in ordered lists: counter the effect of nested Spans numberMargin -= (lists.size() - 2) * listItemIndent; } end(output, Ol.class, new LeadingMarginSpan.Standard(numberMargin)); } } } else { if (opening){ Log.d("TagHandler", "Found an unsupported tag " + tag); } } }
@Override public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) { if (tag.equalsIgnoreCase("ul")) { if (opening) { lists.push(tag); } else { lists.pop(); } } else if (tag.equalsIgnoreCase("ol")) { if (opening) { lists.push(tag); olNextIndex.push(Integer.valueOf(1)).toString();//TODO: add support for lists starting other index than 1 } else { lists.pop(); olNextIndex.pop().toString(); } } else if (tag.equalsIgnoreCase("li")) { if (opening) { if (output.length() > 0 && output.charAt(output.length() - 1) != '\n') { output.append("\n"); } String parentList = lists.peek(); if (parentList.equalsIgnoreCase("ol")) { start(output, new Ol()); output.append(olNextIndex.peek().toString() + ". "); olNextIndex.push(Integer.valueOf(olNextIndex.pop().intValue() + 1)); } else if (parentList.equalsIgnoreCase("ul")) { start(output, new Ul()); } } else { if (lists.peek().equalsIgnoreCase("ul")) { if ( output.length() > 0 && output.charAt(output.length() - 1) != '\n' ) { output.append("\n"); } // Nested BulletSpans increases distance between bullet and text, so we must prevent it. int bulletMargin = indent; if (lists.size() > 1) { bulletMargin = indent-bullet.getLeadingMargin(true); if (lists.size() > 2) { // This get's more complicated when we add a LeadingMarginSpan into the same line: // we have also counter it's effect to BulletSpan bulletMargin -= (lists.size() - 2) * listItemIndent; } } BulletSpan newBullet = new BulletSpan(bulletMargin); end(output, Ul.class, new LeadingMarginSpan.Standard(listItemIndent * (lists.size() - 1)), newBullet); } else if (lists.peek().equalsIgnoreCase("ol")) { if ( output.length() > 0 && output.charAt(output.length() - 1) != '\n' ) { output.append("\n"); } int numberMargin = listItemIndent * (lists.size() - 1); if (lists.size() > 2) { // Same as in ordered lists: counter the effect of nested Spans numberMargin -= (lists.size() - 2) * listItemIndent; } end(output, Ol.class, new LeadingMarginSpan.Standard(numberMargin)); } } } else { if (opening) Log.d("TagHandler", "Found an unsupported tag " + tag); } }
/** * Processes a single list item. * * @param opening is this the opening tag? * @see <a href="https://bitbucket.org/Kuitsi/android-textview-html-list">Kuitsi/android-textview-html-list</a> */ private void processListItem(boolean opening, Editable output) { if (opening) { if (output.length() > 0 && output.charAt(output.length() - 1) != '\n') { output.append("\n"); } String parentList = lists.peek(); if (parentList.equalsIgnoreCase("ol")) { start(output, new Ol()); output.append(olNextIndex.peek().toString()).append(". "); olNextIndex.push(olNextIndex.pop() + 1); } else if (parentList.equalsIgnoreCase("ul")) { start(output, new Ul()); } } else { if (lists.peek().equalsIgnoreCase("ul")) { if (output.length() > 0 && output.charAt(output.length() - 1) != '\n') { output.append("\n"); } // Nested BulletSpans increases distance between bullet and text, so we must prevent it. int bulletMargin = indent; if (lists.size() > 1) { bulletMargin = indent - bullet.getLeadingMargin(true); if (lists.size() > 2) { // This get's more complicated when we add a LeadingMarginSpan into the same line: // we have also counter it's effect to BulletSpan bulletMargin -= (lists.size() - 2) * listItemIndent; } } BulletSpan newBullet = new BulletSpan(bulletMargin); end(output, Ul.class, new LeadingMarginSpan.Standard(listItemIndent * (lists.size() - 1)), newBullet); } else if (lists.peek().equalsIgnoreCase("ol")) { if (output.length() > 0 && output.charAt(output.length() - 1) != '\n') { output.append("\n"); } int numberMargin = listItemIndent * (lists.size() - 1); if (lists.size() > 2) { // Same as in ordered lists: counter the effect of nested Spans numberMargin -= (lists.size() - 2) * listItemIndent; } end(output, Ol.class, new LeadingMarginSpan.Standard(numberMargin)); } } }
@Override public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) { if (tag.equalsIgnoreCase("ul")) { if (opening) { lists.push(tag); } else { lists.pop(); } } else if (tag.equalsIgnoreCase("ol")) { if (opening) { lists.push(tag); olNextIndex.push(Integer.valueOf(1)).toString();//TODO: add support for lists starting other index than 1 } else { lists.pop(); olNextIndex.pop().toString(); } } else if (tag.equalsIgnoreCase("li")) { if (opening) { if (output.length() > 0 && output.charAt(output.length() - 1) != '\n') { output.append("\n"); } String parentList = lists.peek(); if (parentList.equalsIgnoreCase("ol")) { start(output, new Ol()); output.append(olNextIndex.peek().toString() + ". "); olNextIndex.push(Integer.valueOf(olNextIndex.pop().intValue() + 1)); } else if (parentList.equalsIgnoreCase("ul")) { start(output, new Ul()); } } else { if (lists.peek().equalsIgnoreCase("ul")) { if (output.length() > 0 && output.charAt(output.length() - 1) != '\n') { output.append("\n"); } // Nested BulletSpans increases distance between bullet and text, so we must prevent it. int bulletMargin = indent; if (lists.size() > 1) { bulletMargin = indent - bullet.getLeadingMargin(true); if (lists.size() > 2) { // This get's more complicated when we add a LeadingMarginSpan into the same line: // we have also counter it's effect to BulletSpan bulletMargin -= (lists.size() - 2) * listItemIndent; } } BulletSpan newBullet = new BulletSpan(bulletMargin, mBulletColor, mBulletRadius); end(output, Ul.class, new LeadingMarginSpan.Standard(listItemIndent * (lists.size() - 1)), newBullet); } else if (lists.peek().equalsIgnoreCase("ol")) { if (output.length() > 0 && output.charAt(output.length() - 1) != '\n') { output.append("\n"); } int numberMargin = listItemIndent * (lists.size() - 1); if (lists.size() > 2) { // Same as in ordered lists: counter the effect of nested Spans numberMargin -= (lists.size() - 2) * listItemIndent; } end(output, Ol.class, new LeadingMarginSpan.Standard(numberMargin)); } } } else { if (opening) { Log.d("TagHandler", "Found an unsupported tag " + tag); } } }
@Override public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) { if (tag.equalsIgnoreCase("ul")) { if (opening) { lists.push(tag); } else { lists.pop(); } } else if (tag.equalsIgnoreCase("ol")) { if (opening) { lists.push(tag); olNextIndex.push(Integer.valueOf(1)).toString();// TODO: add support for lists starting other index than 1 } else { lists.pop(); olNextIndex.pop().toString(); } } else if (tag.equalsIgnoreCase("li")) { if (opening) { if (output.length() > 0 && output.charAt(output.length() - 1) != '\n') { output.append("\n"); } String parentList = lists.peek(); if (parentList.equalsIgnoreCase("ol")) { start(output, new Ol()); output.append(olNextIndex.peek().toString() + ". "); olNextIndex.push(Integer.valueOf(olNextIndex.pop().intValue() + 1)); } else if (parentList.equalsIgnoreCase("ul")) { start(output, new Ul()); } } else { if (lists.peek().equalsIgnoreCase("ul")) { if (output.charAt(output.length() - 1) != '\n') { output.append("\n"); } // Nested BulletSpans increases distance between bullet and text, so we must prevent it. int bulletMargin = indent; if (lists.size() > 1) { bulletMargin = indent - bullet.getLeadingMargin(true); if (lists.size() > 2) { // This get's more complicated when we add a LeadingMarginSpan into the same line: // we have also counter it's effect to BulletSpan bulletMargin -= (lists.size() - 2) * listItemIndent; } } BulletSpan newBullet = new BulletSpan(bulletMargin); end(output, Ul.class, new LeadingMarginSpan.Standard(listItemIndent * (lists.size() - 1)), newBullet); } else if (lists.peek().equalsIgnoreCase("ol")) { if (output.charAt(output.length() - 1) != '\n') { output.append("\n"); } int numberMargin = listItemIndent * (lists.size() - 1); if (lists.size() > 2) { // Same as in ordered lists: counter the effect of nested Spans numberMargin -= (lists.size() - 2) * listItemIndent; } end(output, Ol.class, new LeadingMarginSpan.Standard(numberMargin)); } } } else if (tag.equalsIgnoreCase("code")) { if (opening) { output.setSpan(new TypefaceSpan("monospace"), output.length(), output.length(), Spannable.SPAN_MARK_MARK); } else { L.d("Code tag encountered"); Object obj = getLast(output, TypefaceSpan.class); int where = output.getSpanStart(obj); output.setSpan(new TypefaceSpan("monospace"), where, output.length(), 0); output.setSpan(new BackgroundColorSpan(Color.parseColor("#f1f1ff")), where, output.length(), 0); } } else { if (opening) L.d("Found an unsupported tag " + tag); } }