diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/FastRGridExternalLookup.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/FastRGridExternalLookup.java index 5863de72a47db700e3e773967266d68c1312da39..b2d0f365a4671906ea50704e74880d4f987328ed 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/FastRGridExternalLookup.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/FastRGridExternalLookup.java @@ -22,6 +22,7 @@ */ package com.oracle.truffle.r.library.fastrGrid; +import com.oracle.truffle.r.library.fastrGrid.grDevices.DevHoldFlush; import com.oracle.truffle.r.library.fastrGrid.grDevices.InitWindowedDevice; import com.oracle.truffle.r.library.fastrGrid.graphics.CPar; import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; @@ -42,7 +43,7 @@ public class FastRGridExternalLookup { public static RExternalBuiltinNode lookupDotExternal(String name) { switch (name) { case "devholdflush": - return new IgnoredGridExternal(RNull.instance); + return DevHoldFlush.create(); case "PDF": return new IgnoredGridExternal(RNull.instance); default: diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GPar.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GPar.java index 41d785ee1fcffc9bfc4c4e39a4a719d10aadb226..6f69df073cbb3035caf1effbb0d77ef62ec23009 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GPar.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GPar.java @@ -17,7 +17,9 @@ import static com.oracle.truffle.r.library.fastrGrid.GridUtils.asDouble; import java.util.Arrays; import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext; +import com.oracle.truffle.r.library.fastrGrid.device.DrawingContextDefaults; import com.oracle.truffle.r.library.fastrGrid.device.GridColor; +import com.oracle.truffle.r.library.fastrGrid.device.GridDevice; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.RRuntime; @@ -84,11 +86,12 @@ public final class GPar { }; private static final RStringVector NAMES_VECTOR = (RStringVector) RDataFactory.createStringVector(NAMES, RDataFactory.COMPLETE_VECTOR).makeSharedPermanent(); - public static RList createNew() { + public static RList createNew(GridDevice device) { Object[] data = new Object[GP_LENGTH]; + DrawingContextDefaults defaults = device.getDrawingContextDefaults(); Arrays.fill(data, RNull.instance); - data[GP_FILL] = "transparent"; - data[GP_COL] = "black"; + data[GP_COL] = defaults.color; + data[GP_FILL] = defaults.fillColor; data[GP_GAMMA] = newDoubleVec(0); data[GP_LTY] = "solid"; data[GP_LWD] = newDoubleVec(1); @@ -102,7 +105,9 @@ public final class GPar { data[GP_LINEJOIN] = "round"; data[GP_LINEMITRE] = newDoubleVec(10); data[GP_LEX] = newDoubleVec(1); - return RDataFactory.createList(data, NAMES_VECTOR); + RList result = RDataFactory.createList(data, NAMES_VECTOR); + result.makeSharedPermanent(); + return result; } public static double getCex(RList gpar) { @@ -122,6 +127,7 @@ public final class GPar { private GParDrawingContext(RList list) { data = list.getDataWithoutCopying(); + list.makeSharedPermanent(); } @Override @@ -158,11 +164,6 @@ public final class GPar { return getGridColor(GP_COL); } - @Override - public void setColor(GridColor color) { - data[GP_COL] = GridColorUtils.gridColorToRString(color); - } - @Override public double getFontSize() { return asDouble(data[GP_FONTSIZE]) * asDouble(data[GP_CEX]); @@ -178,11 +179,6 @@ public final class GPar { return getGridColor(GP_FILL); } - @Override - public void setFillColor(GridColor color) { - data[GP_FILL] = GridColorUtils.gridColorToRString(color); - } - private GridColor getGridColor(int index) { return GridColorUtils.gridColorFromString(RRuntime.asString(data[index])); } diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridContext.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridContext.java index 2980378933908efae26bb8a345024acd57714529..ec68fcff20f2af94b77f30ea667e8bb8b0164465 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridContext.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridContext.java @@ -22,6 +22,7 @@ */ package com.oracle.truffle.r.library.fastrGrid; +import com.oracle.truffle.r.library.fastrGrid.device.BufferedJFrameDevice; import com.oracle.truffle.r.library.fastrGrid.device.GridDevice; import com.oracle.truffle.r.library.fastrGrid.device.JFrameDevice; @@ -43,7 +44,7 @@ public final class GridContext { public GridDevice getCurrentDevice() { if (currentDevice == null) { - currentDevice = new JFrameDevice(); + currentDevice = new BufferedJFrameDevice(new JFrameDevice()); } return currentDevice; } diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridState.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridState.java index 5d840cbf68fcdea0a1a4b761ee232408bc0d8824..fbedb1f85323c1fcee0b6015e237fd051362ec4f 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridState.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridState.java @@ -23,6 +23,7 @@ public final class GridState { private REnvironment gridEnv; private double scale = 1; private boolean deviceInitialized; + private int devHoldCount; /** * Current grob being drawn (for determining the list of grobs to search when evaluating a @@ -33,6 +34,15 @@ public final class GridState { GridState() { } + public int getDevHoldCount() { + return devHoldCount; + } + + public int setDevHoldCount(int devHoldCount) { + this.devHoldCount = devHoldCount; + return devHoldCount; + } + public void init(REnvironment gridEnv, GridDevice currentDevice) { this.gridEnv = gridEnv; this.currentGrob = RNull.instance; @@ -40,14 +50,11 @@ public final class GridState { } void initGPar(GridDevice currentDevice) { - gpar = GPar.createNew(); - currentDevice.initDrawingContext(GPar.asDrawingContext(gpar)); + gpar = GPar.createNew(currentDevice); } public static DrawingContext getInitialGPar(GridDevice device) { - DrawingContext result = GPar.asDrawingContext(GPar.createNew()); - device.initDrawingContext(result); - return result; + return GPar.asDrawingContext(GPar.createNew(device)); } public RList getGpar() { diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LPoints.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LPoints.java index fb8977b780450c1967a5dc81b0de4272ea14640a..d4b71e0a5baadde23ac35c280a5362ba0fe7f908 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LPoints.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LPoints.java @@ -73,11 +73,12 @@ public abstract class LPoints extends RExternalBuiltinNode.Arg4 { // Note: unlike in other drawing primitives, we only consider length of x int length = unitLength.execute(xVec); + PointDrawingContext pointDrawingCtx = new PointDrawingContext(drawingCtx, drawingCtx.getFillColor(), drawingCtx.getFillColor()); for (int i = 0; i < length; i++) { Point loc = TransformMatrix.transLocation(Point.fromUnits(unitToInches, xVec, yVec, i, conversionCtx), vpTransform.transform); double size = unitToInches.convertWidth(sizeVec, i, conversionCtx); if (loc.isFinite() && Double.isFinite(size)) { - drawSymbol(drawingCtx, dev, cex, pchVec.getDataAt(i % pchVec.getLength()), size, loc.x, loc.y); + pointDrawingCtx = drawSymbol(pointDrawingCtx, dev, cex, pchVec.getDataAt(i % pchVec.getLength()), size, loc.x, loc.y); } } return RNull.instance; @@ -85,38 +86,31 @@ public abstract class LPoints extends RExternalBuiltinNode.Arg4 { // transcribed from engine.c function GESymbol - private void drawSymbol(DrawingContext drawingCtx, GridDevice dev, double cex, int pch, double size, double x, double y) { + private PointDrawingContext drawSymbol(PointDrawingContext drawingCtx, GridDevice dev, double cex, int pch, double size, double x, double y) { // pch 0 - 25 are interpreted as geometrical shapes, pch from ascii code of ' ' are // interpreted as corresponding ascii character, which should be drawn switch (pch) { case 46: - drawDot(drawingCtx, dev, cex, x, y); - break; + return drawDot(drawingCtx, dev, cex, x, y); case 1: - drawOctahedron(drawingCtx, dev, GridColor.TRANSPARENT, size, x, y); - break; + return drawOctahedron(drawingCtx, dev, GridColor.TRANSPARENT, size, x, y); case 16: - drawOctahedron(drawingCtx, dev, drawingCtx.getColor(), size, x, y); - break; + return drawOctahedron(drawingCtx, dev, drawingCtx.getWrapped().getColor(), size, x, y); default: throw RInternalError.unimplemented("grid.points unimplemented symbol " + pch); } } - private static void drawOctahedron(DrawingContext drawingCtx, GridDevice dev, GridColor fill, double size, double x, double y) { - GridColor originalFill = drawingCtx.getFillColor(); - drawingCtx.setFillColor(fill); + private static PointDrawingContext drawOctahedron(PointDrawingContext drawingCtxIn, GridDevice dev, GridColor fill, double size, double x, double y) { + PointDrawingContext drawingCtx = drawingCtxIn.update(drawingCtxIn.getWrapped().getColor(), fill); dev.drawCircle(drawingCtx, x, y, RADIUS * size); - drawingCtx.setFillColor(originalFill); + return drawingCtx; } - private static void drawDot(DrawingContext drawingCtx, GridDevice dev, double cex, double x, double y) { + private static PointDrawingContext drawDot(PointDrawingContext drawingCtxIn, GridDevice dev, double cex, double x, double y) { // NOTE: we are *filling* a rect with the current colour (we are not drawing the border AND // we are not using the current fill colour) - GridColor originalFill = drawingCtx.getFillColor(); - drawingCtx.setFillColor(drawingCtx.getColor()); - drawingCtx.setColor(GridColor.TRANSPARENT); - + PointDrawingContext drawingCtx = drawingCtxIn.update(GridColor.TRANSPARENT, drawingCtxIn.getWrapped().getColor()); /* * The idea here is to use a 0.01" square, but to be of at least one device unit in each * direction, assuming that corresponds to pixels. That may be odd if pixels are not square, @@ -135,8 +129,57 @@ public abstract class LPoints extends RExternalBuiltinNode.Arg4 { yc = 0.5; } dev.drawRect(drawingCtx, x - xc, y - yc, x + xc, y + yc); + return drawingCtx; + } + + private static final class PointDrawingContext implements DrawingContext { + private final DrawingContext inner; + private final GridColor color; + private final GridColor fillColor; + + private PointDrawingContext(DrawingContext inner, GridColor color, GridColor fillColor) { + this.inner = inner; + this.color = color; + this.fillColor = fillColor; + } + + // This allows to re-use the existing instance if it would have the same parameters. The + // assumption is that the users will actually draw many points in a row with the same + // parameters. + private PointDrawingContext update(GridColor color, GridColor fillColor) { + if (this.color.equals(color) && this.fillColor.equals(fillColor)) { + return this; + } + return new PointDrawingContext(inner, color, fillColor); + } + + @Override + public GridLineType getLineType() { + return inner.getLineType(); + } - drawingCtx.setColor(drawingCtx.getFillColor()); - drawingCtx.setFillColor(originalFill); + @Override + public GridColor getColor() { + return color; + } + + @Override + public double getFontSize() { + return inner.getFontSize(); + } + + @Override + public double getLineHeight() { + return inner.getLineHeight(); + } + + @Override + public GridColor getFillColor() { + return fillColor; + } + + private DrawingContext getWrapped() { + return inner; + } } } diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/BufferedJFrameDevice.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/BufferedJFrameDevice.java new file mode 100644 index 0000000000000000000000000000000000000000..f85a04b4c446380eb41c4c2724692f4214e59215 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/BufferedJFrameDevice.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.library.fastrGrid.device; + +import java.awt.image.BufferStrategy; +import java.util.ArrayList; + +/** + * Decorator for {@link JFrameDevice} that implements {@link #hold()} and {@link #flush()}. Those + * methods open/draw a 2D graphics buffer, while the buffer is open, any drawing is done in the + * buffer not on the screen and we also record any drawing code to be able to replay it if the + * buffer happens to loose contents, which is a possibility mentioned in the documentation. Note: we + * rely on the fact that {@linkl DrawingContext} is immutable. + */ +public class BufferedJFrameDevice implements GridDevice { + private final JFrameDevice inner; + private BufferStrategy buffer; + private ArrayList<Runnable> drawActions; + + public BufferedJFrameDevice(JFrameDevice inner) { + this.inner = inner; + } + + @Override + public void openNewPage() { + inner.openNewPage(); + } + + @Override + public void hold() { + if (buffer != null) { + return; // already buffering + } + buffer = inner.getCurrentFrame().getBufferStrategy(); + if (buffer == null) { + inner.getCurrentFrame().createBufferStrategy(2); + buffer = inner.getCurrentFrame().getBufferStrategy(); + } + if (drawActions == null) { + drawActions = new ArrayList<>(); + } else { + drawActions.clear(); + } + inner.initGraphics(buffer.getDrawGraphics()); + } + + @Override + public void flush() { + if (buffer == null) { + return; + } + + buffer.show(); + // re-draw the buffer if the contents were lost + while (buffer.contentsLost()) { + inner.initGraphics(buffer.getDrawGraphics()); + for (Runnable drawAction : drawActions) { + drawAction.run(); + } + buffer.show(); + } + + inner.initGraphics(inner.getCurrentFrame().getGraphics()); + buffer.dispose(); + buffer = null; + } + + @Override + public void drawRect(DrawingContext ctx, double leftX, double topY, double width, double height) { + inner.drawRect(ctx, leftX, topY, width, height); + if (buffer != null) { + drawActions.add(() -> inner.drawRect(ctx, leftX, topY, width, height)); + } + } + + @Override + public void drawPolyLines(DrawingContext ctx, double[] x, double[] y, int startIndex, int length) { + inner.drawPolyLines(ctx, x, y, startIndex, length); + if (buffer != null) { + drawActions.add(() -> inner.drawPolyLines(ctx, x, y, startIndex, length)); + } + } + + @Override + public void drawCircle(DrawingContext ctx, double centerX, double centerY, double radius) { + inner.drawCircle(ctx, centerX, centerY, radius); + if (buffer != null) { + drawActions.add(() -> inner.drawCircle(ctx, centerX, centerY, radius)); + } + } + + @Override + public void drawString(DrawingContext ctx, double leftX, double bottomY, double rotationAnticlockWise, String text) { + inner.drawString(ctx, leftX, bottomY, rotationAnticlockWise, text); + if (buffer != null) { + drawActions.add(() -> inner.drawString(ctx, leftX, bottomY, rotationAnticlockWise, text)); + } + } + + @Override + public double getWidth() { + return inner.getWidth(); + } + + @Override + public double getHeight() { + return inner.getHeight(); + } + + @Override + public double getStringWidth(DrawingContext ctx, String text) { + return inner.getStringWidth(ctx, text); + } + + @Override + public double getStringHeight(DrawingContext ctx, String text) { + return inner.getStringHeight(ctx, text); + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/DrawingContext.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/DrawingContext.java index f3d42fa703d922981c033f164f3970438fc96131..b3baf6db3cbbc86c93dfafeca313c5b5e77b581f 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/DrawingContext.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/DrawingContext.java @@ -23,7 +23,8 @@ package com.oracle.truffle.r.library.fastrGrid.device; /** - * Defines parameters for drawing, like color, line style etc. + * Defines parameters for drawing, like color, line style etc. The implementations must be + * immutable. */ public interface DrawingContext { double INCH_TO_POINTS_FACTOR = 72.27; @@ -52,12 +53,10 @@ public interface DrawingContext { GridLineType getLineType(); - GridColor getColor(); - /** - * Alows to set the color drawing color of shape borders, lines and text. + * Drawing color of shape borders, lines and text. */ - void setColor(GridColor color); + GridColor getColor(); /** * Gets the font size in points. @@ -71,10 +70,8 @@ public interface DrawingContext { */ double getLineHeight(); - GridColor getFillColor(); - /** - * Alows to set the fill color of shapes. + * The fill color of shapes. */ - void setFillColor(GridColor color); + GridColor getFillColor(); } diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/DrawingContextDefaults.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/DrawingContextDefaults.java new file mode 100644 index 0000000000000000000000000000000000000000..b7043cbcd4d5266b066b79931aa0940fa78bdb0f --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/DrawingContextDefaults.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.library.fastrGrid.device; + +/** + * Allows the device to communicate the default values for its initial {@link DrawingContext}. The + * format of the values is the same as accepted by the {@code gpar()} function in R. + */ +public class DrawingContextDefaults { + public String fillColor = "transparent"; + public String color = "black"; +} 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 e4cdd7517aca69d5ef477e040ab81279f046e6b4..4b42cdce8cc4db3f9ff42e759f6a1f73a12f229c 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 @@ -55,4 +55,17 @@ public class GridColor { public int getAlpha() { return (value >> 24) & 0xff; } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof GridColor)) { + return false; + } + return value == ((GridColor) obj).value; + } + + @Override + public int hashCode() { + return value; + } } diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/GridDevice.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/GridDevice.java index 9e37a873bb46214d7035d2fefb13467cd7df174e..91593aebf66aa54f9ccfa66126d54cfc7eb74b67 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/GridDevice.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/GridDevice.java @@ -31,6 +31,21 @@ import static com.oracle.truffle.r.library.fastrGrid.device.DrawingContext.INCH_ public interface GridDevice { void openNewPage(); + /** + * If the device is capable of buffering, calling {@code hold} should start buffering, e.g. + * nothing is displayed on the device, until {@link #flush()} is called. + */ + default void hold() { + } + + /** + * Should display the whole buffer at once. + * + * @see #hold() + */ + default void flush() { + } + void drawRect(DrawingContext ctx, double leftX, double topY, double width, double height); /** @@ -58,12 +73,11 @@ public interface GridDevice { double getHeight(); /** - * May change the default values the of the initial drawing context instance. - * - * @param ctx instance of drawing context to be altered. + * May change the default values the of the initial drawing context instance. Must return + * non-null value. */ - default void initDrawingContext(DrawingContext ctx) { - // nop + default DrawingContextDefaults getDrawingContextDefaults() { + return new DrawingContextDefaults(); } double getStringWidth(DrawingContext ctx, String text); diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/JFrameDevice.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/JFrameDevice.java index 8821b8dd0f0d05d46e9d860e594b480aebe22065..2ac24f74a69f39b470acd028cf1724c54ef24a9d 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/JFrameDevice.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/JFrameDevice.java @@ -28,6 +28,7 @@ import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; +import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.HeadlessException; import java.awt.Paint; @@ -73,12 +74,7 @@ public class JFrameDevice implements GridDevice { if (currentFrame == null) { currentFrame = new FastRFrame(); currentFrame.setVisible(true); - graphics = (Graphics2D) currentFrame.getGraphics(); - graphics.translate(0, currentFrame.getHeight()); - graphics.scale(POINTS_IN_INCH, -POINTS_IN_INCH); - graphics.setStroke(new BasicStroke((float) (1d / POINTS_IN_INCH))); - graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - graphics.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); + initGraphics(currentFrame.getGraphics()); } else { noTranform(() -> { graphics.clearRect(0, 0, currentFrame.getWidth(), currentFrame.getHeight()); @@ -156,6 +152,22 @@ public class JFrameDevice implements GridDevice { }); } + FastRFrame getCurrentFrame() { + return currentFrame; + } + + void initGraphics(Graphics newGraphics) { + if (graphics != null) { + graphics.dispose(); + } + graphics = (Graphics2D) newGraphics; + graphics.translate(0, currentFrame.getHeight()); + graphics.scale(POINTS_IN_INCH, -POINTS_IN_INCH); + graphics.setStroke(new BasicStroke((float) (1d / POINTS_IN_INCH))); + graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + graphics.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); + } + private void drawShape(DrawingContext drawingCtx, Shape shape) { Paint paint = graphics.getPaint(); graphics.setPaint(fromGridColor(drawingCtx.getFillColor())); @@ -223,7 +235,7 @@ public class JFrameDevice implements GridDevice { longdashedStroke = new BasicStroke(defaultWidth, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10f, new float[]{2f * dashSize}, 0f); } - private static class FastRFrame extends JFrame { + static class FastRFrame extends JFrame { private static final long serialVersionUID = 1L; private final Dimension framePreferredSize = new Dimension(720, 720); private final JPanel fastRComponent = new JPanel(); diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/DevHoldFlush.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/DevHoldFlush.java new file mode 100644 index 0000000000000000000000000000000000000000..853f82bcf3b07e76bb14ff163b5c5ce2c2e811cd --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/DevHoldFlush.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.library.fastrGrid.grDevices; + +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.r.library.fastrGrid.GridContext; +import com.oracle.truffle.r.library.fastrGrid.GridState; +import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; + +public abstract class DevHoldFlush extends RExternalBuiltinNode.Arg1 { + static { + Casts casts = new Casts(DevHoldFlush.class); + casts.arg(0).mustBe(numericValue()).asIntegerVector().findFirst(); + } + + public static DevHoldFlush create() { + return DevHoldFlushNodeGen.create(); + } + + @Specialization + @TruffleBoundary + int doInteger(int num) { + GridState gridState = GridContext.getContext().getGridState(); + int result = gridState.getDevHoldCount(); + if (num < 0) { + result = gridState.setDevHoldCount(Math.max(0, result + num)); + if (result == 0) { + GridContext.getContext().getCurrentDevice().flush(); + } + } else if (num > 0) { + if (result == 0) { + GridContext.getContext().getCurrentDevice().hold(); + } + result = gridState.setDevHoldCount(result + num); + } + return result; + } +}