Skip to content

Commit

Permalink
#350 - Much improved sizing support for SVG images.
Browse files Browse the repository at this point in the history
Including min-width/min-height and border-box sizing. With test.
  • Loading branch information
danfickle committed May 6, 2019
1 parent ab9a1f9 commit 965e7d4
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -737,16 +737,25 @@ private void sizeReplacedElement(LayoutContext c, ReplacedElement re) {
int intrinsicWidth = re.getIntrinsicWidth();
int intrinsicHeight = re.getIntrinsicHeight();

cssWidth = !getStyle().isMaxWidthNone() && intrinsicWidth > getCSSMaxWidth(c) ?
cssWidth = !getStyle().isMaxWidthNone() &&
(intrinsicWidth > getCSSMaxWidth(c) || cssWidth > getCSSMaxWidth(c)) ?
getCSSMaxWidth(c) : cssWidth;
cssWidth = getCSSMinWidth(c) > 0 && cssWidth < getCSSMinWidth(c) ?
getCSSMinWidth(c) : cssWidth;

cssHeight = !getStyle().isMaxHeightNone() && intrinsicHeight > getCSSMaxHeight(c) ?
cssHeight = !getStyle().isMaxHeightNone() &&
(intrinsicHeight > getCSSMaxHeight(c) || cssHeight > getCSSMaxHeight(c)) ?
getCSSMaxHeight(c) : cssHeight;
cssHeight = getCSSMinHeight(c) > 0 && cssHeight < getCSSMinHeight(c) ?
getCSSMinHeight(c) : cssHeight;

if (getStyle().isBorderBox()) {
BorderPropertySet border = getBorder(c);
RectPropertySet padding = getPadding(c);
cssWidth = (int) Math.max(0, cssWidth - border.width() - padding.width());
cssHeight = (int) Math.max(0, cssHeight - border.height() - padding.height());
}

int nw;
int nh;

Expand Down Expand Up @@ -798,13 +807,8 @@ private void sizeReplacedElement(LayoutContext c, ReplacedElement re) {
nh = intrinsicHeight;
}

if (getStyle().isBorderBox()) {
setBorderBoxWidth(c, nw);
setBorderBoxHeight(c, nh);
} else {
setContentWidth(nw);
setHeight(nh);
}
setContentWidth(nw);
setHeight(nh);
}

public void calcDimensions(LayoutContext c) {
Expand Down
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<html>
<head>
<style>
@page {
size: 500px 1500px;
margin: 0;
}
body {
margin: 0;
}
svg {
display: block;
border: 2px solid red;
margin: 2px;
}
</style>
</head>
<body>
<!-- width only -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 100" style="width: 100px;">
<rect width="150" height="100" style="fill:rgb(0,0,255);" rx="15" />
</svg>

<!-- height only -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 100" style="height: 100px;">
<rect width="150" height="100" style="fill:rgb(0,0,255);" rx="15" />
</svg>

<!-- min-width -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 100" style="width: 100px; min-width: 200px;">
<rect width="150" height="100" style="fill:rgb(0,0,255);" rx="15" />
</svg>

<!-- min-height -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 100" style="height: 100px; min-height: 150px;">
<rect width="150" height="100" style="fill:rgb(0,0,255);" rx="15" />
</svg>

<!-- max-width -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 100" style="width: 400px; max-width: 70px;">
<rect width="150" height="100" style="fill:rgb(0,0,255);" rx="15" />
</svg>

<!-- max-height -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 100" style="height: 400px; max-height: 80px;">
<rect width="150" height="100" style="fill:rgb(0,0,255);" rx="15" />
</svg>

<!-- border-box -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 100" style="padding: 50px; width: 220px; box-sizing: border-box;">
<rect width="150" height="100" style="fill:rgb(0,0,255);" rx="15" />
</svg>

<!-- content-box -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 100" style="padding: 50px; width: 200px; box-sizing: content-box;">
<rect width="150" height="100" style="fill:rgb(0,0,255);" rx="15" />
</svg>

<!-- width and height -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 100" style="width: 100px; height: 100px;">
<rect width="150" height="100" style="fill:rgb(0,0,255);" rx="15" />
</svg>

<!-- border-box with different padding values -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 100" style="padding: 0 10px 20px 40px; width: 220px; box-sizing: border-box;">
<rect width="150" height="100" style="fill:rgb(0,0,255);" rx="15" />
</svg>
</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,15 @@ public void testReplacedSizingImg() throws IOException {
assertTrue(vt.runTest("replaced-sizing-img"));
}

/**
* Tests various sizing properties for replaced SVG images including box-sizing,
* min/max, etc.
*/
@Test
public void testReplacedSizingSvg() throws IOException {
assertTrue(vt.runTest("replaced-sizing-svg", WITH_SVG));
}

// TODO:
// + Elements that appear just on generated overflow pages.
// + content property (page counters, etc)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public SVGImage buildSVGImage(Element svgElement, Box box, CssContext c,
double cssMaxWidth = CalculatedStyle.getCSSMaxWidth(c, box);
double cssMaxHeight = CalculatedStyle.getCSSMaxHeight(c, box);

BatikSVGImage img = new BatikSVGImage(svgElement, cssWidth, cssHeight,
BatikSVGImage img = new BatikSVGImage(svgElement, box, cssWidth, cssHeight,
cssMaxWidth, cssMaxHeight, dotsPerPixel);
img.setFontResolver(fontResolver);
return img;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import com.openhtmltopdf.extend.OutputDevice;
import com.openhtmltopdf.extend.SVGDrawer.SVGImage;
import com.openhtmltopdf.render.Box;
import com.openhtmltopdf.render.RenderingContext;
import com.openhtmltopdf.svgsupport.PDFTranscoder.OpenHtmlFontResolver;
import com.openhtmltopdf.util.XRLog;
Expand All @@ -27,12 +28,12 @@ public class BatikSVGImage implements SVGImage {

private PDFTranscoder pdfTranscoder;

public BatikSVGImage(Element svgElement, double cssWidth, double cssHeight,
public BatikSVGImage(Element svgElement, Box box, double cssWidth, double cssHeight,
double cssMaxWidth, double cssMaxHeight, double dotsPerPixel) {
this.svgElement = svgElement;
this.dotsPerPixel = dotsPerPixel;

this.pdfTranscoder = new PDFTranscoder(cssWidth, cssHeight);
this.pdfTranscoder = new PDFTranscoder(box, dotsPerPixel, cssWidth, cssHeight);
if (cssWidth >= 0) {
this.pdfTranscoder.addTranscodingHint(
SVGAbstractTranscoder.KEY_WIDTH,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.openhtmltopdf.extend.OutputDevice;
import com.openhtmltopdf.extend.OutputDeviceGraphicsDrawer;
import com.openhtmltopdf.layout.SharedContext;
import com.openhtmltopdf.render.Box;
import com.openhtmltopdf.render.RenderingContext;
import com.openhtmltopdf.util.XRLog;
import org.apache.batik.bridge.FontFace;
Expand All @@ -21,6 +22,8 @@

import java.awt.*;
import java.awt.font.TextAttribute;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
Expand All @@ -31,17 +34,22 @@ public class PDFTranscoder extends SVGAbstractTranscoder {
private OutputDevice outputDevice;
private double x;
private double y;
private final Box box;
private RenderingContext ctx;
private final double dotsPerPixel;

public PDFTranscoder(double width, double height ) {
public PDFTranscoder(Box box, double dotsPerPixel, double width, double height) {
this.box = box;
this.width = (float)width;
this.height = (float)height;
this.dotsPerPixel = dotsPerPixel;
}

public void setRenderingParameters(OutputDevice od, RenderingContext ctx, double x, double y, OpenHtmlFontResolver fontResolver) {
this.x = x;
this.y = y;
this.outputDevice = od;

this.ctx = ctx;
this.fontResolver = fontResolver;
}

Expand Down Expand Up @@ -199,14 +207,71 @@ protected void transcode(Document svg, String uri, TranscoderOutput out) throws
// is called before our constructor is called in the super constructor.
this.userAgent = new OpenHtmlUserAgent(this.fontResolver);
super.transcode(svg, uri, out);

outputDevice.drawWithGraphics((float)x, (float)y, width, height, new OutputDeviceGraphicsDrawer() {

int intrinsicWidth = (int) width;
int intrinsicHeight = (int) height;

Rectangle contentBounds = box.getContentAreaEdge(box.getAbsX(), box.getAbsY(), ctx);

int desiredWidth = (int) (contentBounds.width / this.dotsPerPixel);
int desiredHeight = (int) (contentBounds.height / this.dotsPerPixel);

boolean transformed = false;
AffineTransform scale = null;

if (width == 0 || height == 0) {
// Do nothing...
}
else if (desiredWidth > intrinsicWidth &&
desiredHeight > intrinsicHeight) {

double rw = (double) desiredWidth / width;
double rh = (double) desiredHeight / height;

double factor = Math.min(rw, rh);
scale = AffineTransform.getScaleInstance(factor, factor);
transformed = true;
} else if (desiredWidth < intrinsicWidth &&
desiredHeight < intrinsicHeight) {
double rw = (double) desiredWidth / width;
double rh = (double) desiredHeight / height;

double factor = Math.max(rw, rh);
scale = AffineTransform.getScaleInstance(factor, factor);
transformed = true;
}

AffineTransform inverseScale = null;
try {
if (transformed) {
inverseScale = scale.createInverse();
}
} catch (NoninvertibleTransformException e) {
transformed = false;
}
final AffineTransform scale2 = scale;
final AffineTransform inverse2 = inverseScale;
final boolean transformed2 = transformed;

outputDevice.drawWithGraphics(
(float) x,
(float) y,
(float) (contentBounds.width / this.dotsPerPixel),
(float) (contentBounds.height / this.dotsPerPixel),
new OutputDeviceGraphicsDrawer() {
@Override
public void render(Graphics2D graphics2D) {
if (transformed2) {
graphics2D.transform(scale2);
}
/*
* Do the real paint
*/
PDFTranscoder.this.root.paint(graphics2D);

if (transformed2) {
graphics2D.transform(inverse2);
}
}
});
}
Expand Down

0 comments on commit 965e7d4

Please sign in to comment.