Images support inside table cells

This commit is contained in:
Dimitry Ivanov 2020-04-28 17:58:41 +03:00
parent b497f872e5
commit bc38768539
5 changed files with 163 additions and 28 deletions

View File

@ -5,6 +5,7 @@
* `TextLayoutSpan` to obtain `Layout` in which markdown is displayed (applied by `TablePlugin`, more specifically `TableRowSpan` to propagate layout in which cell content is displayed)
* `HtmlEmptyTagReplacement` now is configurable by `HtmlPlugin`, `iframe` handling ([#235])
* `AsyncDrawableLoader` now uses `TextView` width without padding instead of width of canvas
* Support for images inside table cells (`ext-tables` module)
[#235]: https://github.com/noties/Markwon/issues/235

View File

@ -530,7 +530,20 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
@NonNull
@Override
public Rect resolveImageSize(@NonNull AsyncDrawable drawable) {
return drawable.getResult().getBounds();
// @since $nap; resolve inline size (scale down if exceed available width)
final Rect imageBounds = drawable.getResult().getBounds();
final int canvasWidth = drawable.getLastKnownCanvasWidth();
final int w = imageBounds.width();
if (w > canvasWidth) {
// here we must scale it down (keeping the ratio)
final float ratio = (float) w / imageBounds.height();
final int h = (int) (canvasWidth / ratio + .5F);
return new Rect(0, 0, canvasWidth, h);
}
return imageBounds;
}
}
}

View File

@ -4,6 +4,7 @@ import android.annotation.SuppressLint;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.Layout;
import android.text.Spannable;
import android.text.SpannableString;
@ -23,6 +24,8 @@ import java.util.ArrayList;
import java.util.List;
import io.noties.markwon.core.spans.TextLayoutSpan;
import io.noties.markwon.image.AsyncDrawable;
import io.noties.markwon.image.AsyncDrawableSpan;
import io.noties.markwon.utils.LeadingMarginUtils;
import io.noties.markwon.utils.SpanUtils;
@ -71,7 +74,7 @@ public class TableRowSpan extends ReplacementSpan {
private final TableTheme theme;
private final List<Cell> cells;
private final List<StaticLayout> layouts;
private final List<Layout> layouts;
private final TextPaint textPaint;
private final boolean header;
private final boolean odd;
@ -112,7 +115,7 @@ public class TableRowSpan extends ReplacementSpan {
if (fm != null) {
int max = 0;
for (StaticLayout layout : layouts) {
for (Layout layout : layouts) {
final int height = layout.getHeight();
if (height > max) {
max = height;
@ -240,7 +243,7 @@ public class TableRowSpan extends ReplacementSpan {
final int borderTop = isFirstTableRow ? borderWidth : 0;
final int borderBottom = bottom - top - borderWidth;
StaticLayout layout;
Layout layout;
for (int i = 0; i < size; i++) {
layout = layouts.get(i);
final int save = canvas.save();
@ -297,34 +300,76 @@ public class TableRowSpan extends ReplacementSpan {
final int w = (width / columns) - padding;
this.layouts.clear();
Cell cell;
StaticLayout layout;
Spannable spannable;
for (int i = 0, size = cells.size(); i < size; i++) {
makeLayout(i, w, cells.get(i));
}
}
cell = cells.get(i);
private void makeLayout(final int index, final int width, @NonNull final Cell cell) {
if (cell.text instanceof Spannable) {
spannable = (Spannable) cell.text;
} else {
spannable = new SpannableString(cell.text);
final Runnable recreate = new Runnable() {
@Override
public void run() {
final Invalidator invalidator = TableRowSpan.this.invalidator;
if (invalidator != null) {
layouts.remove(index);
makeLayout(index, width, cell);
invalidator.invalidate();
}
}
};
layout = new StaticLayout(
spannable,
textPaint,
w,
alignment(cell.alignment),
1.0F,
0.0F,
false
);
final Spannable spannable;
// @since $nap;
TextLayoutSpan.applyTo(spannable, layout);
if (cell.text instanceof Spannable) {
spannable = (Spannable) cell.text;
} else {
spannable = new SpannableString(cell.text);
}
layouts.add(layout);
final Layout layout = new StaticLayout(
spannable,
textPaint,
width,
alignment(cell.alignment),
1.0F,
0.0F,
false
);
// @since $nap;
TextLayoutSpan.applyTo(spannable, layout);
// @since $nap;
scheduleAsyncDrawables(spannable, recreate);
layouts.add(index, layout);
}
private void scheduleAsyncDrawables(@NonNull Spannable spannable, @NonNull final Runnable recreate) {
final AsyncDrawableSpan[] spans = spannable.getSpans(0, spannable.length(), AsyncDrawableSpan.class);
if (spans != null
&& spans.length > 0) {
for (AsyncDrawableSpan span : spans) {
final AsyncDrawable drawable = span.getDrawable();
// it is absolutely crucial to check if drawable is already attached,
// otherwise we would end up with a loop
if (drawable.isAttached()) {
continue;
}
drawable.setCallback2(new CallbackAdapter() {
@Override
public void invalidateDrawable(@NonNull Drawable who) {
recreate.run();
}
});
}
}
}
@ -348,4 +393,21 @@ public class TableRowSpan extends ReplacementSpan {
public void invalidator(@Nullable Invalidator invalidator) {
this.invalidator = invalidator;
}
private static abstract class CallbackAdapter implements Drawable.Callback {
@Override
public void invalidateDrawable(@NonNull Drawable who) {
}
@Override
public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) {
}
@Override
public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) {
}
}
}

View File

@ -68,7 +68,8 @@ public class LatexActivity extends ActivityWithMenuOptions {
.add("textColor", this::textColor)
.add("defaultTextColor", this::defaultTextColor)
.add("inlineAndBlock", this::inlineAndBlock)
.add("dark", this::dark);
.add("dark", this::dark)
.add("omega", this::omega);
}
@Override
@ -221,6 +222,18 @@ public class LatexActivity extends ActivityWithMenuOptions {
renderWithBlocksAndInlines(md);
}
private void omega() {
final String md = "" +
"# Block\n\n" +
"$$\n" +
"\\Omega\n" +
"$$\n\n" +
"# Inline\n\n" +
"$$\\Omega$$";
renderWithBlocksAndInlines(md);
}
@NonNull
private static String wrapLatexInSampleMarkdown(@NonNull String latex) {
return "" +

View File

@ -7,10 +7,11 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.noties.debug.Debug;
import io.noties.markwon.Markwon;
import io.noties.markwon.ext.latex.JLatexMathPlugin;
import io.noties.markwon.ext.tables.TablePlugin;
import io.noties.markwon.ext.tables.TableTheme;
import io.noties.markwon.image.ImagesPlugin;
import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
import io.noties.markwon.linkify.LinkifyPlugin;
import io.noties.markwon.sample.ActivityWithMenuOptions;
import io.noties.markwon.sample.MenuOptions;
@ -25,7 +26,9 @@ public class TableActivity extends ActivityWithMenuOptions {
public MenuOptions menuOptions() {
return MenuOptions.create()
.add("customize", this::customize)
.add("tableAndLinkify", this::tableAndLinkify);
.add("tableAndLinkify", this::tableAndLinkify)
.add("withImages", this::withImages)
.add("withLatex", this::withLatex);
}
private TextView textView;
@ -86,4 +89,47 @@ public class TableActivity extends ActivityWithMenuOptions {
markwon.setMarkdown(textView, md);
}
private void withImages() {
final String md = "" +
"| HEADER | HEADER |\n" +
"|:----:|:----:|\n" +
"| ![Build](https://github.com/noties/Markwon/workflows/Build/badge.svg) | Build |\n" +
"| Stable | ![stable](https://img.shields.io/maven-central/v/io.noties.markwon/core.svg?label=stable) |\n" +
"| BIG | ![image](https://images.pexels.com/photos/41171/brussels-sprouts-sprouts-cabbage-grocery-41171.jpeg) |\n" +
"\n";
final Markwon markwon = Markwon.builder(this)
.usePlugin(ImagesPlugin.create())
.usePlugin(TablePlugin.create(this))
.build();
markwon.setMarkdown(textView, md);
}
private void withLatex() {
String latex = "\\begin{array}{cc}";
latex += "\\fbox{\\text{A framed box with \\textdbend}}&\\shadowbox{\\text{A shadowed box}}\\cr";
latex += "\\doublebox{\\text{A double framed box}}&\\ovalbox{\\text{An oval framed box}}\\cr";
latex += "\\end{array}";
final String md = "" +
"| HEADER | HEADER |\n" +
"|:----:|:----:|\n" +
"| ![Build](https://github.com/noties/Markwon/workflows/Build/badge.svg) | Build |\n" +
"| Stable | ![stable](https://img.shields.io/maven-central/v/io.noties.markwon/core.svg?label=stable) |\n" +
"| BIG | $$" + latex + "$$ |\n" +
"\n";
final Markwon markwon = Markwon.builder(this)
.usePlugin(MarkwonInlineParserPlugin.create())
.usePlugin(ImagesPlugin.create())
.usePlugin(JLatexMathPlugin.create(textView.getTextSize(), builder -> builder.inlinesEnabled(true)))
.usePlugin(TablePlugin.create(this))
.build();
markwon.setMarkdown(textView, md);
}
}