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 daea6bc6818c09f22a3cffa04a728973c4ade270..1f297581c409dd3eb1c7e4bf0c1f3cf691fefcd5 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
@@ -25,6 +25,7 @@ package com.oracle.truffle.r.library.fastrGrid;
 import com.oracle.truffle.r.library.fastrGrid.DisplayList.LGetDisplayListElement;
 import com.oracle.truffle.r.library.fastrGrid.DisplayList.LInitDisplayList;
 import com.oracle.truffle.r.library.fastrGrid.DisplayList.LSetDisplayListOn;
+import com.oracle.truffle.r.library.fastrGrid.grDevices.DevCairo;
 import com.oracle.truffle.r.library.fastrGrid.grDevices.DevCurr;
 import com.oracle.truffle.r.library.fastrGrid.grDevices.DevHoldFlush;
 import com.oracle.truffle.r.library.fastrGrid.grDevices.DevOff;
@@ -59,6 +60,8 @@ public final class FastRGridExternalLookup {
                 return DevOff.create();
             case "PDF":
                 return new IgnoredGridExternal(RNull.instance);
+            case "devCairo":
+                return new DevCairo();
             default:
                 return null;
         }
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 f00b510ec41d04dc1eb86bce7076a6c0e8cb5ee8..10f8a4d797edbf09fda291719df551e85554a539 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
@@ -100,6 +100,10 @@ public final class GridContext {
     public void closeDevice(int which) throws DeviceCloseException {
         assert which >= 0 && which < devices.size();
         devices.get(which).device.close();
+        removeDevice(which);
+    }
+
+    public void removeDevice(int which) {
         RGridGraphicsAdapter.removeDevice(which);
         devices.remove(which);
         if (currentDeviceIdx >= which) {
@@ -107,6 +111,10 @@ public final class GridContext {
         }
     }
 
+    public GridDevice getDevice(int index) {
+        return devices.get(index).device;
+    }
+
     /**
      * Runs arbitrary function from 'fastrGrid.R' file and returns its result.
      */
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 2986d9ffba8f4133eafbfc4dc56672905d80965f..dcfb747b4f7be4595bc795e2b31b08c1fd74d353 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
@@ -53,6 +53,14 @@ public interface DrawingContext {
             assert num > 0 && num <= SYMBOL.ordinal() + 1;
             return values()[num - 1];
         }
+
+        public boolean isBold() {
+            return this == BOLD || this == BOLDITALIC;
+        }
+
+        public boolean isItalic() {
+            return this == ITALIC || this == BOLDITALIC;
+        }
     }
 
     enum GridLineJoin {
@@ -132,7 +140,8 @@ public interface DrawingContext {
     String getFontFamily();
 
     /**
-     * Gets the height of a line in multiplies of the base line height.
+     * Gets the height of a text line in multiplies of the base line height. This is typically not a
+     * concern of devices, since they always receive single line strings for drawing.
      */
     double getLineHeight();
 
@@ -140,4 +149,18 @@ public interface DrawingContext {
      * The fill color of shapes.
      */
     GridColor getFillColor();
+
+    static boolean areSame(DrawingContext ctx1, DrawingContext ctx2) {
+        return ctx1 == ctx2 || (ctx1.getColor().equals(ctx2.getColor()) &&
+                        ctx1.getLineEnd() == ctx2.getLineEnd() &&
+                        ctx1.getLineJoin() == ctx2.getLineJoin() &&
+                        ctx1.getLineType() == ctx2.getLineType() &&
+                        ctx1.getLineHeight() == ctx2.getLineHeight() &&
+                        ctx1.getFontStyle() == ctx2.getFontStyle() &&
+                        ctx1.getFontSize() == ctx2.getFontSize() &&
+                        ctx1.getFontFamily().equals(ctx2.getFontFamily()) &&
+                        ctx1.getLineWidth() == ctx2.getLineWidth() &&
+                        ctx1.getLineMitre() == ctx2.getLineMitre() &&
+                        ctx1.getFillColor().equals(ctx2.getFillColor()));
+    }
 }
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 2ea6e4468e66e623d119819c643716f1ae1541a8..0515ded9b5bf94c49d13a8092c7063d0fbaee6bf 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
@@ -81,7 +81,7 @@ public interface GridDevice {
     void drawCircle(DrawingContext ctx, double centerX, double centerY, double radius);
 
     /**
-     * Prints a string with left bottom corner at given position rotates by given angle anti clock
+     * Prints a string with left bottom corner at given position rotated by given angle anti clock
      * wise, the centre of the rotation should be the bottom left corer.
      */
     void drawString(DrawingContext ctx, double leftX, double bottomY, double rotationAnticlockWise, String text);
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
new file mode 100644
index 0000000000000000000000000000000000000000..702a586e3c65000cf14534ba168f8908c0064c73
--- /dev/null
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/SVGDevice.java
@@ -0,0 +1,267 @@
+/*
+ * 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 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 java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.text.DecimalFormat;
+import java.util.Collections;
+
+import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext.GridFontStyle;
+import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext.GridLineEnd;
+import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext.GridLineJoin;
+import com.oracle.truffle.r.runtime.RInternalError;
+
+public class SVGDevice implements GridDevice {
+    private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.000");
+    private final StringBuilder data = new StringBuilder(1024);
+    private final String filename;
+    private final double width;
+    private final double height;
+
+    private DrawingContext cachedCtx;
+
+    public SVGDevice(String filename, double width, double height) {
+        this.filename = filename;
+        this.width = width;
+        this.height = height;
+    }
+
+    public String getContents() {
+        return data.toString();
+    }
+
+    @Override
+    public void openNewPage() {
+        // We stay compatible with GnuR: opening new page wipes out what has been drawn without
+        // saving it anywhere.
+        data.setLength(0);
+        cachedCtx = null;
+        append("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">");
+        // we could use real inches, but that makes the output different to GnuR and other formats
+        // (jpg, ...), which use conversion 70px ~ 1in
+        append("<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' version='1.1' width='%.3fpx' height='%.3fpx' viewBox='0 0 %.3f %.3f'>", width * 70d, height * 70d,
+                        width,
+                        height);
+    }
+
+    @Override
+    public void close() throws DeviceCloseException {
+        if (cachedCtx != null) {
+            // see #appendStyle
+            append("</g>");
+        }
+        append("</svg>");
+        try {
+            Files.write(Paths.get(filename), Collections.singleton(data.toString()), StandardCharsets.UTF_8);
+        } catch (IOException e) {
+            throw new DeviceCloseException(e);
+        }
+    }
+
+    @Override
+    public void drawRect(DrawingContext ctx, double leftX, double bottomY, double width, double height, double rotationAnticlockWise) {
+        appendStyle(ctx);
+        append("<rect vector-effect='non-scaling-stroke' x='%.3f' y='%.3f' width='%.3f' height='%.3f'", leftX, transY(bottomY + height), width, height);
+        if (rotationAnticlockWise != 0) {
+            append("transform='rotate(%.3f %.3f,%.3f)'", toDegrees(rotationAnticlockWise), (leftX + width / 2.), transY(bottomY + height / 2.));
+        }
+        data.append("/>"); // end of 'rect' tag
+    }
+
+    @Override
+    public void drawPolyLines(DrawingContext ctx, double[] x, double[] y, int startIndex, int length) {
+        drawPoly(ctx, x, y, startIndex, length, "style='fill:transparent'");
+    }
+
+    @Override
+    public void drawPolygon(DrawingContext ctx, double[] x, double[] y, int startIndex, int length) {
+        drawPoly(ctx, x, y, startIndex, length, "");
+    }
+
+    @Override
+    public void drawCircle(DrawingContext ctx, double centerX, double centerY, double radius) {
+        appendStyle(ctx);
+        append("<circle vector-effect='non-scaling-stroke' cx='%.3f' cy='%.3f' r='%.3f'/>", centerX, transY(centerY), radius);
+    }
+
+    @Override
+    public void drawString(DrawingContext ctx, double leftX, double bottomY, double rotationAnticlockWise, String text) {
+        appendStyle(ctx);
+        append("<text x='%.3f' y='%.3f' textLength='%.3f' lengthAdjust='spacingAndGlyphs' ", leftX, transY(bottomY), getStringWidth(ctx, text));
+        // SVG interprets the "fill" as the color of the text
+        data.append("style='").append(getStyleColor("fill", ctx.getColor())).append(";stroke:transparent'");
+        if (rotationAnticlockWise != 0) {
+            append(" transform='rotate(%.3f %.3f,%.3f)'", toDegrees(rotationAnticlockWise), leftX, transY(bottomY));
+        }
+        data.append(">").append(text).append("</text>");
+    }
+
+    @Override
+    public double getWidth() {
+        return width;
+    }
+
+    @Override
+    public double getHeight() {
+        return height;
+    }
+
+    @Override
+    public double getStringWidth(DrawingContext ctx, String text) {
+        // The architecture of the GridDevice and grid package requires the devices be able to
+        // calculate the width of given string, this way one can e.g. create a box around text. SVG
+        // supports this by means of "textLength" attribute, which allows us to force text to have
+        // specified width. So we approximate the width of given text in the calculation below and
+        // then force the text to actually have such width if it ever gets displayed by #drawString.
+        double factor = 0.5;    // empirically chosen
+        if (ctx.getFontStyle() == GridFontStyle.BOLD || ctx.getFontStyle() == GridFontStyle.BOLDITALIC) {
+            factor = 0.62;
+        }
+        double letterWidth = (ctx.getFontSize() / INCH_TO_POINTS_FACTOR);
+        double result = factor * (double) text.length() * letterWidth;
+        for (int i = 0; i < text.length(); i++) {
+            char c = text.charAt(i);
+            if (c == 'w' || c == 'm') {
+                result += letterWidth * 0.2;
+            } else if (c == 'z') {
+                result += letterWidth * 0.1;
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public double getStringHeight(DrawingContext ctx, String text) {
+        // we need height without ascent/descent of letters that are not in the string, this is
+        // empirically tested calculation
+        return 0.8 * (ctx.getFontSize() / INCH_TO_POINTS_FACTOR);
+    }
+
+    private void drawPoly(DrawingContext ctx, double[] x, double[] y, int startIndex, int length, String attributes) {
+        appendStyle(ctx);
+        data.append("<polyline vector-effect='non-scaling-stroke' points='");
+        for (int i = 0; i < length; i++) {
+            data.append(DECIMAL_FORMAT.format(x[i + startIndex]));
+            data.append(',');
+            data.append(DECIMAL_FORMAT.format(transY(y[i + startIndex])));
+            data.append(' ');
+        }
+        data.append("' ").append(attributes).append(" />");
+    }
+
+    private void appendStyle(DrawingContext ctx) {
+        if (cachedCtx == null || !DrawingContext.areSame(cachedCtx, ctx)) {
+            if (cachedCtx != null) {
+                append("</g>"); // close the previous style definition
+            }
+            append("<g style='");
+            appendStyleUncached(ctx);
+            append("'>");
+        }
+        cachedCtx = ctx;
+    }
+
+    private void appendStyleUncached(DrawingContext ctx) {
+        byte[] lineType = ctx.getLineType();
+        if (lineType == GRID_LINE_BLANK) {
+            append("stroke:transparent");
+        } else {
+            append(getStyleColor("stroke", ctx.getColor()));
+        }
+        data.append(';').append(getStyleColor("fill", ctx.getFillColor()));
+        data.append(";stroke-width:").append(ctx.getLineWidth());
+        if (lineType != DrawingContext.GRID_LINE_SOLID && lineType != DrawingContext.GRID_LINE_BLANK) {
+            data.append(";stroke-dasharray:");
+            for (int i = 0; i < lineType.length; i++) {
+                data.append(lineType[i]);
+                if (i != lineType.length - 1) {
+                    data.append(',');
+                }
+            }
+        }
+        data.append(";stroke-linejoin:").append(getSVGLineJoin(ctx.getLineJoin()));
+        data.append(";stroke-linecap:").append(getSVGLineCap(ctx.getLineEnd()));
+        if (ctx.getLineJoin() == GridLineJoin.MITRE) {
+            data.append(";stroke-miterlimit:").append(ctx.getLineMitre());
+        }
+        data.append(";font-size:").append(ctx.getFontSize() / INCH_TO_POINTS_FACTOR).append("px");
+        if (!ctx.getFontFamily().isEmpty()) {
+            // Font-family strings 'mono', 'sans', and 'serif' are OK for us
+            data.append(";font-family:").append(ctx.getFontFamily());
+        }
+        if (ctx.getFontStyle().isBold()) {
+            data.append(";font-weight:bold");
+        }
+        if (ctx.getFontStyle().isItalic()) {
+            data.append(";font-style:italic");
+        }
+    }
+
+    private static String getSVGLineCap(GridLineEnd lineEnd) {
+        switch (lineEnd) {
+            case ROUND:
+                return "round";
+            case BUTT:
+                return "butt";
+            case SQUARE:
+                return "square";
+            default:
+                throw RInternalError.shouldNotReachHere("Unexpected value of GridLineEnd enum.");
+        }
+    }
+
+    private static String getSVGLineJoin(GridLineJoin lineJoin) {
+        switch (lineJoin) {
+            case ROUND:
+                return "round";
+            case MITRE:
+                return "miter";
+            case BEVEL:
+                return "bevel";
+            default:
+                throw RInternalError.shouldNotReachHere("Unexpected value of GridLineJoin enum.");
+        }
+    }
+
+    private static String getStyleColor(String prefix, GridColor color) {
+        return String.format("%s:rgb(%d,%d,%d);%s-opacity:%.3f", prefix, color.getRed(), color.getGreen(), color.getBlue(), prefix, (double) color.getAlpha() / 255d);
+    }
+
+    private void append(String fmt, Object... args) {
+        data.append(String.format(fmt + "\n", args));
+    }
+
+    private double transY(double y) {
+        return (height - y);
+    }
+
+    private static double toDegrees(double rotationAnticlockWise) {
+        return (180. / Math.PI) * -rotationAnticlockWise;
+    }
+}
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/DevCairo.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/DevCairo.java
new file mode 100644
index 0000000000000000000000000000000000000000..6ae4427041d6d613254cd87fdb1f0ba971e8d5ad
--- /dev/null
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/DevCairo.java
@@ -0,0 +1,54 @@
+/*
+ * 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 com.oracle.truffle.r.library.fastrGrid.GridContext;
+import com.oracle.truffle.r.library.fastrGrid.device.SVGDevice;
+import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
+import com.oracle.truffle.r.runtime.RError.Message;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
+import com.oracle.truffle.r.runtime.data.RNull;
+
+public class DevCairo extends RExternalBuiltinNode {
+    static {
+        Casts.noCasts(DevCairo.class);
+    }
+
+    @Override
+    protected Object call(RArgsValuesAndNames args) {
+        if (args.getLength() < 4) {
+            throw error(Message.ARGUMENTS_REQUIRED_COUNT, args.getLength(), "devCairo", 4);
+        }
+
+        String filename = RRuntime.asString(args.getArgument(0));
+        int witdh = RRuntime.asInteger(args.getArgument(2));
+        int height = RRuntime.asInteger(args.getArgument(2));
+        if (RRuntime.isNA(witdh) || RRuntime.isNA(height) || RRuntime.isNA(filename) || filename.isEmpty()) {
+            throw error(Message.INVALID_ARG_TYPE);
+        }
+
+        GridContext.getContext().setCurrentDevice("svg", new SVGDevice(filename, (double) witdh / 72., (double) height / 72.));
+        return RNull.instance;
+    }
+}
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/DevOff.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/DevOff.java
index e0d57b606a07af5bb4a1a457f0c0a90d5d50dffe..87f99d3561440d6dfad00f35ca162e63d7daa7b0 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/DevOff.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/DevOff.java
@@ -25,7 +25,9 @@ package com.oracle.truffle.r.library.fastrGrid.grDevices;
 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.device.GridDevice;
 import com.oracle.truffle.r.library.fastrGrid.device.GridDevice.DeviceCloseException;
+import com.oracle.truffle.r.library.fastrGrid.device.SVGDevice;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -45,10 +47,17 @@ public abstract class DevOff extends RExternalBuiltinNode.Arg1 {
     @TruffleBoundary
     public Object devOff(int whichR) {
         GridContext ctx = GridContext.getContext();
-        int which = whichR - 1; // convert to Java index
+        int which = Math.abs(whichR) - 1; // convert to Java index
         if (which < 0 || which >= ctx.getDevicesSize()) {
             throw RError.error(RError.NO_CALLER, Message.GENERIC, "Wrong device number.");
         }
+
+        // FastR specific special handling for SVG device, when the index is negative, return the
+        // SVG code
+        if (whichR < 0) {
+            return closeSvgDevice(ctx, which);
+        }
+
         try {
             ctx.closeDevice(which);
         } catch (DeviceCloseException e) {
@@ -56,4 +65,15 @@ public abstract class DevOff extends RExternalBuiltinNode.Arg1 {
         }
         return RNull.instance;
     }
+
+    private String closeSvgDevice(GridContext ctx, int which) {
+        GridDevice dev = ctx.getDevice(which);
+        ctx.removeDevice(which);
+        if ((dev instanceof SVGDevice)) {
+            return ((SVGDevice) dev).getContents();
+        } else {
+            warning(Message.GENERIC, "The device was not SVG device.");
+            return "";
+        }
+    }
 }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/R/fastrGridDevices.R b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/R/fastrGridDevices.R
index 2e551b4a1a6ea52155d5066ce195421440c700ed..aad9c69ae671c971c18b81e89920be6f54cc66b5 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/R/fastrGridDevices.R
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/R/fastrGridDevices.R
@@ -27,6 +27,14 @@ eval(expression({
     awt <- function(width = NULL, height = NULL, graphicsObj = NULL) {
         .External2(grDevices:::C_X11, ".FASTR.AWT", width, height, graphicsObj)
     }
+    # Allows to get the SVG code from SVG device, it also closes the device,
+    # but the contents are not saved to the given file.
+    svg.off <- function(which = dev.cur()) {
+        if (which == 1) {
+            stop("cannot shut down device 1 (the null device)")
+        }
+        .External(C_devoff, as.integer(-which))
+    }
     # GnuR version only works with "X11cairo" device. Our version of savePlot
     # works with "awt" device and "X11cairo", which is for us only alias for
     # "awt". Moreover, we only support formats that awt supports.