diff --git a/README.md b/README.md
index 1e33a9f4..5fe29ccf 100644
--- a/README.md
+++ b/README.md
@@ -50,8 +50,10 @@ compile 'ru.noties:markwon-view:1.0.0' // optional
Taken with default configuration (except for image loading):
-
-
+
+
+
+
By default configuration uses TextView textColor for styling, so changing textColor changes style
diff --git a/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java b/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java
index 21b0ae7a..f276dfe2 100644
--- a/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java
+++ b/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java
@@ -3,6 +3,7 @@ package ru.noties.markwon;
import android.content.Context;
import android.net.Uri;
import android.os.Handler;
+import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@@ -11,6 +12,7 @@ import java.util.concurrent.Future;
import javax.inject.Inject;
+import ru.noties.debug.Debug;
import ru.noties.markwon.spans.AsyncDrawable;
@ActivityScope
@@ -57,8 +59,14 @@ public class MarkdownRenderer {
.urlProcessor(urlProcessor)
.build();
+ final long start = SystemClock.uptimeMillis();
+
final CharSequence text = Markwon.markdown(configuration, markdown);
+ final long end = SystemClock.uptimeMillis();
+
+ Debug.i("markdown rendered: %d ms", end - start);
+
if (!isCancelled()) {
handler.post(new Runnable() {
@Override
diff --git a/library/src/main/java/ru/noties/markwon/SpannableConfiguration.java b/library/src/main/java/ru/noties/markwon/SpannableConfiguration.java
index aa1af671..3b9332bd 100644
--- a/library/src/main/java/ru/noties/markwon/SpannableConfiguration.java
+++ b/library/src/main/java/ru/noties/markwon/SpannableConfiguration.java
@@ -3,6 +3,8 @@ package ru.noties.markwon;
import android.content.Context;
import android.support.annotation.NonNull;
+import ru.noties.markwon.renderer.html.ImageSizeResolver;
+import ru.noties.markwon.renderer.html.ImageSizeResolverDef;
import ru.noties.markwon.renderer.html.SpannableHtmlParser;
import ru.noties.markwon.spans.AsyncDrawable;
import ru.noties.markwon.spans.LinkSpan;
@@ -12,10 +14,12 @@ import ru.noties.markwon.spans.SpannableTheme;
public class SpannableConfiguration {
// creates default configuration
+ @NonNull
public static SpannableConfiguration create(@NonNull Context context) {
return new Builder(context).build();
}
+ @NonNull
public static Builder builder(@NonNull Context context) {
return new Builder(context);
}
@@ -27,7 +31,7 @@ public class SpannableConfiguration {
private final UrlProcessor urlProcessor;
private final SpannableHtmlParser htmlParser;
- private SpannableConfiguration(Builder builder) {
+ private SpannableConfiguration(@NonNull Builder builder) {
this.theme = builder.theme;
this.asyncDrawableLoader = builder.asyncDrawableLoader;
this.syntaxHighlight = builder.syntaxHighlight;
@@ -36,26 +40,32 @@ public class SpannableConfiguration {
this.htmlParser = builder.htmlParser;
}
+ @NonNull
public SpannableTheme theme() {
return theme;
}
+ @NonNull
public AsyncDrawable.Loader asyncDrawableLoader() {
return asyncDrawableLoader;
}
+ @NonNull
public SyntaxHighlight syntaxHighlight() {
return syntaxHighlight;
}
+ @NonNull
public LinkSpan.Resolver linkResolver() {
return linkResolver;
}
+ @NonNull
public UrlProcessor urlProcessor() {
return urlProcessor;
}
+ @NonNull
public SpannableHtmlParser htmlParser() {
return htmlParser;
}
@@ -70,60 +80,89 @@ public class SpannableConfiguration {
private LinkSpan.Resolver linkResolver;
private UrlProcessor urlProcessor;
private SpannableHtmlParser htmlParser;
+ private ImageSizeResolver imageSizeResolver;
- Builder(Context context) {
+ Builder(@NonNull Context context) {
this.context = context;
}
- public Builder theme(SpannableTheme theme) {
+ @NonNull
+ public Builder theme(@NonNull SpannableTheme theme) {
this.theme = theme;
return this;
}
- public Builder asyncDrawableLoader(AsyncDrawable.Loader asyncDrawableLoader) {
+ @NonNull
+ public Builder asyncDrawableLoader(@NonNull AsyncDrawable.Loader asyncDrawableLoader) {
this.asyncDrawableLoader = asyncDrawableLoader;
return this;
}
- public Builder syntaxHighlight(SyntaxHighlight syntaxHighlight) {
+ @NonNull
+ public Builder syntaxHighlight(@NonNull SyntaxHighlight syntaxHighlight) {
this.syntaxHighlight = syntaxHighlight;
return this;
}
- public Builder linkResolver(LinkSpan.Resolver linkResolver) {
+ @NonNull
+ public Builder linkResolver(@NonNull LinkSpan.Resolver linkResolver) {
this.linkResolver = linkResolver;
return this;
}
- public Builder urlProcessor(UrlProcessor urlProcessor) {
+ @NonNull
+ public Builder urlProcessor(@NonNull UrlProcessor urlProcessor) {
this.urlProcessor = urlProcessor;
return this;
}
- public Builder htmlParser(SpannableHtmlParser htmlParser) {
+ @NonNull
+ public Builder htmlParser(@NonNull SpannableHtmlParser htmlParser) {
this.htmlParser = htmlParser;
return this;
}
+ /**
+ * @since 1.0.1
+ */
+ @NonNull
+ public Builder imageSizeResolver(@NonNull ImageSizeResolver imageSizeResolver) {
+ this.imageSizeResolver = imageSizeResolver;
+ return this;
+ }
+
+ @NonNull
public SpannableConfiguration build() {
+
if (theme == null) {
theme = SpannableTheme.create(context);
}
+
if (asyncDrawableLoader == null) {
asyncDrawableLoader = new AsyncDrawableLoaderNoOp();
}
+
if (syntaxHighlight == null) {
syntaxHighlight = new SyntaxHighlightNoOp();
}
+
if (linkResolver == null) {
linkResolver = new LinkResolverDef();
}
+
if (urlProcessor == null) {
urlProcessor = new UrlProcessorNoOp();
}
+
if (htmlParser == null) {
- htmlParser = SpannableHtmlParser.create(theme, asyncDrawableLoader, urlProcessor, linkResolver);
+
+ if (imageSizeResolver == null) {
+ imageSizeResolver = new ImageSizeResolverDef();
+ }
+
+ htmlParser = SpannableHtmlParser.create(theme, asyncDrawableLoader, urlProcessor, linkResolver, imageSizeResolver);
}
+
return new SpannableConfiguration(this);
}
}
diff --git a/library/src/main/java/ru/noties/markwon/renderer/html/ImageProviderImpl.java b/library/src/main/java/ru/noties/markwon/renderer/html/ImageProviderImpl.java
index 3e45caee..54a5086f 100644
--- a/library/src/main/java/ru/noties/markwon/renderer/html/ImageProviderImpl.java
+++ b/library/src/main/java/ru/noties/markwon/renderer/html/ImageProviderImpl.java
@@ -1,10 +1,13 @@
package ru.noties.markwon.renderer.html;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextUtils;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
import ru.noties.markwon.UrlProcessor;
@@ -17,14 +20,18 @@ class ImageProviderImpl implements SpannableHtmlParser.ImageProvider {
private final SpannableTheme theme;
private final AsyncDrawable.Loader loader;
private final UrlProcessor urlProcessor;
+ private final ImageSizeResolver imageSizeResolver;
ImageProviderImpl(
@NonNull SpannableTheme theme,
@NonNull AsyncDrawable.Loader loader,
- @NonNull UrlProcessor urlProcessor) {
+ @NonNull UrlProcessor urlProcessor,
+ @NonNull ImageSizeResolver imageSizeResolver
+ ) {
this.theme = theme;
this.loader = loader;
this.urlProcessor = urlProcessor;
+ this.imageSizeResolver = imageSizeResolver;
}
@Override
@@ -47,7 +54,7 @@ class ImageProviderImpl implements SpannableHtmlParser.ImageProvider {
replacement = "\uFFFC";
}
- final AsyncDrawable drawable = new AsyncDrawable(destination, loader);
+ final AsyncDrawable drawable = new AsyncDrawable(destination, loader, imageSizeResolver, parseImageSize(attributes));
final AsyncDrawableSpan span = new AsyncDrawableSpan(theme, drawable);
final SpannableString string = new SpannableString(replacement);
@@ -60,4 +67,138 @@ class ImageProviderImpl implements SpannableHtmlParser.ImageProvider {
return spanned;
}
+
+ @Nullable
+ private static ImageSize parseImageSize(@NonNull Map attributes) {
+
+ final ImageSize imageSize;
+
+ final StyleProvider styleProvider = new StyleProvider(attributes.get("style"));
+
+ final ImageSize.Dimension width = parseDimension(extractDimension("width", attributes, styleProvider));
+ final ImageSize.Dimension height = parseDimension(extractDimension("height", attributes, styleProvider));
+
+ if (width == null
+ && height == null) {
+ imageSize = null;
+ } else {
+ imageSize = new ImageSize(width, height);
+ }
+
+ return imageSize;
+ }
+
+ @Nullable
+ private static String extractDimension(@NonNull String name, @NonNull Map attributes, @NonNull StyleProvider styleProvider) {
+
+ final String out;
+
+ final String inline = attributes.get(name);
+ if (!TextUtils.isEmpty(inline)) {
+ out = inline;
+ } else {
+ out = extractDimensionFromStyle(name, styleProvider);
+ }
+
+ return out;
+ }
+
+ @Nullable
+ private static String extractDimensionFromStyle(@NonNull String name, @NonNull StyleProvider styleProvider) {
+ return styleProvider.attributes().get(name);
+ }
+
+ @Nullable
+ private static ImageSize.Dimension parseDimension(@Nullable String raw) {
+
+ // a set of digits, then dimension unit (allow floating)
+
+ final ImageSize.Dimension dimension;
+
+ final int length = raw != null
+ ? raw.length()
+ : 0;
+
+ if (length == 0) {
+ dimension = null;
+ } else {
+
+ // first digit to find -> unit is finished (can be null)
+
+ int index = -1;
+
+ for (int i = length - 1; i >= 0; i--) {
+ if (Character.isDigit(raw.charAt(i))) {
+ index = i;
+ break;
+ }
+ }
+
+ // no digits -> no dimension
+ if (index == -1) {
+ dimension = null;
+ } else {
+
+ final String value;
+ final String unit;
+
+ // no unit is specified
+ if (index == length - 1) {
+ value = raw;
+ unit = null;
+ } else {
+ value = raw.substring(0, index + 1);
+ unit = raw.substring(index + 1);
+ }
+
+ ImageSize.Dimension inner;
+ try {
+ final float floatValue = Float.parseFloat(value);
+ inner = new ImageSize.Dimension(floatValue, unit);
+ } catch (NumberFormatException e) {
+ inner = null;
+ }
+
+ dimension = inner;
+ }
+ }
+
+ return dimension;
+ }
+
+ private static class StyleProvider {
+
+ private final String style;
+ private Map attributes;
+
+ StyleProvider(@Nullable String style) {
+ this.style = style;
+ }
+
+ @NonNull
+ Map attributes() {
+ final Map out;
+ if (attributes != null) {
+ out = attributes;
+ } else {
+ if (TextUtils.isEmpty(style)) {
+ out = attributes = Collections.emptyMap();
+ } else {
+ final String[] split = style.split(";");
+ final Map map = new HashMap<>(split.length);
+ String[] parts;
+ for (String s : split) {
+ if (!TextUtils.isEmpty(s)) {
+ parts = s.split(":");
+ if (parts.length == 2) {
+ map.put(parts[0].trim(), parts[1].trim());
+ }
+ }
+ }
+ out = attributes = map;
+ }
+ }
+ return out;
+ }
+ }
}
diff --git a/library/src/main/java/ru/noties/markwon/renderer/html/ImageSize.java b/library/src/main/java/ru/noties/markwon/renderer/html/ImageSize.java
new file mode 100644
index 00000000..f65144ab
--- /dev/null
+++ b/library/src/main/java/ru/noties/markwon/renderer/html/ImageSize.java
@@ -0,0 +1,37 @@
+package ru.noties.markwon.renderer.html;
+
+import android.support.annotation.Nullable;
+
+/**
+ * @since 1.0.1
+ */
+@SuppressWarnings("WeakerAccess")
+public class ImageSize {
+
+ public static class Dimension {
+
+ public final float value;
+ public final String unit;
+
+ public Dimension(float value, @Nullable String unit) {
+ this.value = value;
+ this.unit = unit;
+ }
+
+ @Override
+ public String toString() {
+ return "Dimension{" +
+ "value=" + value +
+ ", unit='" + unit + '\'' +
+ '}';
+ }
+ }
+
+ public final Dimension width;
+ public final Dimension height;
+
+ public ImageSize(@Nullable Dimension width, @Nullable Dimension height) {
+ this.width = width;
+ this.height = height;
+ }
+}
diff --git a/library/src/main/java/ru/noties/markwon/renderer/html/ImageSizeResolver.java b/library/src/main/java/ru/noties/markwon/renderer/html/ImageSizeResolver.java
new file mode 100644
index 00000000..41574bb7
--- /dev/null
+++ b/library/src/main/java/ru/noties/markwon/renderer/html/ImageSizeResolver.java
@@ -0,0 +1,29 @@
+package ru.noties.markwon.renderer.html;
+
+import android.graphics.Rect;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+/**
+ * @since 1.0.1
+ */
+@SuppressWarnings({"WeakerAccess", "unused"})
+public abstract class ImageSizeResolver {
+
+ /**
+ * We do not expose canvas height deliberately. As we cannot rely on this value very much
+ *
+ * @param imageSize {@link ImageSize} parsed from HTML
+ * @param imageBounds original image bounds
+ * @param canvasWidth width of the canvas
+ * @param textSize current font size
+ * @return resolved image bounds
+ */
+ @NonNull
+ public abstract Rect resolveImageSize(
+ @Nullable ImageSize imageSize,
+ @NonNull Rect imageBounds,
+ int canvasWidth,
+ float textSize
+ );
+}
diff --git a/library/src/main/java/ru/noties/markwon/renderer/html/ImageSizeResolverDef.java b/library/src/main/java/ru/noties/markwon/renderer/html/ImageSizeResolverDef.java
new file mode 100644
index 00000000..b7eb1fc9
--- /dev/null
+++ b/library/src/main/java/ru/noties/markwon/renderer/html/ImageSizeResolverDef.java
@@ -0,0 +1,85 @@
+package ru.noties.markwon.renderer.html;
+
+import android.graphics.Rect;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+/**
+ * @since 1.0.1
+ */
+@SuppressWarnings({"WeakerAccess", "unused"})
+public class ImageSizeResolverDef extends ImageSizeResolver {
+
+ // we track these two, others are considered to be pixels
+ protected static final String UNIT_PERCENT = "%";
+ protected static final String UNIT_EM = "em";
+
+ @NonNull
+ @Override
+ public Rect resolveImageSize(
+ @Nullable ImageSize imageSize,
+ @NonNull Rect imageBounds,
+ int canvasWidth,
+ float textSize
+ ) {
+
+ if (imageSize == null) {
+ return imageBounds;
+ }
+
+ final Rect rect;
+
+ final ImageSize.Dimension width = imageSize.width;
+ final ImageSize.Dimension height = imageSize.height;
+
+ final int imageWidth = imageBounds.width();
+ final int imageHeight = imageBounds.height();
+
+ final float ratio = (float) imageWidth / imageHeight;
+
+ if (width != null) {
+
+ final int w;
+ final int h;
+
+ if (UNIT_PERCENT.equals(width.unit)) {
+ w = (int) (canvasWidth * (width.value / 100.F) + .5F);
+ } else {
+ w = resolveAbsolute(width, imageWidth, textSize);
+ }
+
+ if (height == null
+ || UNIT_PERCENT.equals(height.unit)) {
+ h = (int) (w / ratio + .5F);
+ } else {
+ h = resolveAbsolute(height, imageHeight, textSize);
+ }
+
+ rect = new Rect(0, 0, w, h);
+
+ } else if (height != null) {
+
+ if (!UNIT_PERCENT.equals(height.unit)) {
+ final int h = resolveAbsolute(height, imageHeight, textSize);
+ final int w = (int) (h * ratio + .5F);
+ rect = new Rect(0, 0, w, h);
+ } else {
+ rect = imageBounds;
+ }
+ } else {
+ rect = imageBounds;
+ }
+
+ return rect;
+ }
+
+ protected int resolveAbsolute(@NonNull ImageSize.Dimension dimension, int original, float textSize) {
+ final int out;
+ if (UNIT_EM.equals(dimension.unit)) {
+ out = (int) (dimension.value * textSize + .5F);
+ } else {
+ out = original;
+ }
+ return out;
+ }
+}
diff --git a/library/src/main/java/ru/noties/markwon/renderer/html/SpannableHtmlParser.java b/library/src/main/java/ru/noties/markwon/renderer/html/SpannableHtmlParser.java
index af616330..6423e1f9 100644
--- a/library/src/main/java/ru/noties/markwon/renderer/html/SpannableHtmlParser.java
+++ b/library/src/main/java/ru/noties/markwon/renderer/html/SpannableHtmlParser.java
@@ -21,37 +21,74 @@ import ru.noties.markwon.spans.SpannableTheme;
public class SpannableHtmlParser {
// creates default parser
+ @NonNull
public static SpannableHtmlParser create(
@NonNull SpannableTheme theme,
@NonNull AsyncDrawable.Loader loader
) {
- return builderWithDefaults(theme, loader, null, null)
+ return builderWithDefaults(theme, loader, null, null, null)
.build();
}
+ /**
+ * @since 1.0.1
+ */
+ @NonNull
+ public static SpannableHtmlParser create(
+ @NonNull SpannableTheme theme,
+ @NonNull AsyncDrawable.Loader loader,
+ @NonNull ImageSizeResolver imageSizeResolver
+ ) {
+ return builderWithDefaults(theme, loader, null, null, imageSizeResolver)
+ .build();
+ }
+
+ @NonNull
public static SpannableHtmlParser create(
@NonNull SpannableTheme theme,
@NonNull AsyncDrawable.Loader loader,
@NonNull UrlProcessor urlProcessor,
@NonNull LinkSpan.Resolver resolver
) {
- return builderWithDefaults(theme, loader, urlProcessor, resolver)
+ return builderWithDefaults(theme, loader, urlProcessor, resolver, null)
.build();
}
+ /**
+ * @since 1.0.1
+ */
+ @NonNull
+ public static SpannableHtmlParser create(
+ @NonNull SpannableTheme theme,
+ @NonNull AsyncDrawable.Loader loader,
+ @NonNull UrlProcessor urlProcessor,
+ @NonNull LinkSpan.Resolver resolver,
+ @NonNull ImageSizeResolver imageSizeResolver
+ ) {
+ return builderWithDefaults(theme, loader, urlProcessor, resolver, imageSizeResolver)
+ .build();
+ }
+
+ @NonNull
public static Builder builder() {
return new Builder();
}
+ @NonNull
public static Builder builderWithDefaults(@NonNull SpannableTheme theme) {
- return builderWithDefaults(theme, null, null, null);
+ return builderWithDefaults(theme, null, null, null, null);
}
+ /**
+ * Updated in 1.0.1: added imageSizeResolverArgument
+ */
+ @NonNull
public static Builder builderWithDefaults(
@NonNull SpannableTheme theme,
@Nullable AsyncDrawable.Loader asyncDrawableLoader,
@Nullable UrlProcessor urlProcessor,
- @Nullable LinkSpan.Resolver resolver
+ @Nullable LinkSpan.Resolver resolver,
+ @Nullable ImageSizeResolver imageSizeResolver
) {
if (urlProcessor == null) {
@@ -68,7 +105,12 @@ public class SpannableHtmlParser {
final ImageProvider imageProvider;
if (asyncDrawableLoader != null) {
- imageProvider = new ImageProviderImpl(theme, asyncDrawableLoader, urlProcessor);
+
+ if (imageSizeResolver == null) {
+ imageSizeResolver = new ImageSizeResolverDef();
+ }
+
+ imageProvider = new ImageProviderImpl(theme, asyncDrawableLoader, urlProcessor, imageSizeResolver);
} else {
imageProvider = null;
}
@@ -163,21 +205,25 @@ public class SpannableHtmlParser {
private ImageProvider imageProvider;
private HtmlParser parser;
+ @NonNull
Builder simpleTag(@NonNull String tag, @NonNull SpanProvider provider) {
simpleTags.put(tag, provider);
return this;
}
- public Builder imageProvider(ImageProvider imageProvider) {
+ @NonNull
+ public Builder imageProvider(@Nullable ImageProvider imageProvider) {
this.imageProvider = imageProvider;
return this;
}
+ @NonNull
public Builder parser(@NonNull HtmlParser parser) {
this.parser = parser;
return this;
}
+ @NonNull
public SpannableHtmlParser build() {
if (parser == null) {
parser = DefaultHtmlParser.create();
diff --git a/library/src/main/java/ru/noties/markwon/spans/AsyncDrawable.java b/library/src/main/java/ru/noties/markwon/spans/AsyncDrawable.java
index b466e194..2253a5ba 100644
--- a/library/src/main/java/ru/noties/markwon/spans/AsyncDrawable.java
+++ b/library/src/main/java/ru/noties/markwon/spans/AsyncDrawable.java
@@ -3,15 +3,20 @@ package ru.noties.markwon.spans;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.PixelFormat;
+import android.graphics.Rect;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import ru.noties.markwon.renderer.html.ImageSize;
+import ru.noties.markwon.renderer.html.ImageSizeResolver;
+
public class AsyncDrawable extends Drawable {
public interface Loader {
+
void load(@NonNull String destination, @NonNull AsyncDrawable drawable);
void cancel(@NonNull String destination);
@@ -19,13 +24,32 @@ public class AsyncDrawable extends Drawable {
private final String destination;
private final Loader loader;
+ private final ImageSize imageSize;
+ private final ImageSizeResolver imageSizeResolver;
private Drawable result;
private Callback callback;
+ private int canvasWidth;
+ private float textSize;
+
public AsyncDrawable(@NonNull String destination, @NonNull Loader loader) {
+ this(destination, loader, null, null);
+ }
+
+ /**
+ * @since 1.0.1
+ */
+ public AsyncDrawable(
+ @NonNull String destination,
+ @NonNull Loader loader,
+ @Nullable ImageSizeResolver imageSizeResolver,
+ @Nullable ImageSize imageSize
+ ) {
this.destination = destination;
this.loader = loader;
+ this.imageSizeResolver = imageSizeResolver;
+ this.imageSize = imageSize;
}
public String getDestination() {
@@ -77,13 +101,22 @@ public class AsyncDrawable extends Drawable {
this.result = result;
this.result.setCallback(callback);
- // should we copy the data here? like bounds etc?
- // if we are async and we load some image from some source
- // thr bounds might change... so we are better off copy `result` bounds to this instance
- setBounds(result.getBounds());
+ final Rect bounds = resolveBounds();
+ result.setBounds(bounds);
+ setBounds(bounds);
+
invalidateSelf();
}
+ /**
+ * @since 1.0.1
+ */
+ @SuppressWarnings("WeakerAccess")
+ public void initWithKnownDimensions(int width, float textSize) {
+ this.canvasWidth = width;
+ this.textSize = textSize;
+ }
+
@Override
public void draw(@NonNull Canvas canvas) {
if (hasResult()) {
@@ -133,4 +166,19 @@ public class AsyncDrawable extends Drawable {
}
return out;
}
+
+ /**
+ * @since 1.0.1
+ */
+ @NonNull
+ private Rect resolveBounds() {
+ final Rect rect;
+ if (imageSizeResolver == null
+ || imageSize == null) {
+ rect = result.getBounds();
+ } else {
+ rect = imageSizeResolver.resolveImageSize(imageSize, result.getBounds(), canvasWidth, textSize);
+ }
+ return rect;
+ }
}
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 c74a1305..f9bd8f33 100644
--- a/library/src/main/java/ru/noties/markwon/spans/AsyncDrawableSpan.java
+++ b/library/src/main/java/ru/noties/markwon/spans/AsyncDrawableSpan.java
@@ -109,6 +109,8 @@ public class AsyncDrawableSpan extends ReplacementSpan {
int bottom,
@NonNull Paint paint) {
+ drawable.initWithKnownDimensions(canvas.getWidth(), paint.getTextSize());
+
final AsyncDrawable drawable = this.drawable;
if (drawable.hasResult()) {