Update sample configuration for latex block_and_inline renderMode
This commit is contained in:
		
							parent
							
								
									c7494a9225
								
							
						
					
					
						commit
						a80ff09e15
					
				| @ -0,0 +1,50 @@ | ||||
| package io.noties.markwon.ext.latex; | ||||
| 
 | ||||
| import android.graphics.Rect; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| 
 | ||||
| import io.noties.markwon.image.AsyncDrawable; | ||||
| import io.noties.markwon.image.ImageSizeResolver; | ||||
| 
 | ||||
| // we must make drawable fit canvas (if specified), but do not keep the ratio whilst scaling up | ||||
| // @since 4.0.0 | ||||
| class JLatexBlockImageSizeResolver extends ImageSizeResolver { | ||||
| 
 | ||||
|     private final boolean fitCanvas; | ||||
| 
 | ||||
|     JLatexBlockImageSizeResolver(boolean fitCanvas) { | ||||
|         this.fitCanvas = fitCanvas; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @Override | ||||
|     public Rect resolveImageSize(@NonNull AsyncDrawable drawable) { | ||||
| 
 | ||||
|         final Rect imageBounds = drawable.getResult().getBounds(); | ||||
|         final int canvasWidth = drawable.getLastKnownCanvasWidth(); | ||||
| 
 | ||||
|         if (fitCanvas) { | ||||
| 
 | ||||
|             // we modify bounds only if `fitCanvas` is true | ||||
|             final int w = imageBounds.width(); | ||||
| 
 | ||||
|             if (w < canvasWidth) { | ||||
|                 // increase width and center formula (keep height as-is) | ||||
|                 return new Rect(0, 0, canvasWidth, imageBounds.height()); | ||||
|             } | ||||
| 
 | ||||
|             // @since 4.0.2 we additionally scale down the resulting formula (keeping the ratio) | ||||
|             // the thing is - JLatexMathDrawable will do it anyway, but it will modify its own | ||||
|             // bounds (which AsyncDrawable won't catch), thus leading to an empty space after the formula | ||||
|             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; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,61 @@ | ||||
| package io.noties.markwon.ext.latex; | ||||
| 
 | ||||
| import android.graphics.Paint; | ||||
| import android.graphics.Rect; | ||||
| 
 | ||||
| import androidx.annotation.IntRange; | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| 
 | ||||
| import io.noties.markwon.core.MarkwonTheme; | ||||
| import io.noties.markwon.image.AsyncDrawable; | ||||
| import io.noties.markwon.image.AsyncDrawableSpan; | ||||
| 
 | ||||
| /** | ||||
|  * @since 4.3.0-SNAPSHOT | ||||
|  */ | ||||
| class JLatexInlineAsyncDrawableSpan extends AsyncDrawableSpan { | ||||
| 
 | ||||
|     private final AsyncDrawable drawable; | ||||
| 
 | ||||
|     JLatexInlineAsyncDrawableSpan(@NonNull MarkwonTheme theme, @NonNull AsyncDrawable drawable, int alignment, boolean replacementTextIsLink) { | ||||
|         super(theme, drawable, alignment, replacementTextIsLink); | ||||
|         this.drawable = drawable; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int getSize( | ||||
|             @NonNull Paint paint, | ||||
|             CharSequence text, | ||||
|             @IntRange(from = 0) int start, | ||||
|             @IntRange(from = 0) int end, | ||||
|             @Nullable Paint.FontMetricsInt fm) { | ||||
| 
 | ||||
|         // if we have no async drawable result - we will just render text | ||||
| 
 | ||||
|         final int size; | ||||
| 
 | ||||
|         if (drawable.hasResult()) { | ||||
| 
 | ||||
|             final Rect rect = drawable.getBounds(); | ||||
| 
 | ||||
|             if (fm != null) { | ||||
|                 final int half = rect.bottom / 2; | ||||
|                 fm.ascent = -half; | ||||
|                 fm.descent = half; | ||||
| 
 | ||||
|                 fm.top = fm.ascent; | ||||
|                 fm.bottom = 0; | ||||
|             } | ||||
| 
 | ||||
|             size = rect.right; | ||||
| 
 | ||||
|         } else { | ||||
| 
 | ||||
|             // NB, no specific text handling (no new lines, etc) | ||||
|             size = (int) (paint.measureText(text, start, end) + .5F); | ||||
|         } | ||||
| 
 | ||||
|         return size; | ||||
|     } | ||||
| } | ||||
| @ -1,7 +1,5 @@ | ||||
| package io.noties.markwon.ext.latex; | ||||
| 
 | ||||
| import android.util.Log; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| 
 | ||||
| import org.commonmark.internal.util.Parsing; | ||||
| @ -13,6 +11,10 @@ import org.commonmark.parser.block.BlockStart; | ||||
| import org.commonmark.parser.block.MatchedBlockParser; | ||||
| import org.commonmark.parser.block.ParserState; | ||||
| 
 | ||||
| /** | ||||
|  * @since 4.3.0-SNAPSHOT (although there was a class with the same name, | ||||
|  * which is renamed now to {@link JLatexMathBlockParserLegacy}) | ||||
|  */ | ||||
| public class JLatexMathBlockParser extends AbstractBlockParser { | ||||
| 
 | ||||
|     private static final char DOLLAR = '$'; | ||||
| @ -22,8 +24,6 @@ public class JLatexMathBlockParser extends AbstractBlockParser { | ||||
| 
 | ||||
|     private final StringBuilder builder = new StringBuilder(); | ||||
| 
 | ||||
| //    private boolean isClosed; | ||||
| 
 | ||||
|     private final int signs; | ||||
| 
 | ||||
|     @SuppressWarnings("WeakerAccess") | ||||
| @ -44,12 +44,9 @@ public class JLatexMathBlockParser extends AbstractBlockParser { | ||||
| 
 | ||||
|         // check for closing | ||||
|         if (parserState.getIndent() < Parsing.CODE_BLOCK_INDENT) { | ||||
|             Log.e("LTX", String.format("signs: %d, skip dollar: %s", signs, Parsing.skip(DOLLAR, line, nextNonSpaceIndex, length))); | ||||
| //            if (Parsing.skip(DOLLAR, line, nextNonSpaceIndex, length) == signs) { | ||||
|             if (consume(DOLLAR, line, nextNonSpaceIndex, length) == signs) { | ||||
|                 // okay, we have our number of signs | ||||
|                 // let's consume spaces until the end | ||||
|                 Log.e("LTX", String.format("length; %d, skip spaces: %s", length, Parsing.skip(SPACE, line, nextNonSpaceIndex + signs, length))); | ||||
|                 if (Parsing.skip(SPACE, line, nextNonSpaceIndex + signs, length) == length) { | ||||
|                     return BlockContinue.finished(); | ||||
|                 } | ||||
| @ -61,22 +58,6 @@ public class JLatexMathBlockParser extends AbstractBlockParser { | ||||
| 
 | ||||
|     @Override | ||||
|     public void addLine(CharSequence line) { | ||||
| // | ||||
| //        if (builder.length() > 0) { | ||||
| //            builder.append('\n'); | ||||
| //        } | ||||
| // | ||||
| //        builder.append(line); | ||||
| // | ||||
| //        final int length = builder.length(); | ||||
| //        if (length > 1) { | ||||
| //            isClosed = '$' == builder.charAt(length - 1) | ||||
| //                    && '$' == builder.charAt(length - 2); | ||||
| //            if (isClosed) { | ||||
| //                builder.replace(length - 2, length, ""); | ||||
| //            } | ||||
| //        } | ||||
|         Log.e("LTX", "addLine: " + line); | ||||
|         builder.append(line); | ||||
|         builder.append('\n'); | ||||
|     } | ||||
| @ -88,8 +69,6 @@ public class JLatexMathBlockParser extends AbstractBlockParser { | ||||
| 
 | ||||
|     public static class Factory extends AbstractBlockParserFactory { | ||||
| 
 | ||||
| //        private static final Pattern RE = Pattern.compile("(\\${2,}) *$"); | ||||
| 
 | ||||
|         @Override | ||||
|         public BlockStart tryStart(ParserState state, MatchedBlockParser matchedBlockParser) { | ||||
| 
 | ||||
| @ -111,7 +90,6 @@ public class JLatexMathBlockParser extends AbstractBlockParser { | ||||
|             final CharSequence line = state.getLine(); | ||||
|             final int length = line.length(); | ||||
| 
 | ||||
| //            final int signs = Parsing.skip(DOLLAR, line, nextNonSpaceIndex, length) - 1; | ||||
|             final int signs = consume(DOLLAR, line, nextNonSpaceIndex, length); | ||||
| 
 | ||||
|             // 2 is minimum | ||||
| @ -120,73 +98,16 @@ public class JLatexMathBlockParser extends AbstractBlockParser { | ||||
|             } | ||||
| 
 | ||||
|             // consume spaces until the end of the line, if any other content is found -> NONE | ||||
|             // TODO: here we can check mode in which we operate (legacy or not) | ||||
|             if (Parsing.skip(SPACE, line, nextNonSpaceIndex + signs, length) != length) { | ||||
|                 return BlockStart.none(); | ||||
|             } | ||||
| 
 | ||||
|             Log.e("LTX", String.format("signs: %s, next: %d, length: %d, line: '%s'", signs, nextNonSpaceIndex, length, line)); | ||||
| 
 | ||||
|             return BlockStart.of(new JLatexMathBlockParser(signs)) | ||||
|                     .atIndex(length + 1); | ||||
| 
 | ||||
| 
 | ||||
| //            // check if it's an indented code block | ||||
| //            if (indent < Parsing.CODE_BLOCK_INDENT) { | ||||
| // | ||||
| //                final int nextNonSpaceIndex = state.getNextNonSpaceIndex(); | ||||
| //                final CharSequence line = state.getLine(); | ||||
| //                final int length = line.length(); | ||||
| // | ||||
| //                final int signs = Parsing.skip('$', line, nextNonSpaceIndex, length); | ||||
| // | ||||
| //                // 2 is minimum | ||||
| //                if (signs < 2) { | ||||
| //                    return BlockStart.none(); | ||||
| //                } | ||||
| // | ||||
| //                // consume spaces until the end of the line, if any other content is found -> NONE | ||||
| //                if (Parsing.skip(' ', line, nextNonSpaceIndex + signs, length) != length) { | ||||
| //                    return BlockStart.none(); | ||||
| //                } | ||||
| // | ||||
| ////                // consume spaces until the end of the line, if any other content is found -> NONE | ||||
| ////                if ((nextNonSpaceIndex + signs) < length) { | ||||
| ////                    // check if more content is available | ||||
| ////                    if (Parsing.skip(' ',  line,nextNonSpaceIndex + signs, length) != length) { | ||||
| ////                        return BlockStart.none(); | ||||
| ////                    } | ||||
| ////                } | ||||
| // | ||||
| ////                final Matcher matcher = RE.matcher(line); | ||||
| ////                matcher.region(nextNonSpaceIndex, length); | ||||
| // | ||||
| ////                Log.e("LATEX", String.format("nonSpace: %d, length: %s, line: '%s'", nextNonSpaceIndex, length, line)); | ||||
| // | ||||
| //                // we are looking for 2 `$$` subsequent signs | ||||
| //                // and immediate new-line or arbitrary number of white spaces (we check for the first one) | ||||
| //                // so, nextNonSpaceIndex + 2 >= length and both symbols are `$`s | ||||
| //                final int diff = length - (nextNonSpaceIndex + 2); | ||||
| //                if (diff >= 0) { | ||||
| //                    // check for both `$` | ||||
| //                    if (line.charAt(nextNonSpaceIndex) == '$' | ||||
| //                            && line.charAt(nextNonSpaceIndex + 1) == '$') { | ||||
| // | ||||
| //                        if (diff > 0) { | ||||
| //                            if (!Character.isWhitespace(line.charAt(nextNonSpaceIndex + 2))) { | ||||
| //                                return BlockStart.none(); | ||||
| //                            } | ||||
| //                            return BlockStart.of(new JLatexMathBlockParser()).atIndex(nextNonSpaceIndex + 3); | ||||
| //                        } | ||||
| // | ||||
| //                    } | ||||
| //                } | ||||
| //            } | ||||
| // | ||||
| //            return BlockStart.none(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @SuppressWarnings("SameParameterValue") | ||||
|     private static int consume(char c, @NonNull CharSequence line, int start, int end) { | ||||
|         for (int i = start; i < end; i++) { | ||||
|             if (c != line.charAt(i)) { | ||||
|  | ||||
| @ -0,0 +1,82 @@ | ||||
| package io.noties.markwon.ext.latex; | ||||
| 
 | ||||
| import org.commonmark.node.Block; | ||||
| import org.commonmark.parser.block.AbstractBlockParser; | ||||
| import org.commonmark.parser.block.AbstractBlockParserFactory; | ||||
| import org.commonmark.parser.block.BlockContinue; | ||||
| import org.commonmark.parser.block.BlockStart; | ||||
| import org.commonmark.parser.block.MatchedBlockParser; | ||||
| import org.commonmark.parser.block.ParserState; | ||||
| 
 | ||||
| /** | ||||
|  * @since 4.3.0-SNAPSHOT (although it is just renamed parser from previous versions) | ||||
|  */ | ||||
| public class JLatexMathBlockParserLegacy extends AbstractBlockParser { | ||||
| 
 | ||||
|     private final JLatexMathBlock block = new JLatexMathBlock(); | ||||
| 
 | ||||
|     private final StringBuilder builder = new StringBuilder(); | ||||
| 
 | ||||
|     private boolean isClosed; | ||||
| 
 | ||||
|     @Override | ||||
|     public Block getBlock() { | ||||
|         return block; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public BlockContinue tryContinue(ParserState parserState) { | ||||
| 
 | ||||
|         if (isClosed) { | ||||
|             return BlockContinue.finished(); | ||||
|         } | ||||
| 
 | ||||
|         return BlockContinue.atIndex(parserState.getIndex()); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void addLine(CharSequence line) { | ||||
| 
 | ||||
|         if (builder.length() > 0) { | ||||
|             builder.append('\n'); | ||||
|         } | ||||
| 
 | ||||
|         builder.append(line); | ||||
| 
 | ||||
|         final int length = builder.length(); | ||||
|         if (length > 1) { | ||||
|             isClosed = '$' == builder.charAt(length - 1) | ||||
|                     && '$' == builder.charAt(length - 2); | ||||
|             if (isClosed) { | ||||
|                 builder.replace(length - 2, length, ""); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void closeBlock() { | ||||
|         block.latex(builder.toString()); | ||||
|     } | ||||
| 
 | ||||
|     public static class Factory extends AbstractBlockParserFactory { | ||||
| 
 | ||||
|         @Override | ||||
|         public BlockStart tryStart(ParserState state, MatchedBlockParser matchedBlockParser) { | ||||
| 
 | ||||
|             final CharSequence line = state.getLine(); | ||||
|             final int length = line != null | ||||
|                     ? line.length() | ||||
|                     : 0; | ||||
| 
 | ||||
|             if (length > 1) { | ||||
|                 if ('$' == line.charAt(0) | ||||
|                         && '$' == line.charAt(1)) { | ||||
|                     return BlockStart.of(new JLatexMathBlockParserLegacy()) | ||||
|                             .atIndex(state.getIndex() + 2); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return BlockStart.none(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -1,6 +1,5 @@ | ||||
| package io.noties.markwon.ext.latex; | ||||
| 
 | ||||
| import android.graphics.Paint; | ||||
| import android.graphics.Rect; | ||||
| import android.graphics.drawable.Drawable; | ||||
| import android.os.Handler; | ||||
| @ -10,7 +9,6 @@ import android.text.Spanned; | ||||
| import android.util.Log; | ||||
| import android.widget.TextView; | ||||
| 
 | ||||
| import androidx.annotation.IntRange; | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.annotation.Px; | ||||
| @ -28,14 +26,11 @@ import java.util.concurrent.Future; | ||||
| import io.noties.markwon.AbstractMarkwonPlugin; | ||||
| import io.noties.markwon.MarkwonConfiguration; | ||||
| import io.noties.markwon.MarkwonVisitor; | ||||
| import io.noties.markwon.core.MarkwonTheme; | ||||
| import io.noties.markwon.image.AsyncDrawable; | ||||
| import io.noties.markwon.image.AsyncDrawableLoader; | ||||
| import io.noties.markwon.image.AsyncDrawableScheduler; | ||||
| import io.noties.markwon.image.AsyncDrawableSpan; | ||||
| import io.noties.markwon.image.ImageSize; | ||||
| import io.noties.markwon.image.ImageSizeResolver; | ||||
| import io.noties.markwon.image.ImageSizeResolverDef; | ||||
| import io.noties.markwon.inlineparser.MarkwonInlineParser; | ||||
| import ru.noties.jlatexmath.JLatexMathDrawable; | ||||
| 
 | ||||
| @ -68,7 +63,6 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { | ||||
|         BLOCKS_AND_INLINES | ||||
|     } | ||||
| 
 | ||||
|     // TODO: inlines are not moved to a new line when exceed available width.. (api 23, emulator) | ||||
|     public interface BuilderConfigure { | ||||
|         void configureBuilder(@NonNull Builder builder); | ||||
|     } | ||||
| @ -78,52 +72,65 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { | ||||
|         return new JLatexMathPlugin(builder(textSize).build()); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @since 4.3.0-SNAPSHOT | ||||
|      */ | ||||
|     @NonNull | ||||
|     public static JLatexMathPlugin create(@Px float inlineTextSize, @Px float blockTextSize) { | ||||
|         return new JLatexMathPlugin(builder(inlineTextSize, blockTextSize).build()); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     public static JLatexMathPlugin create(@NonNull Config config) { | ||||
|         return new JLatexMathPlugin(config); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     public static JLatexMathPlugin create(float textSize, @NonNull BuilderConfigure builderConfigure) { | ||||
|         final Builder builder = new Builder(textSize); | ||||
|     public static JLatexMathPlugin create(@Px float textSize, @NonNull BuilderConfigure builderConfigure) { | ||||
|         final Builder builder = builder(textSize); | ||||
|         builderConfigure.configureBuilder(builder); | ||||
|         return new JLatexMathPlugin(builder.build()); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @since 4.3.0-SNAPSHOT | ||||
|      */ | ||||
|     @NonNull | ||||
|     public static JLatexMathPlugin create( | ||||
|             @Px float inlineTextSize, | ||||
|             @Px float blockTextSize, | ||||
|             @NonNull BuilderConfigure builderConfigure) { | ||||
|         final Builder builder = builder(inlineTextSize, blockTextSize); | ||||
|         builderConfigure.configureBuilder(builder); | ||||
|         return new JLatexMathPlugin(builder.build()); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     public static JLatexMathPlugin.Builder builder(float textSize) { | ||||
|         return new Builder(textSize); | ||||
|     public static JLatexMathPlugin.Builder builder(@Px float textSize) { | ||||
|         return new Builder(JLatexMathTheme.builder(textSize)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @since 4.3.0-SNAPSHOT | ||||
|      */ | ||||
|     @NonNull | ||||
|     public static JLatexMathPlugin.Builder builder(@Px float inlineTextSize, @Px float blockTextSize) { | ||||
|         return new Builder(JLatexMathTheme.builder(inlineTextSize, blockTextSize)); | ||||
|     } | ||||
| 
 | ||||
|     public static class Config { | ||||
| 
 | ||||
|         private final float textSize; | ||||
|         // @since 4.3.0-SNAPSHOT | ||||
|         private final JLatexMathTheme theme; | ||||
| 
 | ||||
|         // @since 4.0.0 | ||||
|         private final JLatexMathTheme.BackgroundProvider backgroundProvider; | ||||
|         // @since 4.3.0-SNAPSHOT | ||||
|         private final RenderMode renderMode; | ||||
| 
 | ||||
|         @JLatexMathDrawable.Align | ||||
|         private final int align; | ||||
| 
 | ||||
|         private final boolean fitCanvas; | ||||
| 
 | ||||
|         // @since 4.0.0 | ||||
|         private final int paddingHorizontal; | ||||
| 
 | ||||
|         // @since 4.0.0 | ||||
|         private final int paddingVertical; | ||||
| 
 | ||||
|         // @since 4.0.0 | ||||
|         private final ExecutorService executorService; | ||||
| 
 | ||||
|         Config(@NonNull Builder builder) { | ||||
|             this.textSize = builder.textSize; | ||||
|             this.backgroundProvider = builder.backgroundProvider; | ||||
|             this.align = builder.align; | ||||
|             this.fitCanvas = builder.fitCanvas; | ||||
|             this.paddingHorizontal = builder.paddingHorizontal; | ||||
|             this.paddingVertical = builder.paddingVertical; | ||||
| 
 | ||||
|             this.theme = builder.theme.build(); | ||||
|             this.renderMode = builder.renderMode; | ||||
|             // @since 4.0.0 | ||||
|             ExecutorService executorService = builder.executorService; | ||||
|             if (executorService == null) { | ||||
| @ -133,23 +140,34 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private final Config config; | ||||
|     private final JLatextAsyncDrawableLoader jLatextAsyncDrawableLoader; | ||||
|     private final JLatexImageSizeResolver jLatexImageSizeResolver; | ||||
|     private final JLatexBlockImageSizeResolver jLatexBlockImageSizeResolver; | ||||
|     private final ImageSizeResolver inlineImageSizeResolver; | ||||
| 
 | ||||
|     @SuppressWarnings("WeakerAccess") | ||||
|     JLatexMathPlugin(@NonNull Config config) { | ||||
|         this.config = config; | ||||
|         this.jLatextAsyncDrawableLoader = new JLatextAsyncDrawableLoader(config); | ||||
|         this.jLatexImageSizeResolver = new JLatexImageSizeResolver(config.fitCanvas); | ||||
|         this.jLatexBlockImageSizeResolver = new JLatexBlockImageSizeResolver(config.theme.blockFitCanvas()); | ||||
|         this.inlineImageSizeResolver = new InlineImageSizeResolver(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void configureParser(@NonNull Parser.Builder builder) { | ||||
| 
 | ||||
|         // what we can do: | ||||
|         // [0-3] spaces before block start/end | ||||
|         // if it's $$\n -> block | ||||
|         // if it's $$\\dhdsfjh$$ -> inline | ||||
|         // TODO: depending on renderMode we should register our parsing here | ||||
|         // * for LEGACY -> just add custom block parser | ||||
|         // * for INLINE.. -> require InlinePlugin, add inline processor + add block parser | ||||
| 
 | ||||
|         switch (config.renderMode) { | ||||
| 
 | ||||
|             case LEGACY: { | ||||
|                 builder.customBlockParserFactory(new JLatexMathBlockParserLegacy.Factory()); | ||||
|             } | ||||
|             break; | ||||
| 
 | ||||
|             case BLOCKS_AND_INLINES: { | ||||
|                 builder.customBlockParserFactory(new JLatexMathBlockParser.Factory()); | ||||
| 
 | ||||
|                 final InlineParserFactory factory = MarkwonInlineParser.factoryBuilder() | ||||
| @ -157,6 +175,12 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { | ||||
|                         .build(); | ||||
|                 builder.inlineParserFactory(factory); | ||||
|             } | ||||
|             break; | ||||
| 
 | ||||
|             default: | ||||
|                 throw new RuntimeException("Unexpected `renderMode`: " + config.renderMode); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) { | ||||
| @ -182,7 +206,7 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { | ||||
|                         new JLatextAsyncDrawable( | ||||
|                                 latex, | ||||
|                                 jLatextAsyncDrawableLoader, | ||||
|                                 jLatexImageSizeResolver, | ||||
|                                 jLatexBlockImageSizeResolver, | ||||
|                                 null, | ||||
|                                 true), | ||||
|                         AsyncDrawableSpan.ALIGN_CENTER, | ||||
| @ -196,6 +220,10 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
| 
 | ||||
|         if (RenderMode.BLOCKS_AND_INLINES == config.renderMode) { | ||||
| 
 | ||||
|             builder.on(JLatexMathNode.class, new MarkwonVisitor.NodeVisitor<JLatexMathNode>() { | ||||
|                 @Override | ||||
|                 public void visit(@NonNull MarkwonVisitor visitor, @NonNull JLatexMathNode jLatexMathNode) { | ||||
| @ -210,12 +238,12 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { | ||||
| 
 | ||||
|                     final MarkwonConfiguration configuration = visitor.configuration(); | ||||
| 
 | ||||
|                 final AsyncDrawableSpan span = new JLatexAsyncDrawableSpan( | ||||
|                     final AsyncDrawableSpan span = new JLatexInlineAsyncDrawableSpan( | ||||
|                             configuration.theme(), | ||||
|                             new JLatextAsyncDrawable( | ||||
|                                     latex, | ||||
|                                     jLatextAsyncDrawableLoader, | ||||
|                                 new ImageSizeResolverDef(), | ||||
|                                     inlineImageSizeResolver, | ||||
|                                     null, | ||||
|                                     false), | ||||
|                             AsyncDrawableSpan.ALIGN_CENTER, | ||||
| @ -225,6 +253,7 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) { | ||||
| @ -245,61 +274,30 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { | ||||
| 
 | ||||
|     public static class Builder { | ||||
| 
 | ||||
|         private final float textSize; | ||||
|         // @since 4.3.0-SNAPSHOT | ||||
|         private final JLatexMathTheme.Builder theme; | ||||
| 
 | ||||
|         // @since 4.0.0 | ||||
|         private JLatexMathTheme.BackgroundProvider backgroundProvider; | ||||
| 
 | ||||
|         @JLatexMathDrawable.Align | ||||
|         private int align = JLatexMathDrawable.ALIGN_CENTER; | ||||
| 
 | ||||
|         private boolean fitCanvas = false; | ||||
| 
 | ||||
|         // @since 4.0.0 | ||||
|         private int paddingHorizontal; | ||||
| 
 | ||||
|         // @since 4.0.0 | ||||
|         private int paddingVertical; | ||||
|         // @since 4.3.0-SNAPSHOT | ||||
|         private RenderMode renderMode = RenderMode.BLOCKS_AND_INLINES; | ||||
| 
 | ||||
|         // @since 4.0.0 | ||||
|         private ExecutorService executorService; | ||||
| 
 | ||||
|         Builder(float textSize) { | ||||
|             this.textSize = textSize; | ||||
|         Builder(@NonNull JLatexMathTheme.Builder builder) { | ||||
|             this.theme = builder; | ||||
|         } | ||||
| 
 | ||||
|         @NonNull | ||||
|         public Builder backgroundProvider(@NonNull JLatexMathTheme.BackgroundProvider backgroundProvider) { | ||||
|             this.backgroundProvider = backgroundProvider; | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         @NonNull | ||||
|         public Builder align(@JLatexMathDrawable.Align int align) { | ||||
|             this.align = align; | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         @NonNull | ||||
|         public Builder fitCanvas(boolean fitCanvas) { | ||||
|             this.fitCanvas = fitCanvas; | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         @NonNull | ||||
|         public Builder padding(@Px int padding) { | ||||
|             this.paddingHorizontal = padding; | ||||
|             this.paddingVertical = padding; | ||||
|             return this; | ||||
|         public JLatexMathTheme.Builder theme() { | ||||
|             return theme; | ||||
|         } | ||||
| 
 | ||||
|         /** | ||||
|          * @since 4.0.0 | ||||
|          * @since 4.3.0-SNAPSHOT | ||||
|          */ | ||||
|         @NonNull | ||||
|         public Builder builder(@Px int paddingHorizontal, @Px int paddingVertical) { | ||||
|             this.paddingHorizontal = paddingHorizontal; | ||||
|             this.paddingVertical = paddingVertical; | ||||
|         public Builder renderMode(@NonNull RenderMode renderMode) { | ||||
|             this.renderMode = renderMode; | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
| @ -319,7 +317,7 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { | ||||
|     } | ||||
| 
 | ||||
|     // @since 4.0.0 | ||||
|     private static class JLatextAsyncDrawableLoader extends AsyncDrawableLoader { | ||||
|     static class JLatextAsyncDrawableLoader extends AsyncDrawableLoader { | ||||
| 
 | ||||
|         private final Config config; | ||||
|         private final Handler handler = new Handler(Looper.getMainLooper()); | ||||
| @ -358,57 +356,15 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { | ||||
| 
 | ||||
|                     private void execute() { | ||||
| 
 | ||||
|                         // @since 4.0.1 (background provider can be null) | ||||
|                         final JLatexMathTheme.BackgroundProvider backgroundProvider = config.backgroundProvider; | ||||
| 
 | ||||
|                         final JLatexMathDrawable jLatexMathDrawable; | ||||
| 
 | ||||
|                         // TODO: obtain real values from theme (for blocks and inlines) | ||||
|                         final JLatextAsyncDrawable jLatextAsyncDrawable = (JLatextAsyncDrawable) drawable; | ||||
|                         if (jLatextAsyncDrawable.isBlock) { | ||||
|                             // create JLatexMathDrawable | ||||
|                             //noinspection ConstantConditions | ||||
|                             jLatexMathDrawable = | ||||
|                                     JLatexMathDrawable.builder(drawable.getDestination()) | ||||
|                                             .textSize(config.textSize) | ||||
|                                             .background(backgroundProvider != null ? backgroundProvider.provide() : null) | ||||
|                                             .align(config.align) | ||||
|                                             .fitCanvas(config.fitCanvas) | ||||
|                                             .padding( | ||||
|                                                     config.paddingHorizontal, | ||||
|                                                     config.paddingVertical, | ||||
|                                                     config.paddingHorizontal, | ||||
|                                                     config.paddingVertical) | ||||
|                                             .build(); | ||||
|                         } else { | ||||
|                             jLatexMathDrawable = | ||||
|                                     JLatexMathDrawable.builder(drawable.getDestination()) | ||||
|                                             .textSize(config.textSize) | ||||
| //                                            .background(backgroundProvider != null ? backgroundProvider.provide() : null) | ||||
| //                                            .align(config.align) | ||||
| //                                            .fitCanvas(config.fitCanvas) | ||||
| //                                            .padding( | ||||
| //                                                    config.paddingHorizontal, | ||||
| //                                                    config.paddingVertical, | ||||
| //                                                    config.paddingHorizontal, | ||||
| //                                                    config.paddingVertical) | ||||
|                                             .build(); | ||||
|                         } | ||||
| 
 | ||||
|                         // create JLatexMathDrawable | ||||
| //                        //noinspection ConstantConditions | ||||
| //                        final JLatexMathDrawable jLatexMathDrawable = | ||||
| //                                JLatexMathDrawable.builder(drawable.getDestination()) | ||||
| //                                        .textSize(config.textSize) | ||||
| //                                        .background(backgroundProvider != null ? backgroundProvider.provide() : null) | ||||
| //                                        .align(config.align) | ||||
| //                                        .fitCanvas(config.fitCanvas) | ||||
| //                                        .padding( | ||||
| //                                                config.paddingHorizontal, | ||||
| //                                                config.paddingVertical, | ||||
| //                                                config.paddingHorizontal, | ||||
| //                                                config.paddingVertical) | ||||
| //                                        .build(); | ||||
|                         if (jLatextAsyncDrawable.isBlock()) { | ||||
|                             jLatexMathDrawable = createBlockDrawable(jLatextAsyncDrawable.getDestination()); | ||||
|                         } else { | ||||
|                             jLatexMathDrawable = createInlineDrawable(jLatextAsyncDrawable.getDestination()); | ||||
|                         } | ||||
| 
 | ||||
|                         // we must post to handler, but also have a way to identify the drawable | ||||
|                         // for which we are posting (in case of cancellation) | ||||
| @ -447,109 +403,63 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { | ||||
|         public Drawable placeholder(@NonNull AsyncDrawable drawable) { | ||||
|             return null; | ||||
|         } | ||||
| 
 | ||||
|         // @since 4.3.0-SNAPSHOT | ||||
|         @NonNull | ||||
|         private JLatexMathDrawable createBlockDrawable(@NonNull String latex) { | ||||
| 
 | ||||
|             final JLatexMathTheme theme = config.theme; | ||||
| 
 | ||||
|             final JLatexMathTheme.BackgroundProvider backgroundProvider = theme.blockBackgroundProvider(); | ||||
|             final JLatexMathTheme.Padding padding = theme.blockPadding(); | ||||
| 
 | ||||
|             final JLatexMathDrawable.Builder builder = JLatexMathDrawable.builder(latex) | ||||
|                     .textSize(theme.blockTextSize()) | ||||
|                     .align(theme.blockHorizontalAlignment()) | ||||
|                     .fitCanvas(theme.blockFitCanvas()); | ||||
| 
 | ||||
|             if (backgroundProvider != null) { | ||||
|                 builder.background(backgroundProvider.provide()); | ||||
|             } | ||||
| 
 | ||||
|     // we must make drawable fit canvas (if specified), but do not keep the ratio whilst scaling up | ||||
|     // @since 4.0.0 | ||||
|     private static class JLatexImageSizeResolver extends ImageSizeResolver { | ||||
| 
 | ||||
|         private final boolean fitCanvas; | ||||
| 
 | ||||
|         JLatexImageSizeResolver(boolean fitCanvas) { | ||||
|             this.fitCanvas = fitCanvas; | ||||
|             if (padding != null) { | ||||
|                 builder.padding(padding.left, padding.top, padding.right, padding.bottom); | ||||
|             } | ||||
| 
 | ||||
|             return builder.build(); | ||||
|         } | ||||
| 
 | ||||
|         // @since 4.3.0-SNAPSHOT | ||||
|         @NonNull | ||||
|         private JLatexMathDrawable createInlineDrawable(@NonNull String latex) { | ||||
| 
 | ||||
|             final JLatexMathTheme theme = config.theme; | ||||
| 
 | ||||
|             final JLatexMathTheme.BackgroundProvider backgroundProvider = theme.inlineBackgroundProvider(); | ||||
|             final JLatexMathTheme.Padding padding = theme.inlinePadding(); | ||||
| 
 | ||||
|             final JLatexMathDrawable.Builder builder = JLatexMathDrawable.builder(latex) | ||||
|                     .textSize(theme.inlineTextSize()) | ||||
|                     .fitCanvas(false); | ||||
| 
 | ||||
|             if (backgroundProvider != null) { | ||||
|                 builder.background(backgroundProvider.provide()); | ||||
|             } | ||||
| 
 | ||||
|             if (padding != null) { | ||||
|                 builder.padding(padding.left, padding.top, padding.right, padding.bottom); | ||||
|             } | ||||
| 
 | ||||
|             return builder.build(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private static class InlineImageSizeResolver extends ImageSizeResolver { | ||||
| 
 | ||||
|         @NonNull | ||||
|         @Override | ||||
|         public Rect resolveImageSize(@NonNull AsyncDrawable drawable) { | ||||
| 
 | ||||
|             final Rect imageBounds = drawable.getResult().getBounds(); | ||||
|             final int canvasWidth = drawable.getLastKnownCanvasWidth(); | ||||
| 
 | ||||
|             if (fitCanvas) { | ||||
| 
 | ||||
|                 // we modify bounds only if `fitCanvas` is true | ||||
|                 final int w = imageBounds.width(); | ||||
| 
 | ||||
|                 if (w < canvasWidth) { | ||||
|                     // increase width and center formula (keep height as-is) | ||||
|                     return new Rect(0, 0, canvasWidth, imageBounds.height()); | ||||
|                 } | ||||
| 
 | ||||
|                 // @since 4.0.2 we additionally scale down the resulting formula (keeping the ratio) | ||||
|                 // the thing is - JLatexMathDrawable will do it anyway, but it will modify its own | ||||
|                 // bounds (which AsyncDrawable won't catch), thus leading to an empty space after the formula | ||||
|                 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; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private static class JLatextAsyncDrawable extends AsyncDrawable { | ||||
| 
 | ||||
|         private final boolean isBlock; | ||||
| 
 | ||||
|         public JLatextAsyncDrawable( | ||||
|                 @NonNull String destination, | ||||
|                 @NonNull AsyncDrawableLoader loader, | ||||
|                 @NonNull ImageSizeResolver imageSizeResolver, | ||||
|                 @Nullable ImageSize imageSize, | ||||
|                 boolean isBlock | ||||
|         ) { | ||||
|             super(destination, loader, imageSizeResolver, imageSize); | ||||
|             this.isBlock = isBlock; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private static class JLatexAsyncDrawableSpan extends AsyncDrawableSpan { | ||||
| 
 | ||||
|         private final AsyncDrawable drawable; | ||||
| 
 | ||||
|         public JLatexAsyncDrawableSpan(@NonNull MarkwonTheme theme, @NonNull AsyncDrawable drawable, int alignment, boolean replacementTextIsLink) { | ||||
|             super(theme, drawable, alignment, replacementTextIsLink); | ||||
|             this.drawable = drawable; | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public int getSize( | ||||
|                 @NonNull Paint paint, | ||||
|                 CharSequence text, | ||||
|                 @IntRange(from = 0) int start, | ||||
|                 @IntRange(from = 0) int end, | ||||
|                 @Nullable Paint.FontMetricsInt fm) { | ||||
| 
 | ||||
|             // if we have no async drawable result - we will just render text | ||||
| 
 | ||||
|             final int size; | ||||
| 
 | ||||
|             if (drawable.hasResult()) { | ||||
| 
 | ||||
|                 final Rect rect = drawable.getBounds(); | ||||
| 
 | ||||
|                 if (fm != null) { | ||||
|                     final int half = rect.bottom / 2; | ||||
|                     fm.ascent = -half; | ||||
|                     fm.descent = half; | ||||
| 
 | ||||
|                     fm.top = fm.ascent; | ||||
|                     fm.bottom = 0; | ||||
|                 } | ||||
| 
 | ||||
|                 size = rect.right; | ||||
| 
 | ||||
|             } else { | ||||
| 
 | ||||
|                 // NB, no specific text handling (no new lines, etc) | ||||
|                 size = (int) (paint.measureText(text, start, end) + .5F); | ||||
|             } | ||||
| 
 | ||||
|             return size; | ||||
|             return drawable.getResult().getBounds(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -128,9 +128,9 @@ public abstract class JLatexMathTheme { | ||||
|         private BackgroundProvider inlineBackgroundProvider; | ||||
|         private BackgroundProvider blockBackgroundProvider; | ||||
| 
 | ||||
|         private boolean blockFitCanvas; | ||||
|         private boolean blockFitCanvas = true; | ||||
|         // horizontal alignment (when there is additional horizontal space) | ||||
|         private int blockHorizontalAlignment; | ||||
|         private int blockHorizontalAlignment = JLatexMathDrawable.ALIGN_CENTER; | ||||
| 
 | ||||
|         private Padding padding; | ||||
|         private Padding inlinePadding; | ||||
| @ -196,7 +196,7 @@ public abstract class JLatexMathTheme { | ||||
| 
 | ||||
|         @NonNull | ||||
|         public JLatexMathTheme build() { | ||||
|             return null; | ||||
|             return new Impl(this); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -0,0 +1,32 @@ | ||||
| package io.noties.markwon.ext.latex; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| 
 | ||||
| import io.noties.markwon.image.AsyncDrawable; | ||||
| import io.noties.markwon.image.AsyncDrawableLoader; | ||||
| import io.noties.markwon.image.ImageSize; | ||||
| import io.noties.markwon.image.ImageSizeResolver; | ||||
| 
 | ||||
| /** | ||||
|  * @since 4.3.0-SNAPSHOT | ||||
|  */ | ||||
| class JLatextAsyncDrawable extends AsyncDrawable { | ||||
| 
 | ||||
|     private final boolean isBlock; | ||||
| 
 | ||||
|     JLatextAsyncDrawable( | ||||
|             @NonNull String destination, | ||||
|             @NonNull AsyncDrawableLoader loader, | ||||
|             @NonNull ImageSizeResolver imageSizeResolver, | ||||
|             @Nullable ImageSize imageSize, | ||||
|             boolean isBlock | ||||
|     ) { | ||||
|         super(destination, loader, imageSizeResolver, imageSize); | ||||
|         this.isBlock = isBlock; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isBlock() { | ||||
|         return isBlock; | ||||
|     } | ||||
| } | ||||
| @ -1,7 +1,7 @@ | ||||
| package io.noties.markwon.sample.latex; | ||||
| 
 | ||||
| import android.content.res.Resources; | ||||
| import android.graphics.drawable.ColorDrawable; | ||||
| import android.graphics.drawable.Drawable; | ||||
| import android.os.Bundle; | ||||
| import android.widget.TextView; | ||||
| 
 | ||||
| @ -14,7 +14,6 @@ import io.noties.markwon.ext.latex.JLatexMathTheme; | ||||
| import io.noties.markwon.sample.ActivityWithMenuOptions; | ||||
| import io.noties.markwon.sample.MenuOptions; | ||||
| import io.noties.markwon.sample.R; | ||||
| import ru.noties.jlatexmath.JLatexMathDrawable; | ||||
| 
 | ||||
| public class LatexActivity extends ActivityWithMenuOptions { | ||||
| 
 | ||||
| @ -87,7 +86,7 @@ public class LatexActivity extends ActivityWithMenuOptions { | ||||
|     private static String wrapLatexInSampleMarkdown(@NonNull String latex) { | ||||
|         return "" + | ||||
|                 "# Example of LaTeX\n\n" + | ||||
|                 "(inline): $$" + latex + "$$ so nice, really? Now, (block):\n\n" + | ||||
|                 "(inline): $$" + latex + "$$ so nice, really-really really-really really-really? Now, (block):\n\n" + | ||||
|                 "$$\n" + | ||||
|                 "" + latex + "\n" + | ||||
|                 "$$\n\n" + | ||||
| @ -95,23 +94,22 @@ public class LatexActivity extends ActivityWithMenuOptions { | ||||
|     } | ||||
| 
 | ||||
|     private void render(@NonNull String markdown) { | ||||
| 
 | ||||
|         final float textSize = textView.getTextSize(); | ||||
|         final Resources r = getResources(); | ||||
| 
 | ||||
|         final Markwon markwon = Markwon.builder(this) | ||||
|                 .usePlugin(JLatexMathPlugin.create(textView.getTextSize(), new JLatexMathPlugin.BuilderConfigure() { | ||||
|                     @Override | ||||
|                     public void configureBuilder(@NonNull JLatexMathPlugin.Builder builder) { | ||||
|                         builder | ||||
|                                 .backgroundProvider(new JLatexMathTheme.BackgroundProvider() { | ||||
|                                     @NonNull | ||||
|                                     @Override | ||||
|                                     public Drawable provide() { | ||||
|                                         return new ColorDrawable(0x40ff0000); | ||||
|                                     } | ||||
|                                 }) | ||||
|                                 .fitCanvas(true) | ||||
|                                 .align(JLatexMathDrawable.ALIGN_CENTER) | ||||
|                                 .padding(48) | ||||
|                         ; | ||||
|                     } | ||||
|                 .usePlugin(JLatexMathPlugin.create(textSize, textSize * 1.25F, builder -> { | ||||
|                     builder.theme() | ||||
|                             .inlineBackgroundProvider(() -> new ColorDrawable(0x1000ff00)) | ||||
|                             .blockBackgroundProvider(() -> new ColorDrawable(0x10ff0000)) | ||||
|                             .blockPadding(JLatexMathTheme.Padding.symmetric( | ||||
|                                     r.getDimensionPixelSize(R.dimen.latex_block_padding_vertical), | ||||
|                                     r.getDimensionPixelSize(R.dimen.latex_block_padding_horizontal) | ||||
|                             )); | ||||
| 
 | ||||
|                     // explicitly request LEGACY rendering mode | ||||
| //                    builder.renderMode(JLatexMathPlugin.RenderMode.LEGACY); | ||||
|                 })) | ||||
|                 .build(); | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										5
									
								
								sample/src/main/res/values/dimens.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								sample/src/main/res/values/dimens.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|     <dimen name="latex_block_padding_vertical">8dip</dimen> | ||||
|     <dimen name="latex_block_padding_horizontal">16dip</dimen> | ||||
| </resources> | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user