package com.scrivenvar.preview;
import com.scrivenvar.util.BoundedCache;
import org.apache.commons.io.FilenameUtils;
import org.w3c.dom.Element;
import org.xhtmlrenderer.extend.ReplacedElement;
import org.xhtmlrenderer.extend.ReplacedElementFactory;
import org.xhtmlrenderer.extend.UserAgentCallback;
import org.xhtmlrenderer.layout.LayoutContext;
import org.xhtmlrenderer.render.BlockBox;
import org.xhtmlrenderer.simple.extend.FormSubmissionListener;
import org.xhtmlrenderer.swing.ImageReplacedElement;
import java.awt.image.BufferedImage;
import java.util.Map;
import java.util.function.Function;
import static com.scrivenvar.StatusBarNotifier.alert;
import static com.scrivenvar.preview.SvgRasterizer.rasterize;
import static com.scrivenvar.processors.markdown.tex.TeXNode.HTML_TEX;
public class SvgReplacedElementFactory implements ReplacedElementFactory {
private static class MathRendererContainer {
private static final MathRenderer INSTANCE = new MathRenderer();
}
public static MathRenderer getInstance() {
return MathRendererContainer.INSTANCE;
}
private static final String SVG_FILE = "svg";
private static final String HTML_IMAGE = "img";
private static final String HTML_IMAGE_SRC = "src";
private final Map<String, BufferedImage> mImageCache =
new BoundedCache<>( 150 );
@Override
public ReplacedElement createReplacedElement(
final LayoutContext c,
final BlockBox box,
final UserAgentCallback uac,
final int cssWidth,
final int cssHeight ) {
BufferedImage image = null;
final var e = box.getElement();
if( e != null ) {
try {
final var nodeName = e.getNodeName();
if( HTML_IMAGE.equals( nodeName ) ) {
final var src = e.getAttribute( HTML_IMAGE_SRC );
final var ext = FilenameUtils.getExtension( src );
if( SVG_FILE.equalsIgnoreCase( ext ) ) {
image = getCachedImage(
src, svg -> rasterize( svg, box.getContentWidth() ) );
}
}
else if( HTML_TEX.equals( nodeName ) ) {
final var src = e.getTextContent();
image = getCachedImage(
src, __ -> rasterize( getInstance().render( src ) )
);
}
} catch( final Exception ex ) {
alert( ex );
}
}
if( image != null ) {
final var w = image.getWidth( null );
final var h = image.getHeight( null );
return new ImageReplacedElement( image, w, h );
}
return null;
}
@Override
public void reset() {
}
@Override
public void remove( final Element e ) {
}
@Override
public void setFormSubmissionListener( FormSubmissionListener listener ) {
}
private BufferedImage getCachedImage(
final String src, final Function<String, BufferedImage> rasterizer ) {
return mImageCache.computeIfAbsent( src, __ -> rasterizer.apply( src ) );
}
}