From dd9691ddb81998fcffd324f895483e4327dad4a5 Mon Sep 17 00:00:00 2001 From: stepan <stepan.sindelar@oracle.com> Date: Thu, 23 Mar 2017 17:13:27 +0100 Subject: [PATCH] FastR Grid: support gpar containing vectors --- .../r/library/fastrGrid/DoSetViewPort.java | 40 ++++---- .../r/library/fastrGrid/DrawArrowsNode.java | 2 +- .../truffle/r/library/fastrGrid/GPar.java | 91 ++++++++++++++----- .../r/library/fastrGrid/GridLinesNode.java | 8 +- .../r/library/fastrGrid/GridState.java | 9 +- .../r/library/fastrGrid/GridTextNode.java | 8 +- .../r/library/fastrGrid/GridUtils.java | 13 +++ .../truffle/r/library/fastrGrid/LCircle.java | 7 +- .../truffle/r/library/fastrGrid/LConvert.java | 7 +- .../library/fastrGrid/LInitViewPortStack.java | 1 - .../truffle/r/library/fastrGrid/LPoints.java | 19 +++- .../truffle/r/library/fastrGrid/LRect.java | 7 +- .../r/library/fastrGrid/LSegments.java | 7 +- .../truffle/r/library/fastrGrid/Unit.java | 26 +++--- .../device/BufferedJFrameDevice.java | 2 +- .../r/library/fastrGrid/device/GridColor.java | 5 +- 16 files changed, 155 insertions(+), 97 deletions(-) diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPort.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPort.java index 591c4e25f4..3154017025 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPort.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPort.java @@ -29,7 +29,6 @@ import com.oracle.truffle.r.library.fastrGrid.Unit.IsRelativeUnitNode; import com.oracle.truffle.r.library.fastrGrid.Unit.UnitConversionContext; import com.oracle.truffle.r.library.fastrGrid.ViewPort.LayoutPos; import com.oracle.truffle.r.library.fastrGrid.ViewPort.LayoutSize; -import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext; import com.oracle.truffle.r.library.fastrGrid.device.GridDevice; import com.oracle.truffle.r.nodes.unary.CastNode; import com.oracle.truffle.r.runtime.RError.Message; @@ -65,11 +64,11 @@ class DoSetViewPort extends RBaseNode { } GridDevice currentDevice = GridContext.getContext().getCurrentDevice(); - DrawingContext deviceDrawingContext = GridState.getInitialGPar(currentDevice); + GPar gpar = GridState.getInitialGPar(currentDevice); RList parent = asListOrNull(pushedViewPort.getDataAt(ViewPort.PVP_PARENT)); boolean doNotRecalculateParent = hasParent && !ViewPort.updateDeviceSizeInVP(parent, currentDevice); - calcViewportTransform(pushedViewPort, parent, doNotRecalculateParent, currentDevice, deviceDrawingContext); + calcViewportTransform(pushedViewPort, parent, doNotRecalculateParent, currentDevice, gpar); // TODO: clipping pushedVPData[ViewPort.PVP_CLIPRECT] = RDataFactory.createDoubleVector(new double[]{0, 0, 0, 0}, RDataFactory.COMPLETE_VECTOR); @@ -87,37 +86,37 @@ class DoSetViewPort extends RBaseNode { * @param incremental If {@code true} it is assumed that we can just take the transformation * matrix and other values from the parent without re-calculating them recursively. * @param device This method needs the device in order to convert units - * @param deviceDrawingContext This method needs to know the device default drawing context in + * @param deviceTopLevelGpar This method needs to know the device default drawing context in * order to convert units for the top level view port */ @TruffleBoundary - public void calcViewportTransform(RList viewPort, Object parent, boolean incremental, GridDevice device, DrawingContext deviceDrawingContext) { + public void calcViewportTransform(RList viewPort, Object parent, boolean incremental, GridDevice device, GPar deviceTopLevelGpar) { double[][] parentTransform; ViewPortContext parentContext; ViewPortLocation vpl; Size parentSize; - DrawingContext drawingContext; + GPar drawingContext; double parentAngle; if (parent == null || parent == RNull.instance) { parentTransform = TransformMatrix.identity(); parentContext = ViewPortContext.createDefault(); parentSize = new Size(device.getWidth(), device.getHeight()); vpl = ViewPortLocation.fromViewPort(viewPort); - drawingContext = deviceDrawingContext; + drawingContext = deviceTopLevelGpar; parentAngle = 0; } else { assert parent instanceof RList : "inconsistent data: parent of a viewport must be a list"; RList parentVPList = (RList) parent; Object[] parentData = parentVPList.getDataWithoutCopying(); if (!incremental) { - calcViewportTransform(parentVPList, parentData[ViewPort.PVP_PARENT], false, device, deviceDrawingContext); + calcViewportTransform(parentVPList, parentData[ViewPort.PVP_PARENT], false, device, deviceTopLevelGpar); } parentSize = new Size(Unit.cmToInches(castScalar(parentData[ViewPort.PVP_WIDTHCM])), Unit.cmToInches(castScalar(parentData[ViewPort.PVP_HEIGHTCM]))); parentTransform = fromFlat(castDoubleVector(parentData[ViewPort.PVP_TRANS]).materialize().getDataWithoutCopying()); parentContext = ViewPortContext.fromViewPort(parentVPList); parentAngle = asDouble(parentData[ViewPort.PVP_ROTATION]); - drawingContext = GPar.asDrawingContext(asList(viewPort.getDataAt(ViewPort.PVP_PARENTGPAR))); + drawingContext = GPar.create(asList(viewPort.getDataAt(ViewPort.PVP_PARENTGPAR))); boolean noLayout = (isNull(viewPort.getDataAt(ViewPort.VP_VALIDLPOSROW)) && isNull(viewPort.getDataAt(ViewPort.VP_VALIDLPOSCOL))) || isNull(parentData[ViewPort.VP_LAYOUT]); if (noLayout) { vpl = ViewPortLocation.fromViewPort(viewPort); @@ -157,8 +156,7 @@ class DoSetViewPort extends RBaseNode { // Finally, allocate the rows and columns for this viewport's layout if it has one if (!isNull(viewPort.getDataAt(ViewPort.VP_LAYOUT))) { ViewPortContext vpCtx = ViewPortContext.fromViewPort(viewPort); - DrawingContext drawingCtx = GPar.asDrawingContext(asList(viewPort.getDataAt(ViewPort.PVP_GPAR))); - calcViewPortLayout(viewPort, new Size(width, height), vpCtx, device, drawingCtx); + calcViewPortLayout(viewPort, new Size(width, height), vpCtx, device, GPar.create(asList(viewPort.getDataAt(ViewPort.PVP_GPAR)))); } Object[] viewPortData = viewPort.getDataWithoutCopying(); @@ -168,13 +166,13 @@ class DoSetViewPort extends RBaseNode { viewPortData[ViewPort.PVP_TRANS] = RDataFactory.createDoubleVector(flatten(transform), RDataFactory.COMPLETE_VECTOR, new int[]{3, 3}); } - private void calcViewPortLayout(RList viewPort, Size size, ViewPortContext parentVPCtx, GridDevice device, DrawingContext drawingCtx) { + private void calcViewPortLayout(RList viewPort, Size size, ViewPortContext parentVPCtx, GridDevice device, GPar gpar) { LayoutSize layoutSize = LayoutSize.fromViewPort(viewPort); double[] npcWidths = new double[layoutSize.ncol]; double[] npcHeights = new double[layoutSize.nrow]; boolean[] relativeWidths = new boolean[layoutSize.ncol]; boolean[] relativeHeights = new boolean[layoutSize.nrow]; - UnitConversionContext conversionCtx = new UnitConversionContext(size, parentVPCtx, device, drawingCtx); + UnitConversionContext conversionCtx = new UnitConversionContext(size, parentVPCtx, device, gpar); // For both dimensions we find out which units are other than "null" for those we can // immediately calculate the physical size in npcWidth/npcHeights. The reducedWidth/Height @@ -195,8 +193,8 @@ class DoSetViewPort extends RBaseNode { int respect = RRuntime.asInteger(layoutAsList.getDataAt(ViewPort.LAYOUT_VRESPECT)); int[] layoutRespectMat = ((RAbstractIntVector) layoutAsList.getDataAt(ViewPort.LAYOUT_MRESPECT)).materialize().getDataWithoutCopying(); if ((reducedHeight > 0 || reducedWidth > 0) && respect > 0) { - double sumRelWidth = sumRelativeDimension(layoutWidths, relativeWidths, parentVPCtx, device, drawingCtx, true); - double sumRelHeight = sumRelativeDimension(layoutHeights, relativeHeights, parentVPCtx, device, drawingCtx, false); + double sumRelWidth = sumRelativeDimension(layoutWidths, relativeWidths, parentVPCtx, device, gpar, true); + double sumRelHeight = sumRelativeDimension(layoutHeights, relativeHeights, parentVPCtx, device, gpar, false); double tempWidth = reducedWidth; double tempHeight = reducedHeight; double denom; @@ -250,8 +248,8 @@ class DoSetViewPort extends RBaseNode { } // Secondly, allocate remaining relative widths and heights in the remaining space - allocateRelativeDim(layoutSize, layoutWidths, npcWidths, relativeWidths, reducedWidth, respect, layoutRespectMat, device, drawingCtx, parentVPCtx, true); - allocateRelativeDim(layoutSize, layoutHeights, npcHeights, relativeHeights, reducedHeight, respect, layoutRespectMat, device, drawingCtx, parentVPCtx, false); + allocateRelativeDim(layoutSize, layoutWidths, npcWidths, relativeWidths, reducedWidth, respect, layoutRespectMat, device, gpar, parentVPCtx, true); + allocateRelativeDim(layoutSize, layoutHeights, npcHeights, relativeHeights, reducedHeight, respect, layoutRespectMat, device, gpar, parentVPCtx, false); // Create the result Object[] vpData = viewPort.getDataWithoutCopying(); @@ -260,9 +258,9 @@ class DoSetViewPort extends RBaseNode { } private void allocateRelativeDim(LayoutSize layoutSize, RAbstractContainer layoutItems, double[] npcItems, boolean[] relativeItems, double reducedDim, int respect, int[] layoutRespectMat, - GridDevice device, DrawingContext drawingCtx, ViewPortContext parentVPCtx, boolean isWidth) { + GridDevice device, GPar gpar, ViewPortContext parentVPCtx, boolean isWidth) { assert relativeItems.length == npcItems.length; - UnitConversionContext layoutModeCtx = new UnitConversionContext(new Size(0, 0), parentVPCtx, device, drawingCtx, 1, 0); + UnitConversionContext layoutModeCtx = new UnitConversionContext(new Size(0, 0), parentVPCtx, device, gpar, 1, 0); double totalUnrespectedSize = 0; if (reducedDim > 0) { for (int i = 0; i < relativeItems.length; i++) { @@ -311,9 +309,9 @@ class DoSetViewPort extends RBaseNode { return false; } - private double sumRelativeDimension(RAbstractContainer layoutItems, boolean[] relativeItems, ViewPortContext parentVPCtx, GridDevice device, DrawingContext drawingCtx, + private double sumRelativeDimension(RAbstractContainer layoutItems, boolean[] relativeItems, ViewPortContext parentVPCtx, GridDevice device, GPar gpar, boolean isWidth) { - UnitConversionContext layoutModeCtx = new UnitConversionContext(new Size(0, 0), parentVPCtx, device, drawingCtx, 1, 0); + UnitConversionContext layoutModeCtx = new UnitConversionContext(new Size(0, 0), parentVPCtx, device, gpar, 1, 0); double totalWidth = 0; for (int i = 0; i < relativeItems.length; i++) { if (relativeItems[i]) { diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DrawArrowsNode.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DrawArrowsNode.java index e177c722b1..cda58b06a3 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DrawArrowsNode.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DrawArrowsNode.java @@ -66,7 +66,7 @@ class DrawArrowsNode extends Node { arrowLength = Math.max(arrowLength, unitToInches.convertWidth(lengthVec, parentIndex, conversionCtx)); // draw the arrows GridDevice device = conversionCtx.device; - DrawingContext drawingCtx = conversionCtx.drawingContext; + DrawingContext drawingCtx = conversionCtx.gpar.getDrawingContext(parentIndex); if (first && start) { drawArrow(drawingCtx, device, arrowType, x[startIndex], y[startIndex], x[startIndex + 1], y[startIndex + 1], angle, arrowLength); } 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 be7d76d5f9..16288015d9 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 @@ -13,6 +13,7 @@ package com.oracle.truffle.r.library.fastrGrid; import static com.oracle.truffle.r.library.fastrGrid.GridUtils.asAbstractContainer; import static com.oracle.truffle.r.library.fastrGrid.GridUtils.asDouble; +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.getDataAtMod; import java.util.Arrays; @@ -30,10 +31,20 @@ import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; /** * In the context of grid package, GPar is a list that contains the parameters for the drawing, like - * line style, color, etc. This class wraps the list and provides type-safe access to its elements. + * line style, color, etc. This class wraps the list and provides way to convert it to + * {@link DrawingContext}. First create instance of {@link GPar} and then use + * {@link #getDrawingContext(int)} to get the drawing context. Note that grid's gpar can + * theoretically contain vector as the value of some graphical parameters, in such case, when + * drawing i-th element, e.g. i-th rectangle in {@link LRect}, we should use i-th (mod length) + * element of such vector. Note that this is sort of ignored in layout calculations, where we always + * take the first element. In other words, instance of {@link GPar} represents grid's gpar where the + * graphical parameter may be vectors, whereas {@link DrawingContext} is flattened view where it is + * already determined which index is used to access the vectors. */ public final class GPar { private static final int GP_FILL = 0; @@ -86,6 +97,40 @@ public final class GPar { "fontface" }; private static final RStringVector NAMES_VECTOR = (RStringVector) RDataFactory.createStringVector(NAMES, RDataFactory.COMPLETE_VECTOR).makeSharedPermanent(); + private final RList gpar; + // majority of gpar instances contains only scalar values, for those we make sure we do not + // create a new drawing context instance for every index. + private final boolean singleDrawingCtx; + private DrawingContext indexZeroDrawingCtx; + + public GPar(RList gpar, boolean singleDrawingCtx) { + this.gpar = gpar; + this.gpar.makeSharedPermanent(); + this.singleDrawingCtx = singleDrawingCtx; + indexZeroDrawingCtx = new GParDrawingContext(gpar, 0); + } + + public static double getCex(RList gpar) { + return asDouble(gpar.getDataAt(GP_CEX)); + } + + public static GPar create(RList gpar) { + boolean singleDrawingCtx = true; + for (int i = 0; i < gpar.getLength(); i++) { + Object item = gpar.getDataAt(i); + if (item instanceof RAbstractVector) { + singleDrawingCtx &= ((RAbstractVector) item).getLength() == 1; + } + } + return new GPar(gpar, singleDrawingCtx); + } + + public DrawingContext getDrawingContext(int cyclicIndex) { + if (singleDrawingCtx || cyclicIndex == 0) { + return indexZeroDrawingCtx; + } + return new GParDrawingContext(gpar, cyclicIndex); + } public static RList createNew(GridDevice device) { Object[] data = new Object[GP_LENGTH]; @@ -111,24 +156,17 @@ public final class GPar { return result; } - public static double getCex(RList gpar) { - return asDouble(gpar.getDataAt(GP_CEX)); - } - - public static DrawingContext asDrawingContext(RList gpar) { - return new GParDrawingContext(gpar); - } - private static RAbstractDoubleVector newDoubleVec(double val) { return RDataFactory.createDoubleVectorFromScalar(val); } private static final class GParDrawingContext implements DrawingContext { private final Object[] data; + private final int index; - private GParDrawingContext(RList list) { + private GParDrawingContext(RList list, int index) { data = list.getDataWithoutCopying(); - list.makeSharedPermanent(); + this.index = index; } @Override @@ -137,24 +175,27 @@ public final class GPar { if (lty == null || lty == RNull.instance) { return DrawingContext.GRID_LINE_SOLID; } - String name = RRuntime.asString(lty); - if (name != null) { - return lineTypeFromName(name); + // convert string values + if (lty instanceof String || lty instanceof RAbstractStringVector) { + String name = GridUtils.asString(lty, index); + if (name != null) { + return lineTypeFromName(name); + } } + // convert numeric values RAbstractContainer ltyVec = asAbstractContainer(lty); - int num; + int num; // NA will indicate error if (ltyVec.getLength() == 0) { num = RRuntime.INT_NA; } else if (ltyVec instanceof RAbstractDoubleVector) { - double realVal = ((RAbstractDoubleVector) ltyVec).getDataAt(0); + double realVal = getDataAtMod((RAbstractDoubleVector) ltyVec, index); num = RRuntime.isNA(realVal) ? RRuntime.INT_NA : (int) realVal; } else if (ltyVec instanceof RAbstractIntVector) { - num = ((RAbstractIntVector) ltyVec).getDataAt(0); + num = getDataAtMod((RAbstractIntVector) ltyVec, index); } else { num = RRuntime.INT_NA; } - - if (RRuntime.isNA(num) || num < LINE_STYLES.length) { + if (RRuntime.isNA(num) || num < 0 || num >= LINE_STYLES.length) { throw RError.error(RError.NO_CALLER, Message.GENERIC, "Invalid line type."); } return LINE_STYLES[num]; @@ -167,22 +208,22 @@ public final class GPar { @Override public double getFontSize() { - return asDouble(data[GP_FONTSIZE]) * asDouble(data[GP_CEX]); + return asDouble(data[GP_FONTSIZE], index) * asDouble(data[GP_CEX], index); } @Override public GridFontStyle getFontStyle() { - return GridFontStyle.fromInt(RRuntime.asInteger(data[GP_FONT])); + return GridFontStyle.fromInt(GridUtils.asInt(data[GP_FONT], index)); } @Override public String getFontFamily() { - return RRuntime.asString(data[GP_FONTFAMILY]); + return GridUtils.asString(data[GP_FONTFAMILY], index); } @Override public double getLineHeight() { - return asDouble(data[GP_LINEHEIGHT]); + return asDouble(data[GP_LINEHEIGHT], index); } @Override @@ -190,8 +231,8 @@ public final class GPar { return getGridColor(GP_FILL); } - private GridColor getGridColor(int index) { - return GridColorUtils.gridColorFromString(RRuntime.asString(data[index])); + private GridColor getGridColor(int listIndex) { + return GridColorUtils.gridColorFromString(GridUtils.asString(data[listIndex], index)); } private static final byte[] DASHED_LINE = new byte[]{4, 4}; diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridLinesNode.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridLinesNode.java index 2cceaeb82a..d2bc1d2830 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridLinesNode.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridLinesNode.java @@ -51,10 +51,10 @@ public abstract class GridLinesNode extends Node { GridDevice dev = ctx.getCurrentDevice(); RList currentVP = ctx.getGridState().getViewPort(); - DrawingContext drawingCtx = GPar.asDrawingContext(ctx.getGridState().getGpar()); + GPar gpar = GPar.create(ctx.getGridState().getGpar()); ViewPortTransform vpTransform = getViewPortTransform.execute(currentVP, dev); ViewPortContext vpContext = ViewPortContext.fromViewPort(currentVP); - UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, drawingCtx); + UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, gpar); // Convert the list of vectors of indexes to type-safe array and calculate the max length of // the vectors. @@ -67,7 +67,9 @@ public abstract class GridLinesNode extends Node { double[] xx = new double[maxIndexesLen + 1]; // plus one for polygons double[] yy = new double[maxIndexesLen + 1]; - for (RAbstractIntVector unitIndexes : unitIndexesList) { + for (int unitIndexesListIdx = 0; unitIndexesListIdx < unitIndexesList.length; unitIndexesListIdx++) { + RAbstractIntVector unitIndexes = unitIndexesList[unitIndexesListIdx]; + DrawingContext drawingCtx = gpar.getDrawingContext(unitIndexesListIdx); boolean oldIsFinite = false; int start = 0; int unitIndexesLen = unitIndexes.getLength(); 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 fbedb1f853..6774a7b722 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 @@ -11,7 +11,6 @@ */ package com.oracle.truffle.r.library.fastrGrid; -import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext; import com.oracle.truffle.r.library.fastrGrid.device.GridDevice; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RNull; @@ -53,8 +52,12 @@ public final class GridState { gpar = GPar.createNew(currentDevice); } - public static DrawingContext getInitialGPar(GridDevice device) { - return GPar.asDrawingContext(GPar.createNew(device)); + /** + * Returns something like a canonical gpar, or top level gpar. This is used when we need a + * context to do e.g. unit conversion, but we are in a situation that no context is available. + */ + public static GPar getInitialGPar(GridDevice device) { + return GPar.create(GPar.createNew(device)); } public RList getGpar() { diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridTextNode.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridTextNode.java index b9d862b0fb..594bca1676 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridTextNode.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridTextNode.java @@ -95,10 +95,10 @@ public final class GridTextNode extends RBaseNode { GridDevice dev = ctx.getCurrentDevice(); RList currentVP = ctx.getGridState().getViewPort(); - DrawingContext drawingCtx = GPar.asDrawingContext(ctx.getGridState().getGpar()); + GPar gpar = GPar.create(ctx.getGridState().getGpar()); ViewPortTransform vpTransform = getViewPortTransform.execute(currentVP, dev); ViewPortContext vpContext = ViewPortContext.fromViewPort(currentVP); - UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, drawingCtx); + UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, gpar); int length = GridUtils.maxLength(unitLength, x, y); @@ -131,7 +131,7 @@ public final class GridTextNode extends RBaseNode { boolean doDraw = true; Rectangle trect = null; if (checkOverlap || !draw) { - trect = textRect(loc, hjust, vjust, rotation, text, drawingCtx, dev); + trect = textRect(loc, hjust, vjust, rotation, text, gpar.getDrawingContext(i), dev); for (int j = 0; j < boundsCount; j++) { if (trect.intersects(bounds[j])) { doDraw = false; @@ -145,7 +145,7 @@ public final class GridTextNode extends RBaseNode { // actual drawing if (draw && doDraw) { - text(loc.x, loc.y, text, hjust, vjust, rotation, drawingCtx, dev); + text(loc.x, loc.y, text, hjust, vjust, rotation, gpar.getDrawingContext(i), dev); } // or bounds checking diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridUtils.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridUtils.java index b57eaaa994..8b34ba02b1 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridUtils.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridUtils.java @@ -26,6 +26,7 @@ import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; final class GridUtils { @@ -161,6 +162,18 @@ final class GridUtils { throw RError.error(RError.NO_CALLER, Message.GENERIC, "Unexpected non integer value " + val.getClass().getSimpleName()); } + static String asString(Object val, int cyclicIndex) { + if (val instanceof String) { + return (String) val; + } else if (val instanceof RAbstractStringVector) { + RAbstractStringVector vec = (RAbstractStringVector) val; + if (vec.getLength() > 0) { + return vec.getDataAt(cyclicIndex % vec.getLength()); + } + } + throw RError.error(RError.NO_CALLER, Message.GENERIC, "Unexpected non character value " + val.getClass().getSimpleName()); + } + static RAbstractIntVector asIntVector(Object value) { if (value instanceof Integer) { return RDataFactory.createIntVectorFromScalar((Integer) value); diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LCircle.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LCircle.java index 4d0183bf8f..07ff0d4e40 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LCircle.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LCircle.java @@ -17,7 +17,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.r.library.fastrGrid.Unit.UnitConversionContext; import com.oracle.truffle.r.library.fastrGrid.ViewPortTransform.GetViewPortTransformNode; -import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext; import com.oracle.truffle.r.library.fastrGrid.device.GridDevice; import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; import com.oracle.truffle.r.runtime.data.RList; @@ -48,10 +47,10 @@ public abstract class LCircle extends RExternalBuiltinNode.Arg3 { GridDevice dev = ctx.getCurrentDevice(); RList currentVP = ctx.getGridState().getViewPort(); - DrawingContext drawingCtx = GPar.asDrawingContext(ctx.getGridState().getGpar()); + GPar gpar = GPar.create(ctx.getGridState().getGpar()); ViewPortTransform vpTransform = getViewPortTransform.execute(currentVP, dev); ViewPortContext vpContext = ViewPortContext.fromViewPort(currentVP); - UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, drawingCtx); + UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, gpar); int length = GridUtils.maxLength(unitLength, xVec, yVec, radiusVec); for (int i = 0; i < length; i++) { @@ -59,7 +58,7 @@ public abstract class LCircle extends RExternalBuiltinNode.Arg3 { double radius = RMath.fmin2(radiusSizes.getWidth(), radiusSizes.getHeight()); Point origLoc = Point.fromUnits(unitToInches, xVec, yVec, i, conversionCtx); Point loc = TransformMatrix.transLocation(origLoc, vpTransform.transform); - dev.drawCircle(drawingCtx, loc.x, loc.y, radius); + dev.drawCircle(gpar.getDrawingContext(i), loc.x, loc.y, radius); } return RNull.instance; } diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LConvert.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LConvert.java index b2300de6ab..134def4c4e 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LConvert.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LConvert.java @@ -23,7 +23,6 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.r.library.fastrGrid.Unit.AxisOrDimension; import com.oracle.truffle.r.library.fastrGrid.Unit.UnitConversionContext; import com.oracle.truffle.r.library.fastrGrid.ViewPortTransform.GetViewPortTransformNode; -import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext; import com.oracle.truffle.r.library.fastrGrid.device.GridDevice; import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; import com.oracle.truffle.r.runtime.data.RDataFactory; @@ -57,10 +56,10 @@ public abstract class LConvert extends RExternalBuiltinNode.Arg4 { GridDevice dev = ctx.getCurrentDevice(); RList currentVP = ctx.getGridState().getViewPort(); - DrawingContext drawingCtx = GPar.asDrawingContext(ctx.getGridState().getGpar()); + GPar gpar = GPar.create(ctx.getGridState().getGpar()); ViewPortTransform vpTransform = getViewPortTransform.execute(currentVP, dev); ViewPortContext vpContext = ViewPortContext.fromViewPort(currentVP); - UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, drawingCtx); + UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, gpar); int length = unitLength.execute(units); double[] result = new double[length]; @@ -94,7 +93,7 @@ public abstract class LConvert extends RExternalBuiltinNode.Arg4 { boolean isX = axisTo.isHorizontal(); double scalemin = isX ? vpContext.xscalemin : vpContext.yscalemin; double scalemax = isX ? vpContext.xscalemax : vpContext.yscalemax; - result[i] = Unit.convertFromInches(inches, unitTo, vpToSize, scalemin, scalemax, axisTo.isDimension(), drawingCtx); + result[i] = Unit.convertFromInches(inches, unitTo, vpToSize, scalemin, scalemax, axisTo.isDimension(), gpar.getDrawingContext(i)); } } diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LInitViewPortStack.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LInitViewPortStack.java index 82c23f06ae..8a28365fc7 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LInitViewPortStack.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LInitViewPortStack.java @@ -11,7 +11,6 @@ */ package com.oracle.truffle.r.library.fastrGrid; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.r.library.fastrGrid.ViewPort.InitViewPortNode; import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; 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 07545f1ba2..d4bd5f8217 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 @@ -64,20 +64,22 @@ public abstract class LPoints extends RExternalBuiltinNode.Arg4 { GridDevice dev = ctx.getCurrentDevice(); RList currentVP = ctx.getGridState().getViewPort(); - RList gpar = ctx.getGridState().getGpar(); - DrawingContext drawingCtx = GPar.asDrawingContext(gpar); - double cex = GPar.getCex(gpar); + RList gparList = ctx.getGridState().getGpar(); + GPar gpar = GPar.create(gparList); + double cex = GPar.getCex(gparList); ViewPortTransform vpTransform = getViewPortTransform.execute(currentVP, dev); ViewPortContext vpContext = ViewPortContext.fromViewPort(currentVP); - UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, drawingCtx); + UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, gpar); // 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()); + DrawingContext initialDrawingCtx = gpar.getDrawingContext(0); + PointDrawingContext pointDrawingCtx = new PointDrawingContext(initialDrawingCtx, initialDrawingCtx.getFillColor(), initialDrawingCtx.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)) { + pointDrawingCtx = pointDrawingCtx.update(gpar.getDrawingContext(i)); pointDrawingCtx = drawSymbol(pointDrawingCtx, dev, cex, pchVec.getDataAt(i % pchVec.getLength()), size, loc.x, loc.y); } } @@ -153,6 +155,13 @@ public abstract class LPoints extends RExternalBuiltinNode.Arg4 { return new PointDrawingContext(inner, color, fillColor); } + private PointDrawingContext update(DrawingContext inner) { + if (this.inner == inner) { + return this; + } + return new PointDrawingContext(inner, this.color, this.fillColor); + } + @Override public byte[] getLineType() { return inner.getLineType(); diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LRect.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LRect.java index a666b07ede..7c69b09329 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LRect.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LRect.java @@ -19,7 +19,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.r.library.fastrGrid.Unit.UnitConversionContext; import com.oracle.truffle.r.library.fastrGrid.ViewPortTransform.GetViewPortTransformNode; -import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext; import com.oracle.truffle.r.library.fastrGrid.device.GridDevice; import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; import com.oracle.truffle.r.runtime.data.RList; @@ -53,10 +52,10 @@ public abstract class LRect extends RExternalBuiltinNode.Arg6 { GridDevice dev = ctx.getCurrentDevice(); RList currentVP = ctx.getGridState().getViewPort(); - DrawingContext drawingCtx = GPar.asDrawingContext(ctx.getGridState().getGpar()); + GPar gpar = GPar.create(ctx.getGridState().getGpar()); ViewPortTransform vpTransform = getViewPortTransform.execute(currentVP, dev); ViewPortContext vpContext = ViewPortContext.fromViewPort(currentVP); - UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, drawingCtx); + UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, gpar); int length = GridUtils.maxLength(unitLength, xVec, yVec, wVec, hVec); for (int i = 0; i < length; i++) { @@ -66,7 +65,7 @@ public abstract class LRect extends RExternalBuiltinNode.Arg6 { Point origLoc = Point.fromUnits(unitToInches, xVec, yVec, i, conversionCtx); Point transLoc = TransformMatrix.transLocation(origLoc, vpTransform.transform); Point loc = transLoc.justify(size, getDataAtMod(hjust, i), getDataAtMod(vjust, i)); - dev.drawRect(drawingCtx, loc.x, loc.y, size.getWidth(), size.getHeight()); + dev.drawRect(gpar.getDrawingContext(i), loc.x, loc.y, size.getWidth(), size.getHeight()); } return RNull.instance; } diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LSegments.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LSegments.java index 1a3dda410e..c2e1cf10ba 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LSegments.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LSegments.java @@ -17,7 +17,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.r.library.fastrGrid.Unit.UnitConversionContext; import com.oracle.truffle.r.library.fastrGrid.ViewPortTransform.GetViewPortTransformNode; -import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext; import com.oracle.truffle.r.library.fastrGrid.device.GridDevice; import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; import com.oracle.truffle.r.runtime.data.RList; @@ -59,10 +58,10 @@ public abstract class LSegments extends RExternalBuiltinNode.Arg5 { GridDevice dev = ctx.getCurrentDevice(); RList currentVP = ctx.getGridState().getViewPort(); - DrawingContext drawingCtx = GPar.asDrawingContext(ctx.getGridState().getGpar()); + GPar gpar = GPar.create(ctx.getGridState().getGpar()); ViewPortTransform vpTransform = getViewPortTransform.execute(currentVP, dev); ViewPortContext vpContext = ViewPortContext.fromViewPort(currentVP); - UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, drawingCtx); + UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, gpar); int length = GridUtils.maxLength(unitLength, x0, y0, x1, y1); double[] xx = new double[2]; @@ -77,7 +76,7 @@ public abstract class LSegments extends RExternalBuiltinNode.Arg5 { xx[1] = loc2.x; yy[0] = loc1.y; yy[1] = loc2.y; - dev.drawPolyLines(drawingCtx, xx, yy, 0, 2); + dev.drawPolyLines(gpar.getDrawingContext(i), xx, yy, 0, 2); if (arrow != null) { drawArrowsNode.drawArrows(xx, yy, 0, 2, i, arrow, true, true, conversionCtx); } diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/Unit.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/Unit.java index 4cb343dfbf..3c20956103 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/Unit.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/Unit.java @@ -183,7 +183,7 @@ public class Unit { } } - private static double convertToInches(double value, int unitId, RList data, UnitConversionContext ctx, AxisOrDimension axisOrDim) { + private static double convertToInches(double value, int index, int unitId, RList data, UnitConversionContext ctx, AxisOrDimension axisOrDim) { double vpSize = ctx.getViewPortSize(axisOrDim); switch (unitId) { case INCHES: @@ -201,16 +201,16 @@ public class Unit { return value / (CM_IN_INCH * 10); case CHAR: case MYCHAR: - return (value * ctx.drawingContext.getFontSize()) / INCH_TO_POINTS_FACTOR; + return (value * ctx.gpar.getDrawingContext(index).getFontSize()) / INCH_TO_POINTS_FACTOR; case LINES: case MYLINES: - return (value * ctx.drawingContext.getFontSize() * ctx.drawingContext.getLineHeight()) / INCH_TO_POINTS_FACTOR; + return (value * ctx.gpar.getDrawingContext(index).getFontSize() * ctx.gpar.getDrawingContext(index).getLineHeight()) / INCH_TO_POINTS_FACTOR; case STRINGWIDTH: case MYSTRINGWIDTH: - return ctx.device.getStringWidth(ctx.drawingContext, RRuntime.asString(data.getDataAt(0))); + return ctx.device.getStringWidth(ctx.gpar.getDrawingContext(index), RRuntime.asString(data.getDataAt(0))); case STRINGHEIGHT: case MYSTRINGHEIGHT: - return ctx.device.getStringHeight(ctx.drawingContext, RRuntime.asString(data.getDataAt(0))); + return ctx.device.getStringHeight(ctx.gpar.getDrawingContext(index), RRuntime.asString(data.getDataAt(0))); case NULL: return evaluateNullUnit(value, vpSize, ctx.nullLayoutMode, ctx.nullArithmeticMode); default: @@ -423,20 +423,20 @@ public class Unit { public static final class UnitConversionContext { public final Size viewPortSize; public final ViewPortContext viewPortContext; - public final DrawingContext drawingContext; + public final GPar gpar; public final GridDevice device; public final int nullLayoutMode; public final int nullArithmeticMode; - public UnitConversionContext(Size viewPortSize, ViewPortContext viewPortContext, GridDevice device, DrawingContext drawingContext) { - this(viewPortSize, viewPortContext, device, drawingContext, 0, 0); + public UnitConversionContext(Size viewPortSize, ViewPortContext viewPortContext, GridDevice device, GPar gpar) { + this(viewPortSize, viewPortContext, device, gpar, 0, 0); } - public UnitConversionContext(Size viewPortSize, ViewPortContext viewPortContext, GridDevice device, DrawingContext drawingContext, int nullLMode, int nullAMode) { + public UnitConversionContext(Size viewPortSize, ViewPortContext viewPortContext, GridDevice device, GPar gpar, int nullLMode, int nullAMode) { this.viewPortSize = viewPortSize; this.viewPortContext = viewPortContext; this.device = device; - this.drawingContext = drawingContext; + this.gpar = gpar; this.nullLayoutMode = nullLMode; this.nullArithmeticMode = nullAMode; } @@ -495,7 +495,7 @@ public class Unit { RList grobList = asList(value.getAttr(UNIT_ATTR_DATA)); return getGrobUnitToInchesNode().execute(scalarValue, unitId, grobList.getDataAt(index % grobList.getLength()), ctx); } - return convertToInches(scalarValue, unitId, asListOrNull(value.getAttr(UNIT_ATTR_DATA)), ctx, axisOrDim); + return convertToInches(scalarValue, index, unitId, asListOrNull(value.getAttr(UNIT_ATTR_DATA)), ctx, axisOrDim); } @Specialization(guards = "isUnitList(value)") @@ -548,7 +548,7 @@ public class Unit { // Note the catch: newNullAMode is applied only if the axisOrDim is dimension private static UnitConversionContext getNewCtx(UnitConversionContext ctx, AxisOrDimension axisOrDim, int newNullAMode) { - return new UnitConversionContext(ctx.viewPortSize, ctx.viewPortContext, ctx.device, ctx.drawingContext, ctx.nullLayoutMode, + return new UnitConversionContext(ctx.viewPortSize, ctx.viewPortContext, ctx.device, ctx.gpar, ctx.nullLayoutMode, axisOrDim.isDimension() ? newNullAMode : ctx.nullArithmeticMode); } @@ -628,7 +628,7 @@ public class Unit { double nullUnitValue = pureNullUnitValue((RAbstractContainer) unitxy.getDataAt(0), 0); result = evaluateNullUnit(nullUnitValue, vpTransform.size.getWidth(), conversionCtx.nullLayoutMode, conversionCtx.nullArithmeticMode); } else { - UnitConversionContext newConversionCtx = new UnitConversionContext(vpTransform.size, vpContext, conversionCtx.device, GPar.asDrawingContext(currentGP)); + UnitConversionContext newConversionCtx = new UnitConversionContext(vpTransform.size, vpContext, conversionCtx.device, GPar.create(currentGP)); initUnitToInchesNode(); if (unitId == GROBWIDTH) { result = unitToInchesNode.convertWidth((RAbstractContainer) unitxy.getDataAt(0), 0, newConversionCtx); 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 index f85a04b4c4..e36fcac3d7 100644 --- 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 @@ -30,7 +30,7 @@ import java.util.ArrayList; * 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. + * rely on the fact that {@link DrawingContext} is immutable. */ public class BufferedJFrameDevice implements GridDevice { private final JFrameDevice inner; 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 4b42cdce8c..6b1c9451bd 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 @@ -58,10 +58,7 @@ public class GridColor { @Override public boolean equals(Object obj) { - if (!(obj instanceof GridColor)) { - return false; - } - return value == ((GridColor) obj).value; + return obj instanceof GridColor && value == ((GridColor) obj).value; } @Override -- GitLab