Sanitize latex text placeholder (no new lines)
This commit is contained in:
		
							parent
							
								
									85f201702e
								
							
						
					
					
						commit
						8daa59709b
					
				| @ -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 | ||||
|  | ||||
| @ -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) | ||||
| @ -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) | ||||
|  | ||||
| @ -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()); | ||||
|     } | ||||
| } | ||||
| @ -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" + | ||||
| //                    "$$"; | ||||
|             final String l = "$$ \n" + | ||||
|                     "    \\sigma_T^2 = \\frac{1-p}{p^2}\n" + | ||||
|                     "$$"; | ||||
|             markwon.setMarkdown(textView, l); | ||||
|             return; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Dimitry Ivanov
						Dimitry Ivanov