Sanitize latex text placeholder (no new lines)

This commit is contained in:
Dimitry Ivanov 2019-07-04 17:17:33 +03:00
parent 85f201702e
commit 8daa59709b
5 changed files with 153 additions and 18 deletions

View File

@ -8,7 +8,7 @@ android.enableJetifier=true
android.enableBuildCache=true
android.buildCacheDir=build/pre-dex-cache
VERSION_NAME=4.0.1
VERSION_NAME=4.0.2-SNAPSHOT
GROUP=io.noties.markwon
POM_DESCRIPTION=Markwon markdown for Android

View File

@ -16,8 +16,14 @@ android {
dependencies {
api project(':markwon-core')
api project(':markwon-image')
api deps['jlatexmath-android']
deps['test'].with {
testImplementation it['junit']
testImplementation it['robolectric']
testImplementation it['mockito']
}
}
registerArtifact(this)

View File

@ -12,6 +12,7 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.Px;
import androidx.annotation.VisibleForTesting;
import org.commonmark.parser.Parser;
@ -84,8 +85,8 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
// @since 4.0.0
private final int paddingHorizontal;
// @since 4.0.0
// @since 4.0.0
private final int paddingVertical;
// @since 4.0.0
@ -132,7 +133,10 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
final int length = visitor.length();
visitor.builder().append(latex);
// @since 4.0.2 we cannot append _raw_ latex as a placeholder-text,
// because Android will draw formula for each line of text, thus
// leading to formula duplicated (drawn on each line of text)
visitor.builder().append(prepareLatexTextPlaceholder(latex));
final MarkwonConfiguration configuration = visitor.configuration();
@ -161,6 +165,13 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
AsyncDrawableScheduler.schedule(textView);
}
// @since 4.0.2
@VisibleForTesting
@NonNull
static String prepareLatexTextPlaceholder(@NonNull String latex) {
return latex.replace('\n', ' ').trim();
}
public static class Builder {
private final float textSize;
@ -350,6 +361,8 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
final Rect imageBounds = drawable.getResult().getBounds();
final int canvasWidth = drawable.getLastKnownCanvasWidth();
// todo: scale down when formula is greater than width (keep ratio and apply height)
if (fitCanvas
&& imageBounds.width() < canvasWidth) {
// we increase only width (keep height as-is)

View File

@ -0,0 +1,113 @@
package io.noties.markwon.ext.latex;
import androidx.annotation.NonNull;
import org.commonmark.parser.Parser;
import org.commonmark.parser.block.BlockParserFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import java.util.concurrent.ExecutorService;
import io.noties.markwon.MarkwonConfiguration;
import io.noties.markwon.MarkwonVisitor;
import io.noties.markwon.SpannableBuilder;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(RobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class JLatexMathPluginTest {
@Test
public void latex_text_placeholder() {
// text placeholder cannot have new-line characters and should be trimmed from ends
final String[] in = {
"hello",
"he\nllo",
" hello\n\n",
"\n\nhello\n\n",
"\n",
" \nhello\n "
};
for (String latex : in) {
final String placeholder = JLatexMathPlugin.prepareLatexTextPlaceholder(latex);
assertTrue(placeholder, placeholder.indexOf('\n') < 0);
if (placeholder.length() > 0) {
assertFalse(placeholder, Character.isWhitespace(placeholder.charAt(0)));
assertFalse(placeholder, Character.isWhitespace(placeholder.charAt(placeholder.length() - 1)));
}
}
}
@Test
public void block_parser_registered() {
final JLatexMathPlugin plugin = JLatexMathPlugin.create(0);
final Parser.Builder builder = mock(Parser.Builder.class);
plugin.configureParser(builder);
verify(builder, times(1)).customBlockParserFactory(any(BlockParserFactory.class));
}
@Test
public void visitor_registered() {
final JLatexMathPlugin plugin = JLatexMathPlugin.create(0);
final MarkwonVisitor.Builder builder = mock(MarkwonVisitor.Builder.class);
plugin.configureVisitor(builder);
//noinspection unchecked
verify(builder, times(1))
.on(eq(JLatexMathBlock.class), any(MarkwonVisitor.NodeVisitor.class));
}
@Test
public void visit() {
final JLatexMathPlugin plugin = JLatexMathPlugin.create(0, new JLatexMathPlugin.BuilderConfigure() {
@Override
public void configureBuilder(@NonNull JLatexMathPlugin.Builder builder) {
// no async in test (nooped for this test)
builder.executorService(mock(ExecutorService.class));
}
});
final MarkwonVisitor.Builder builder = mock(MarkwonVisitor.Builder.class);
final ArgumentCaptor<MarkwonVisitor.NodeVisitor> captor =
ArgumentCaptor.forClass(MarkwonVisitor.NodeVisitor.class);
plugin.configureVisitor(builder);
//noinspection unchecked
verify(builder, times(1))
.on(eq(JLatexMathBlock.class), captor.capture());
final MarkwonVisitor.NodeVisitor nodeVisitor = captor.getValue();
final MarkwonVisitor visitor = mock(MarkwonVisitor.class);
final JLatexMathBlock block = mock(JLatexMathBlock.class);
when(block.latex()).thenReturn(" first\nsecond\n ");
final SpannableBuilder spannableBuilder = mock(SpannableBuilder.class);
when(visitor.builder()).thenReturn(spannableBuilder);
when(visitor.configuration()).thenReturn(mock(MarkwonConfiguration.class));
//noinspection unchecked
nodeVisitor.visit(visitor, block);
verify(block, times(1)).latex();
verify(visitor, times(1)).length();
final ArgumentCaptor<String> stringArgumentCaptor = ArgumentCaptor.forClass(String.class);
verify(spannableBuilder, times(1)).append(stringArgumentCaptor.capture());
final String placeholder = stringArgumentCaptor.getValue();
assertTrue(placeholder, placeholder.indexOf('\n') < 0);
verify(visitor, times(1)).setSpans(eq(0), any());
}
}

View File

@ -68,20 +68,23 @@ public class LatexActivity extends Activity {
.build();
if (true) {
// final String l = "$$\n" +
// " P(X=r)=\\frac{\\lambda^r e^{-\\lambda}}{r!}\n" +
// "$$\n" +
// "\n" +
// "$$\n" +
// " P(X<r)=P(X<r-1)\n" +
// "$$\n" +
// "\n" +
// "$$\n" +
// " P(X>r)=1-P(X<r=1)\n" +
// "$$\n" +
// "\n" +
// "$$\n" +
// " \\text{Variance} = \\lambda\n" +
// "$$";
final String l = "$$ \n" +
" P(X=r)=\\frac{\\lambda^r e^{-\\lambda}}{r!}\n" +
"$$\n" +
"\n" +
"$$\n" +
" P(X<r)=P(X<r-1)\n" +
"$$\n" +
"\n" +
"$$\n" +
" P(X>r)=1-P(X<r=1)\n" +
"$$\n" +
"\n" +
"$$\n" +
" \\text{Variance} = \\lambda\n" +
" \\sigma_T^2 = \\frac{1-p}{p^2}\n" +
"$$";
markwon.setMarkdown(textView, l);
return;