diff --git a/app/build.gradle b/app/build.gradle index fab6b399..bc2bca96 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -19,7 +19,7 @@ android { buildTypes { debug { - minifyEnabled true + minifyEnabled false proguardFile 'proguard.pro' } } diff --git a/app/src/main/java/ru/noties/markwon/MainActivity.java b/app/src/main/java/ru/noties/markwon/MainActivity.java index 8b5b10dc..8e419426 100644 --- a/app/src/main/java/ru/noties/markwon/MainActivity.java +++ b/app/src/main/java/ru/noties/markwon/MainActivity.java @@ -2,8 +2,12 @@ package ru.noties.markwon; import android.app.Activity; import android.content.Intent; +import android.graphics.Canvas; +import android.graphics.Paint; import android.net.Uri; import android.os.Bundle; +import android.text.Layout; +import android.text.style.LeadingMarginSpan; import android.view.View; import android.widget.TextView; @@ -58,6 +62,56 @@ public class MainActivity extends Activity { appBarRenderer.render(appBarState()); + if (false) { + + final class Whatever { + CharSequence text() { + + final SpannableBuilder builder = new SpannableBuilder(); + + builder.append("First line\n\n"); + builder.append(Markwon.markdown(MainActivity.this, "* first\n* second\n* * third\n* * * forth\n\n")); + builder.setSpan(new LeadingMarginSpan() { + @Override + public int getLeadingMargin(boolean first) { + return 100; + } + + @Override + public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom, CharSequence text, int start, int end, boolean first, Layout layout) { + + } + }, 0); + + builder.append("Last line\n\n"); + return builder.text(); + } + } + final Whatever whatever = new Whatever(); + + final SpannableBuilder builder = new SpannableBuilder(); + builder.append(whatever.text()); + builder.append(whatever.text()); + + builder.setSpan(new LeadingMarginSpan() { + @Override + public int getLeadingMargin(boolean first) { + return 50; + } + + @Override + public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom, CharSequence text, int start, int end, boolean first, Layout layout) { + + } + }, 0); + + builder.append(whatever.text()); + + textView.setText(builder.text()); + + return; + } + markdownLoader.load(uri(), new MarkdownLoader.OnMarkdownTextLoaded() { @Override public void apply(final String text) { diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index b24d050e..7e238b79 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -17,6 +17,7 @@ android:layout_margin="16dip" android:lineSpacingExtra="2dip" android:textSize="16sp" + android:textDirection="rtl" tools:context="ru.noties.markwon.MainActivity" tools:text="yo\nman" /> diff --git a/library/src/main/java/ru/noties/markwon/SpannableBuilder.java b/library/src/main/java/ru/noties/markwon/SpannableBuilder.java new file mode 100644 index 00000000..e8715874 --- /dev/null +++ b/library/src/main/java/ru/noties/markwon/SpannableBuilder.java @@ -0,0 +1,208 @@ +package ru.noties.markwon; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.SpannableStringBuilder; +import android.text.Spanned; + +import java.util.ArrayDeque; +import java.util.Deque; + +/** + * This class is used to _revert_ order of applied spans. Original SpannableStringBuilder + * is using an array to store all the information about spans. So, a span that is added first + * will be drawn first, which leads to subtle bugs (spans receive wrong `x` values when + * requested to draw itself) + */ +public class SpannableBuilder { + + // do not implement CharSequence (or any of Spanned interfaces) + + // we will be using SpannableStringBuilder anyway as a backing store + // as it has tight connection with system (implements some hidden methods, etc) + private final SpannableStringBuilder builder; + private final Deque spans = new ArrayDeque<>(8); + + public SpannableBuilder() { + this(null); + } + + public SpannableBuilder(@Nullable CharSequence cs) { + + final CharSequence text; + + if (cs != null) { + text = cs; + } else { + text = null; + } + + if (text == null) { + this.builder = new SpannableStringBuilderImpl(); + } else { + this.builder = new SpannableStringBuilderImpl(text.toString()); + copySpans(text); + } + } + + /** + * Additional method that takes a String, which is proven to NOT contain any spans + * + * @param text String to append + * @return this instance + */ + @NonNull + public SpannableBuilder append(@NonNull String text) { + builder.append(text); + return this; + } + + @NonNull + public SpannableBuilder append(char c) { + builder.append(c); + return this; + } + + @NonNull + public SpannableBuilder append(@NonNull CharSequence cs) { + + copySpans(cs); + + builder.append(cs.toString()); + + return this; + } + + @NonNull + public SpannableBuilder append(@NonNull CharSequence cs, @NonNull Object span) { + final int length = length(); + append(cs); + setSpan(span, length); + return this; + } + + @NonNull + public SpannableBuilder append(@NonNull CharSequence cs, @NonNull Object span, int flags) { + final int length = length(); + append(cs); + setSpan(span, length, length(), flags); + return this; + } + + @NonNull + public SpannableBuilder setSpan(@NonNull Object span, int start) { + return setSpan(span, start, length()); + } + + @NonNull + public SpannableBuilder setSpan(@NonNull Object span, int start, int end) { + return setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + + @NonNull + public SpannableBuilder setSpan(@NonNull Object span, int start, int end, int flags) { + spans.push(new Span(span, start, end, flags)); + return this; + } + + public int length() { + return builder.length(); + } + + public char charAt(int index) { + return builder.charAt(index); + } + + public char lastChar() { + return builder.charAt(length() - 1); + } + + @Override + @NonNull + public String toString() { + return builder.toString(); + } + + // Unfortunately I cannot see any way to NOT expose this internal value, which opens a gate + // to external modification (first of all InputFilters, that potentially break span indexes + // as we keep track of them independently). Must warn user to NOT apply inputFilters + @NonNull + public CharSequence text() { + applySpans(); + return builder; + } + + private void copySpans(@Nullable CharSequence cs) { + + // we must identify already reversed Spanned... + // and (!) iterate backwards when adding (to preserve order) + + if (cs instanceof Spanned) { + + final Spanned spanned = (Spanned) cs; + final boolean reverse = spanned instanceof SpannedReversed; + final int index = length(); + + final Object[] spans = spanned.getSpans(0, spanned.length(), Object.class); + + iterate(reverse, spans, new Action() { + @Override + public void apply(Object o) { + setSpan( + o, + index + spanned.getSpanStart(o), + index + spanned.getSpanEnd(o), + spanned.getSpanFlags(o) + ); + } + }); + } + } + + private void applySpans() { + + // will apply appended spans in reverse order + // clear the stack (that keeps track of them) + + Span span; + while ((span = spans.poll()) != null) { + builder.setSpan(span.what, span.start, span.end, span.flags); + } + } + + private static class Span { + + final Object what; + final int start; + final int end; + final int flags; + + Span(@NonNull Object what, int start, int end, int flags) { + this.what = what; + this.start = start; + this.end = end; + this.flags = flags; + } + } + + private interface Action { + void apply(Object o); + } + + private static void iterate(boolean reverse, @Nullable Object[] array, @NonNull Action action) { + final int length = array != null + ? array.length + : 0; + if (length > 0) { + if (reverse) { + for (int i = length - 1; i >= 0; i--) { + action.apply(array[i]); + } + } else { + for (int i = 0; i < length; i++) { + action.apply(array[i]); + } + } + } + } +} diff --git a/library/src/main/java/ru/noties/markwon/SpannableStringBuilderImpl.java b/library/src/main/java/ru/noties/markwon/SpannableStringBuilderImpl.java new file mode 100644 index 00000000..de207939 --- /dev/null +++ b/library/src/main/java/ru/noties/markwon/SpannableStringBuilderImpl.java @@ -0,0 +1,14 @@ +package ru.noties.markwon; + +import android.text.SpannableStringBuilder; + +class SpannableStringBuilderImpl extends SpannableStringBuilder implements SpannedReversed { + + SpannableStringBuilderImpl() { + super(); + } + + SpannableStringBuilderImpl(CharSequence text) { + super(text); + } +} diff --git a/library/src/main/java/ru/noties/markwon/SpannedReversed.java b/library/src/main/java/ru/noties/markwon/SpannedReversed.java new file mode 100644 index 00000000..a5ad65eb --- /dev/null +++ b/library/src/main/java/ru/noties/markwon/SpannedReversed.java @@ -0,0 +1,6 @@ +package ru.noties.markwon; + +import android.text.Spanned; + +interface SpannedReversed extends Spanned { +} diff --git a/library/src/main/java/ru/noties/markwon/renderer/SpannableMarkdownVisitor.java b/library/src/main/java/ru/noties/markwon/renderer/SpannableMarkdownVisitor.java index f0bbf912..e104d5fd 100644 --- a/library/src/main/java/ru/noties/markwon/renderer/SpannableMarkdownVisitor.java +++ b/library/src/main/java/ru/noties/markwon/renderer/SpannableMarkdownVisitor.java @@ -1,7 +1,6 @@ package ru.noties.markwon.renderer; import android.support.annotation.NonNull; -import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; import android.text.style.StrikethroughSpan; @@ -39,6 +38,7 @@ import java.util.ArrayList; import java.util.Deque; import java.util.List; +import ru.noties.markwon.SpannableBuilder; import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.renderer.html.SpannableHtmlParser; import ru.noties.markwon.spans.AsyncDrawable; @@ -61,7 +61,8 @@ import ru.noties.markwon.tasklist.TaskListItem; public class SpannableMarkdownVisitor extends AbstractVisitor { private final SpannableConfiguration configuration; - private final SpannableStringBuilder builder; + // private final SpannableStringBuilder builder; + private final SpannableBuilder builder; private final Deque htmlInlineItems; private int blockQuoteIndent; @@ -73,7 +74,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor { public SpannableMarkdownVisitor( @NonNull SpannableConfiguration configuration, - @NonNull SpannableStringBuilder builder + @NonNull SpannableBuilder builder ) { this.configuration = configuration; this.builder = builder; @@ -201,10 +202,10 @@ public class SpannableMarkdownVisitor extends AbstractVisitor { visitChildren(listItem); + // todo| in order to provide real RTL experience there must be a way to provide this string setSpan(length, new OrderedListItemSpan( configuration.theme(), - String.valueOf(start) + "." + '\u00a0', - blockQuoteIndent + String.valueOf(start) + "." + '\u00a0' )); // after we have visited the children increment start number @@ -217,7 +218,6 @@ public class SpannableMarkdownVisitor extends AbstractVisitor { setSpan(length, new BulletListItemSpan( configuration.theme(), - blockQuoteIndent, listLevel - 1 )); } @@ -248,11 +248,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor { final int length = builder.length(); visitChildren(heading); - setSpan(length, new HeadingSpan( - configuration.theme(), - heading.getLevel(), - builder.length() - length) - ); + setSpan(length, new HeadingSpan(configuration.theme(), heading.getLevel())); newLine(); @@ -311,7 +307,6 @@ public class SpannableMarkdownVisitor extends AbstractVisitor { setSpan(length, new TaskListSpan( configuration.theme(), blockQuoteIndent, - length, listItem.done() )); @@ -326,6 +321,10 @@ public class SpannableMarkdownVisitor extends AbstractVisitor { private boolean handleTableNodes(CustomNode node) { + if (true) { + return false; + } + final boolean handled; if (node instanceof TableBody) { @@ -367,11 +366,12 @@ public class SpannableMarkdownVisitor extends AbstractVisitor { if (pendingTableRow == null) { pendingTableRow = new ArrayList<>(2); } - pendingTableRow.add(new TableRowSpan.Cell( - tableCellAlignment(cell.getAlignment()), - builder.subSequence(length, builder.length()) - )); - builder.replace(length, builder.length(), ""); + +// pendingTableRow.add(new TableRowSpan.Cell( +// tableCellAlignment(cell.getAlignment()), +// builder.subSequence(length, builder.length()) +// )); +// builder.replace(length, builder.length(), ""); tableRowIsHeader = cell.isHeader(); @@ -497,7 +497,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor { private void newLine() { if (builder.length() > 0 - && '\n' != builder.charAt(builder.length() - 1)) { + && '\n' != builder.lastChar()) { builder.append('\n'); } } diff --git a/library/src/main/java/ru/noties/markwon/renderer/SpannableRenderer.java b/library/src/main/java/ru/noties/markwon/renderer/SpannableRenderer.java index 25073964..f7b75939 100644 --- a/library/src/main/java/ru/noties/markwon/renderer/SpannableRenderer.java +++ b/library/src/main/java/ru/noties/markwon/renderer/SpannableRenderer.java @@ -2,10 +2,10 @@ package ru.noties.markwon.renderer; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.text.SpannableStringBuilder; import org.commonmark.node.Node; +import ru.noties.markwon.SpannableBuilder; import ru.noties.markwon.SpannableConfiguration; public class SpannableRenderer { @@ -16,9 +16,9 @@ public class SpannableRenderer { if (node == null) { out = null; } else { - final SpannableStringBuilder builder = new SpannableStringBuilder(); + final SpannableBuilder builder = new SpannableBuilder(); node.accept(new SpannableMarkdownVisitor(configuration, builder)); - out = builder; + out = builder.text(); } return out; } diff --git a/library/src/main/java/ru/noties/markwon/spans/AsyncDrawableSpan.java b/library/src/main/java/ru/noties/markwon/spans/AsyncDrawableSpan.java index 25d01b00..c74a1305 100644 --- a/library/src/main/java/ru/noties/markwon/spans/AsyncDrawableSpan.java +++ b/library/src/main/java/ru/noties/markwon/spans/AsyncDrawableSpan.java @@ -29,9 +29,6 @@ public class AsyncDrawableSpan extends ReplacementSpan { private final int alignment; private final boolean replacementTextIsLink; - private int lastKnownDrawX; - private int lastKnownDrawY; - public AsyncDrawableSpan(@NonNull SpannableTheme theme, @NonNull AsyncDrawable drawable) { this(theme, drawable, ALIGN_BOTTOM); } @@ -112,9 +109,6 @@ public class AsyncDrawableSpan extends ReplacementSpan { int bottom, @NonNull Paint paint) { - this.lastKnownDrawX = (int) (x + .5F); - this.lastKnownDrawY = y; - final AsyncDrawable drawable = this.drawable; if (drawable.hasResult()) { @@ -154,12 +148,4 @@ public class AsyncDrawableSpan extends ReplacementSpan { public AsyncDrawable getDrawable() { return drawable; } - - public int lastKnownDrawX() { - return lastKnownDrawX; - } - - public int lastKnownDrawY() { - return lastKnownDrawY; - } } diff --git a/library/src/main/java/ru/noties/markwon/spans/BlockQuoteSpan.java b/library/src/main/java/ru/noties/markwon/spans/BlockQuoteSpan.java index 865f9cd2..66b6a3e1 100644 --- a/library/src/main/java/ru/noties/markwon/spans/BlockQuoteSpan.java +++ b/library/src/main/java/ru/noties/markwon/spans/BlockQuoteSpan.java @@ -43,8 +43,16 @@ public class BlockQuoteSpan implements LeadingMarginSpan { theme.applyBlockQuoteStyle(paint); - final int left = theme.getBlockMargin() * (indent - 1); - rect.set(left, top, left + width, bottom); + final int left; + final int right; + { + final int l = x + (dir * width); + final int r = l + (dir * width); + left = Math.min(l, r); + right = Math.max(l, r); + } + + rect.set(left, top, right, bottom); c.drawRect(rect, paint); } diff --git a/library/src/main/java/ru/noties/markwon/spans/BulletListItemSpan.java b/library/src/main/java/ru/noties/markwon/spans/BulletListItemSpan.java index c387a504..7beda477 100644 --- a/library/src/main/java/ru/noties/markwon/spans/BulletListItemSpan.java +++ b/library/src/main/java/ru/noties/markwon/spans/BulletListItemSpan.java @@ -17,15 +17,12 @@ public class BulletListItemSpan implements LeadingMarginSpan { private final RectF circle = ObjectsPool.rectF(); private final Rect rectangle = ObjectsPool.rect(); - private final int blockIndent; private final int level; public BulletListItemSpan( @NonNull SpannableTheme theme, - @IntRange(from = 0) int blockIndent, @IntRange(from = 0) int level) { this.theme = theme; - this.blockIndent = blockIndent; this.level = level; } @@ -38,7 +35,8 @@ public class BulletListItemSpan implements LeadingMarginSpan { public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom, CharSequence text, int start, int end, boolean first, Layout layout) { // if there was a line break, we don't need to draw anything - if (!first) { + if (!first + || !LeadingMarginUtils.selfStart(start, text, this)) { return; } @@ -57,9 +55,16 @@ public class BulletListItemSpan implements LeadingMarginSpan { final int marginLeft = (width - side) / 2; final int marginTop = (height - side) / 2; - final int l = (width * (blockIndent - 1)) + marginLeft; + // in order to support RTL + final int l; + final int r; + { + final int left = x + (dir * marginLeft); + final int right = left + (dir * side); + l = Math.min(left, right); + r = Math.max(left, right); + } final int t = top + marginTop; - final int r = l + side; final int b = t + side; if (level == 0 diff --git a/library/src/main/java/ru/noties/markwon/spans/CodeSpan.java b/library/src/main/java/ru/noties/markwon/spans/CodeSpan.java index db4e0553..0149503c 100644 --- a/library/src/main/java/ru/noties/markwon/spans/CodeSpan.java +++ b/library/src/main/java/ru/noties/markwon/spans/CodeSpan.java @@ -52,7 +52,17 @@ public class CodeSpan extends MetricAffectingSpan implements LeadingMarginSpan { paint.setStyle(Paint.Style.FILL); paint.setColor(theme.getCodeBackgroundColor(p)); - rect.set(x, top, c.getWidth(), bottom); + final int left; + final int right; + if (dir > 0) { + left = x; + right = c.getWidth(); + } else { + left = x - c.getWidth(); + right = x; + } + + rect.set(left, top, right, bottom); c.drawRect(rect, paint); } diff --git a/library/src/main/java/ru/noties/markwon/spans/HeadingSpan.java b/library/src/main/java/ru/noties/markwon/spans/HeadingSpan.java index fc6227eb..0931170e 100644 --- a/library/src/main/java/ru/noties/markwon/spans/HeadingSpan.java +++ b/library/src/main/java/ru/noties/markwon/spans/HeadingSpan.java @@ -16,12 +16,10 @@ public class HeadingSpan extends MetricAffectingSpan implements LeadingMarginSpa private final Rect rect = ObjectsPool.rect(); private final Paint paint = ObjectsPool.paint(); private final int level; - private final int textLength; - public HeadingSpan(@NonNull SpannableTheme theme, @IntRange(from = 1, to = 6) int level, @IntRange(from = 0) int textLength) { + public HeadingSpan(@NonNull SpannableTheme theme, @IntRange(from = 1, to = 6) int level) { this.theme = theme; this.level = level; - this.textLength = textLength; } @Override @@ -47,20 +45,28 @@ public class HeadingSpan extends MetricAffectingSpan implements LeadingMarginSpa @Override public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom, CharSequence text, int start, int end, boolean first, Layout layout) { - if (level == 1 - || level == 2) { + if ((level == 1 || level == 2) + && LeadingMarginUtils.selfEnd(end, text, this)) { - if ((start + textLength) == end) { - paint.set(p); + paint.set(p); - theme.applyHeadingBreakStyle(paint); + theme.applyHeadingBreakStyle(paint); - final float height = paint.getStrokeWidth(); - final int b = (int) (bottom - height + .5F); + final float height = paint.getStrokeWidth(); + final int b = (int) (bottom - height + .5F); - rect.set(x, b, c.getWidth(), bottom); - c.drawRect(rect, paint); + final int left; + final int right; + if (dir > 0) { + left = x; + right = c.getWidth(); + } else { + left = x - c.getWidth(); + right = x; } + + rect.set(left, b, right, bottom); + c.drawRect(rect, paint); } } } diff --git a/library/src/main/java/ru/noties/markwon/spans/LeadingMarginUtils.java b/library/src/main/java/ru/noties/markwon/spans/LeadingMarginUtils.java new file mode 100644 index 00000000..ab1a7de3 --- /dev/null +++ b/library/src/main/java/ru/noties/markwon/spans/LeadingMarginUtils.java @@ -0,0 +1,17 @@ +package ru.noties.markwon.spans; + +import android.text.Spanned; + +abstract class LeadingMarginUtils { + + static boolean selfStart(int start, CharSequence text, Object span) { + return text instanceof Spanned && ((Spanned) text).getSpanStart(span) == start; + } + + static boolean selfEnd(int end, CharSequence text, Object span) { + return text instanceof Spanned && ((Spanned) text).getSpanEnd(span) == end; + } + + private LeadingMarginUtils() { + } +} diff --git a/library/src/main/java/ru/noties/markwon/spans/OrderedListItemSpan.java b/library/src/main/java/ru/noties/markwon/spans/OrderedListItemSpan.java index e46f7344..7c76f052 100644 --- a/library/src/main/java/ru/noties/markwon/spans/OrderedListItemSpan.java +++ b/library/src/main/java/ru/noties/markwon/spans/OrderedListItemSpan.java @@ -2,7 +2,6 @@ package ru.noties.markwon.spans; import android.graphics.Canvas; import android.graphics.Paint; -import android.support.annotation.IntRange; import android.support.annotation.NonNull; import android.text.Layout; import android.text.style.LeadingMarginSpan; @@ -11,16 +10,13 @@ public class OrderedListItemSpan implements LeadingMarginSpan { private final SpannableTheme theme; private final String number; - private final int blockIndent; public OrderedListItemSpan( @NonNull SpannableTheme theme, - @NonNull String number, - @IntRange(from = 0) int blockIndent + @NonNull String number ) { this.theme = theme; this.number = number; - this.blockIndent = blockIndent; } @Override @@ -32,7 +28,8 @@ public class OrderedListItemSpan implements LeadingMarginSpan { public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom, CharSequence text, int start, int end, boolean first, Layout layout) { // if there was a line break, we don't need to draw anything - if (!first) { + if (!first + || !LeadingMarginUtils.selfStart(start, text, this)) { return; } @@ -40,10 +37,16 @@ public class OrderedListItemSpan implements LeadingMarginSpan { final int width = theme.getBlockMargin(); final int numberWidth = (int) (p.measureText(number) + .5F); - final int numberX = (width * blockIndent) - numberWidth; + + final int left; + if (dir > 0) { + left = x + (width * dir) - numberWidth; + } else { + left = x + (width * dir) + (width - numberWidth); + } final float numberY = CanvasUtils.textCenterY(top, bottom, p); - c.drawText(number, numberX, numberY, p); + c.drawText(number, left, numberY, p); } } diff --git a/library/src/main/java/ru/noties/markwon/spans/TaskListSpan.java b/library/src/main/java/ru/noties/markwon/spans/TaskListSpan.java index 1129c781..b56d48d7 100644 --- a/library/src/main/java/ru/noties/markwon/spans/TaskListSpan.java +++ b/library/src/main/java/ru/noties/markwon/spans/TaskListSpan.java @@ -14,13 +14,11 @@ public class TaskListSpan implements LeadingMarginSpan { private final SpannableTheme theme; private final int blockIndent; - private final int start; private final boolean isDone; - public TaskListSpan(@NonNull SpannableTheme theme, int blockIndent, int start, boolean isDone) { + public TaskListSpan(@NonNull SpannableTheme theme, int blockIndent, boolean isDone) { this.theme = theme; this.blockIndent = blockIndent; - this.start = start; this.isDone = isDone; } @@ -32,7 +30,8 @@ public class TaskListSpan implements LeadingMarginSpan { @Override public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom, CharSequence text, int start, int end, boolean first, Layout layout) { - if (!first) { + if (!first + || !LeadingMarginUtils.selfStart(start, text, this)) { return; } @@ -62,7 +61,13 @@ public class TaskListSpan implements LeadingMarginSpan { drawable.setState(state); } - final int l = (width * (blockIndent - 1)) + ((width - w) / 2); + final int l; + if (dir > 0) { + l = x + (width * (blockIndent - 1)) + ((width - w) / 2); + } else { + l = x - (width * blockIndent) + ((width - w) / 2); + } + final int t = top + ((height - h) / 2); c.translate(l, t); diff --git a/library/src/main/java/ru/noties/markwon/spans/ThematicBreakSpan.java b/library/src/main/java/ru/noties/markwon/spans/ThematicBreakSpan.java index 1c5355af..316e4312 100644 --- a/library/src/main/java/ru/noties/markwon/spans/ThematicBreakSpan.java +++ b/library/src/main/java/ru/noties/markwon/spans/ThematicBreakSpan.java @@ -33,7 +33,17 @@ public class ThematicBreakSpan implements LeadingMarginSpan { final int height = (int) (paint.getStrokeWidth() + .5F); final int halfHeight = (int) (height / 2.F + .5F); - rect.set(x, middle - halfHeight, c.getWidth(), middle + halfHeight); + final int left; + final int right; + if (dir > 0) { + left = x; + right = c.getWidth(); + } else { + left = x - c.getWidth(); + right = x; + } + + rect.set(left, middle - halfHeight, right, middle + halfHeight); c.drawRect(rect, paint); } }