From 7063b15a74509903171e4c9f50ca4605abd0ff41 Mon Sep 17 00:00:00 2001 From: stepan <stepan.sindelar@oracle.com> Date: Wed, 4 Oct 2017 18:07:40 +0200 Subject: [PATCH] Do not use String.format in SVGDevice --- .../r/library/fastrGrid/device/GridColor.java | 1 + .../r/library/fastrGrid/device/SVGDevice.java | 56 +++++++++++-------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/GridColor.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/GridColor.java index ec11023ea1..2472e266ca 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/GridColor.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/GridColor.java @@ -30,6 +30,7 @@ public final class GridColor { public static final int OPAQUE_ALPHA = 0xff; private static final int TRANSPARENT_ALPHA = 0; public static final GridColor TRANSPARENT = new GridColor(0, 0, 0, TRANSPARENT_ALPHA); + public static final GridColor BLACK = new GridColor(0, 0, 0, OPAQUE_ALPHA); private final int value; diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/SVGDevice.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/SVGDevice.java index 7b2ca6efef..cd82ccda80 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/SVGDevice.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/SVGDevice.java @@ -24,6 +24,7 @@ package com.oracle.truffle.r.library.fastrGrid.device; import static com.oracle.truffle.r.library.fastrGrid.device.DrawingContext.GRID_LINE_BLANK; import static com.oracle.truffle.r.library.fastrGrid.device.DrawingContext.INCH_TO_POINTS_FACTOR; +import static java.lang.Math.round; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -70,9 +71,9 @@ public class SVGDevice implements GridDevice, FileGridDevice { cachedCtx = null; data.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); data.append("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"); - append("<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' version='1.1' viewBox='0 0 %.3f %.3f'>\n", - width * COORD_FACTOR, - height * COORD_FACTOR); + append("<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' version='1.1' viewBox='0 0 %d %d' style='fill:transparent'>\n", + trRound(width), + trRound(height)); } @Override @@ -90,9 +91,10 @@ public class SVGDevice implements GridDevice, FileGridDevice { @Override public void drawRect(DrawingContext ctx, double leftX, double bottomY, double newWidth, double newHeight, double rotationAnticlockWise) { appendStyle(ctx); - append("<rect x='%.3f' y='%.3f' width='%.3f' height='%.3f'", leftX * COORD_FACTOR, transY(bottomY + newHeight) * COORD_FACTOR, newWidth * COORD_FACTOR, newHeight * COORD_FACTOR); + data.append("<rect x='").append(trRound(leftX)).append("' y='").append(trRound(transY(bottomY + newHeight))).append("' width='").append(trRound(newWidth)).append("' height='").append( + trRound(newHeight)).append('\''); if (rotationAnticlockWise != 0) { - append(" transform='rotate(%.3f %.3f,%.3f)'", toDegrees(rotationAnticlockWise), (leftX + newWidth / 2.) * COORD_FACTOR, transY(bottomY + newHeight / 2.) * COORD_FACTOR); + appendTransform((int) round(toDegrees(rotationAnticlockWise)), trRound(leftX + newWidth / 2.), trRound(transY(bottomY + newHeight / 2.))); } appendColorStyle(ctx); data.append("/>\n"); // end of 'rect' tag @@ -100,18 +102,18 @@ public class SVGDevice implements GridDevice, FileGridDevice { @Override public void drawPolyLines(DrawingContext ctx, double[] x, double[] y, int startIndex, int length) { - drawPoly(ctx, x, y, startIndex, length, "transparent"); + drawPoly(ctx, x, y, startIndex, length, true); } @Override public void drawPolygon(DrawingContext ctx, double[] x, double[] y, int startIndex, int length) { - drawPoly(ctx, x, y, startIndex, length, null); + drawPoly(ctx, x, y, startIndex, length, false); } @Override public void drawCircle(DrawingContext ctx, double centerX, double centerY, double radius) { appendStyle(ctx); - append("<circle cx='%.3f' cy='%.3f' r='%.3f'", centerX * COORD_FACTOR, transY(centerY) * COORD_FACTOR, radius * COORD_FACTOR); + data.append("<circle cx='").append(trRound(centerX)).append("' cy='").append(trRound(transY(centerY))).append("' r='").append(trRound(radius)).append('\''); appendColorStyle(ctx); data.append("/>\n"); } @@ -120,18 +122,19 @@ public class SVGDevice implements GridDevice, FileGridDevice { public void drawRaster(double leftX, double bottomY, double width, double height, int[] pixels, int pixelsColumnsCount, ImageInterpolation interpolation) { byte[] bitmap = Bitmap.create(pixels, pixelsColumnsCount); String base64 = Base64.getEncoder().encodeToString(bitmap); - append("<image x='%.3f' y='%.3f' width='%.3f' height='%.3f' preserveAspectRatio='none' xlink:href='data:image/bmp;base64,%s'/>\n", leftX * COORD_FACTOR, - transY(bottomY + height) * COORD_FACTOR, - width * COORD_FACTOR, height * COORD_FACTOR, base64); + data.append("<image x='").append(round(leftX * COORD_FACTOR)).append("' y='").append(trRound(transY(bottomY + height))); + data.append("' width='").append(round(width * COORD_FACTOR)).append("' height='").append(trRound(height)); + data.append("' preserveAspectRatio='none' xlink:href='data:image/bmp;base64,").append(base64).append("'/>\n"); } @Override public void drawString(DrawingContext ctx, double leftX, double bottomY, double rotationAnticlockWise, String text) { closeStyle(); - append("<text x='%.3f' y='%.3f' textLength='%.3fpx' lengthAdjust='spacingAndGlyphs'", leftX * COORD_FACTOR, transY(bottomY) * COORD_FACTOR, getStringWidth(ctx, text) * COORD_FACTOR); + data.append("<text x='").append(round(leftX * COORD_FACTOR)).append("' y='").append(trRound(transY(bottomY))); + data.append("' lengthAdjust='spacingAndGlyphs' textLength='").append(round(getStringWidth(ctx, text) * COORD_FACTOR)).append("px'"); appendFontStyle(ctx); if (rotationAnticlockWise != 0) { - append(" transform='rotate(%.3f %.3f,%.3f)'", toDegrees(rotationAnticlockWise), leftX * COORD_FACTOR, transY(bottomY) * COORD_FACTOR); + appendTransform((int) round(toDegrees(rotationAnticlockWise)), trRound(leftX), trRound(transY(bottomY))); } data.append(">").append(text).append("</text>\n"); } @@ -177,20 +180,20 @@ public class SVGDevice implements GridDevice, FileGridDevice { return 0.7 * (ctx.getFontSize() / INCH_TO_POINTS_FACTOR); } - private void drawPoly(DrawingContext ctx, double[] x, double[] y, int startIndex, int length, String fillColorOverride) { + private void drawPoly(DrawingContext ctx, double[] x, double[] y, int startIndex, int length, boolean noFill) { appendStyle(ctx); data.append("<polyline points='"); for (int i = 0; i < length; i++) { - data.append(DECIMAL_FORMAT.format(x[i + startIndex] * COORD_FACTOR)); + data.append(trRound(x[i + startIndex])); data.append(','); - data.append(DECIMAL_FORMAT.format(transY(y[i + startIndex]) * COORD_FACTOR)); + data.append(trRound(transY(y[i + startIndex]))); if (i != length - 1) { data.append(' '); } } data.append('\''); - appendColorStyle(ctx, fillColorOverride); - data.append("/>"); + appendColorStyle(ctx, noFill); + data.append("/>\n"); } private void saveFile() throws DeviceCloseException { @@ -254,10 +257,10 @@ public class SVGDevice implements GridDevice, FileGridDevice { } private void appendColorStyle(DrawingContext ctx) { - appendColorStyle(ctx, null); + appendColorStyle(ctx, false); } - private void appendColorStyle(DrawingContext ctx, String fillColorOverride) { + private void appendColorStyle(DrawingContext ctx, boolean noFill) { byte[] lineType = ctx.getLineType(); if (lineType == GRID_LINE_BLANK) { data.append(" style='stroke:transparent"); @@ -265,11 +268,10 @@ public class SVGDevice implements GridDevice, FileGridDevice { data.append(" style='"); appendStyleColorAttrs("stroke", ctx.getColor()); } - if (fillColorOverride == null) { + if (!noFill && !ctx.getFillColor().equals(GridColor.TRANSPARENT)) { data.append(';'); appendStyleColorAttrs("fill", ctx.getFillColor()); - } else { - data.append(";fill:").append(fillColorOverride); + data.append('\''); } data.append('\''); } @@ -337,6 +339,10 @@ public class SVGDevice implements GridDevice, FileGridDevice { data.append(Utils.stringFormat(fmt, args)); } + private void appendTransform(int a, int b, int c) { + data.append(" transform='rotate(").append(a).append(',').append(b).append(',').append(c).append(")'"); + } + private double transY(double y) { return (height - y); } @@ -345,6 +351,10 @@ public class SVGDevice implements GridDevice, FileGridDevice { return (180. / Math.PI) * -rotationAnticlockWise; } + private int trRound(double value) { + return (int) Math.round(value * COORD_FACTOR); + } + static boolean areSameGlobalStyles(DrawingContext ctx1, DrawingContext ctx2) { return ctx1 == ctx2 || (ctx1.getLineEnd() == ctx2.getLineEnd() && ctx1.getLineJoin() == ctx2.getLineJoin() && -- GitLab