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 new file mode 100644 index 0000000000000000000000000000000000000000..591c4e25f4ef7b9780e6870b47f142c4998ecb4f --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPort.java @@ -0,0 +1,410 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +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.asList; +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.asListOrNull; +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.sum; +import static com.oracle.truffle.r.library.fastrGrid.TransformMatrix.flatten; +import static com.oracle.truffle.r.library.fastrGrid.TransformMatrix.fromFlat; +import static com.oracle.truffle.r.library.fastrGrid.TransformMatrix.multiply; +import static com.oracle.truffle.r.library.fastrGrid.TransformMatrix.rotation; +import static com.oracle.truffle.r.library.fastrGrid.TransformMatrix.translation; +import static com.oracle.truffle.r.library.fastrGrid.Unit.newUnit; +import static com.oracle.truffle.r.nodes.builtin.casts.fluent.CastNodeBuilder.newCastBuilder; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +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; +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RDoubleVector; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RNull; +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.env.REnvironment; +import com.oracle.truffle.r.runtime.env.REnvironment.PutException; +import com.oracle.truffle.r.runtime.nodes.RBaseNode; + +class DoSetViewPort extends RBaseNode { + @Child private CastNode castScalarDouble = newCastBuilder().asDoubleVector().findFirst().buildCastNode(); + @Child private CastNode castDoubleVector = newCastBuilder().asDoubleVector().buildCastNode(); + @Child private CastNode castChildrenEnv = newCastBuilder().mustBe(REnvironment.class).buildCastNode(); + @Child private Unit.UnitToInchesNode unitsToInches = Unit.UnitToInchesNode.create(); + @Child private IsRelativeUnitNode isRelativeUnit = new IsRelativeUnitNode(); + + @TruffleBoundary + public RList doSetViewPort(RList pushedViewPort, boolean hasParent, boolean pushing) { + GridState gridState = GridContext.getContext().getGridState(); + Object[] pushedVPData = pushedViewPort.getDataWithoutCopying(); + if (hasParent && pushing) { + RList parent = gridState.getViewPort(); + pushedVPData[ViewPort.PVP_PARENT] = parent; + REnvironment children = (REnvironment) castChildrenEnv.execute(parent.getDataAt(ViewPort.PVP_CHILDREN)); + safePutToEnv(pushedViewPort, pushedVPData[ViewPort.VP_NAME], children); + } + + GridDevice currentDevice = GridContext.getContext().getCurrentDevice(); + DrawingContext deviceDrawingContext = GridState.getInitialGPar(currentDevice); + + RList parent = asListOrNull(pushedViewPort.getDataAt(ViewPort.PVP_PARENT)); + boolean doNotRecalculateParent = hasParent && !ViewPort.updateDeviceSizeInVP(parent, currentDevice); + calcViewportTransform(pushedViewPort, parent, doNotRecalculateParent, currentDevice, deviceDrawingContext); + + // TODO: clipping + pushedVPData[ViewPort.PVP_CLIPRECT] = RDataFactory.createDoubleVector(new double[]{0, 0, 0, 0}, RDataFactory.COMPLETE_VECTOR); + pushedVPData[ViewPort.PVP_DEVWIDTHCM] = scalar(Unit.inchesToCm(currentDevice.getWidth())); + pushedVPData[ViewPort.PVP_DEVHEIGHTCM] = scalar(Unit.inchesToCm(currentDevice.getHeight())); + return pushedViewPort; + } + + /** + * Calculates and sets the view-port width and height in inches, and transformation matrix and + * rotation angle. + * + * @param viewPort The view-port to be updated. + * @param parent The parent of the view-port, null if the view-port is top level. + * @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 + * order to convert units for the top level view port + */ + @TruffleBoundary + public void calcViewportTransform(RList viewPort, Object parent, boolean incremental, GridDevice device, DrawingContext deviceDrawingContext) { + double[][] parentTransform; + ViewPortContext parentContext; + ViewPortLocation vpl; + Size parentSize; + DrawingContext 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; + 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); + } + 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))); + 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); + } else { + vpl = calcViewportLocationFromLayout(getLayoutPos(viewPort, parentVPList), parentVPList, parentSize); + } + } + + UnitConversionContext conversionCtx = new UnitConversionContext(parentSize, parentContext, device, drawingContext); + double xInches = unitsToInches.convertX(vpl.x, 0, conversionCtx); + double yInches = unitsToInches.convertY(vpl.y, 0, conversionCtx); + double width = unitsToInches.convertWidth(vpl.width, 0, conversionCtx); + double height = unitsToInches.convertHeight(vpl.height, 0, conversionCtx); + + if (!Double.isFinite(xInches) || !Double.isFinite(yInches) || !Double.isFinite(width) || !Double.isFinite(height)) { + throw error(Message.GENERIC, "non-finite location and/or size for viewport"); + } + + double xadj = GridUtils.justification(width, vpl.hjust); + double yadj = GridUtils.justification(height, vpl.vjust); + + // Produce transform for this viewport + double[][] thisLocation = translation(xInches, yInches); + double[][] thisJustification = translation(xadj, yadj); + // Position relative to origin of rotation THEN rotate. + double viewPortAngle = asDouble(viewPort.getDataAt(ViewPort.VP_ANGLE)); + double[][] thisRotation = rotation(viewPortAngle); + double[][] tempTransform = multiply(thisJustification, thisRotation); + // Translate to bottom-left corner. + double[][] thisTransform = multiply(tempTransform, thisLocation); + // Combine with parent's transform + double[][] transform = multiply(thisTransform, parentTransform); + + // Sum up the rotation angles + double rotationAngle = parentAngle + viewPortAngle; + + // 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); + } + + Object[] viewPortData = viewPort.getDataWithoutCopying(); + viewPortData[ViewPort.PVP_WIDTHCM] = scalar(Unit.inchesToCm(width)); + viewPortData[ViewPort.PVP_HEIGHTCM] = scalar(Unit.inchesToCm(height)); + viewPortData[ViewPort.PVP_ROTATION] = scalar(rotationAngle); + 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) { + 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); + + // 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 + // gives us how much of width/height is left after we take up the space by physical units + Object[] layoutData = asList(viewPort.getDataAt(ViewPort.VP_LAYOUT)).getDataWithoutCopying(); + RAbstractContainer layoutWidths = asAbstractContainer(layoutData[ViewPort.LAYOUT_WIDTHS]); + assert layoutWidths.getLength() == layoutSize.ncol : "inconsistent layout size with layout widths"; + double reducedWidth = getReducedDimension(layoutWidths, npcWidths, relativeWidths, size.getWidth(), conversionCtx, true); + + RAbstractContainer layoutHeights = asAbstractContainer(layoutData[ViewPort.LAYOUT_HEIGHTS]); + assert layoutHeights.getLength() == layoutSize.nrow : "inconsistent layout size with layout height"; + double reducedHeight = getReducedDimension(layoutHeights, npcHeights, relativeHeights, size.getHeight(), conversionCtx, false); + + // npcHeight (and npcWidth) has some 'holes' in them, at indexes with + // relativeHeights[index]==true, we will calculate the values for them now. + // Firstly allocate the respected widths/heights and calculate how much space remains + RList layoutAsList = asList(viewPort.getDataAt(ViewPort.VP_LAYOUT)); + 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 tempWidth = reducedWidth; + double tempHeight = reducedHeight; + double denom; + double mult; + // Determine whether aspect ratio of available space is bigger or smaller than + // aspect ratio of layout + if (tempHeight * sumRelWidth > sumRelHeight * tempWidth) { + denom = sumRelWidth; + mult = tempWidth; + } else { + denom = sumRelHeight; + mult = tempHeight; + } + for (int i = 0; i < layoutSize.ncol; i++) { + if (relativeWidths[i] && colRespected(respect, i, layoutRespectMat, layoutSize)) { + /* + * Special case of respect, but sumHeight = 0. Action is to allocate widths as + * if unrespected. Ok to test == 0 because will only be 0 if all relative + * heights are actually exactly 0. + */ + if (sumRelHeight == 0) { + denom = sumRelWidth; + mult = tempWidth; + } + // Build a unit SEXP with a single value and no data + npcWidths[i] = Unit.pureNullUnitValue(layoutWidths, i) / denom * mult; + reducedWidth -= npcWidths[i]; + } + } + for (int i = 0; i < layoutSize.nrow; i++) { + if (relativeHeights[i] && rowRespected(respect, i, layoutRespectMat, layoutSize)) { + if (sumRelWidth == 0) { + denom = sumRelHeight; + mult = tempHeight; + } + npcHeights[i] = Unit.pureNullUnitValue(layoutHeights, i) / denom * mult; + reducedHeight -= npcHeights[i]; + } + } + } else if (respect > 0) { + for (int i = 0; i < layoutSize.ncol; i++) { + if (relativeWidths[i] && colRespected(respect, i, layoutRespectMat, layoutSize)) { + npcWidths[i] = 0; + } + } + for (int i = 0; i < layoutSize.nrow; i++) { + if (relativeHeights[i] && rowRespected(respect, i, layoutRespectMat, layoutSize)) { + npcHeights[i] = 0; + } + } + } + + // 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); + + // Create the result + Object[] vpData = viewPort.getDataWithoutCopying(); + vpData[ViewPort.PVP_WIDTHS] = RDataFactory.createDoubleVector(npcWidths, RDataFactory.COMPLETE_VECTOR); + vpData[ViewPort.PVP_HEIGHTS] = RDataFactory.createDoubleVector(npcHeights, RDataFactory.COMPLETE_VECTOR); + } + + 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) { + assert relativeItems.length == npcItems.length; + UnitConversionContext layoutModeCtx = new UnitConversionContext(new Size(0, 0), parentVPCtx, device, drawingCtx, 1, 0); + double totalUnrespectedSize = 0; + if (reducedDim > 0) { + for (int i = 0; i < relativeItems.length; i++) { + if (relativeItems[i] && !rowColRespected(respect, i, layoutRespectMat, layoutSize, isWidth)) { + totalUnrespectedSize += unitsToInches.convertDimension(layoutItems, i, layoutModeCtx, isWidth); + } + } + } + // set the remaining width/height to zero or to proportion of totalUnrespectedSize + for (int i = 0; i < relativeItems.length; i++) { + if (relativeItems[i] && !rowColRespected(respect, i, layoutRespectMat, layoutSize, isWidth)) { + npcItems[i] = 0; + if (totalUnrespectedSize > 0) { + // if there was some with left, then totalUnrespectedSize contains sum of it + npcItems[i] = reducedDim * unitsToInches.convertDimension(layoutItems, i, layoutModeCtx, isWidth) / totalUnrespectedSize; + } + } + } + } + + private boolean rowColRespected(int respected, int rowOrCol, int[] layoutRespectMat, LayoutSize layoutSize, boolean isColumn) { + return isColumn ? colRespected(respected, rowOrCol, layoutRespectMat, layoutSize) : rowRespected(respected, rowOrCol, layoutRespectMat, layoutSize); + } + + private boolean rowRespected(int respected, int row, int[] layoutRespectMat, LayoutSize layoutSize) { + if (respected == 1) { + return true; + } + for (int i = 0; i < layoutSize.ncol; i++) { + if (layoutRespectMat[i * layoutSize.nrow + row] != 0) { + return true; + } + } + return false; + } + + private boolean colRespected(int respected, int col, int[] layoutRespectMat, LayoutSize layoutSize) { + if (respected == 1) { + return true; + } + for (int i = 0; i < layoutSize.nrow; i++) { + if (layoutRespectMat[col * layoutSize.nrow + i] != 0) { + return true; + } + } + return false; + } + + private double sumRelativeDimension(RAbstractContainer layoutItems, boolean[] relativeItems, ViewPortContext parentVPCtx, GridDevice device, DrawingContext drawingCtx, + boolean isWidth) { + UnitConversionContext layoutModeCtx = new UnitConversionContext(new Size(0, 0), parentVPCtx, device, drawingCtx, 1, 0); + double totalWidth = 0; + for (int i = 0; i < relativeItems.length; i++) { + if (relativeItems[i]) { + totalWidth += unitsToInches.convertDimension(layoutItems, i, layoutModeCtx, isWidth); + } + } + return totalWidth; + } + + private double getReducedDimension(RAbstractContainer layoutItems, double[] npcItems, boolean[] relativeItems, double initialSize, UnitConversionContext conversionCtx, + boolean isWidth) { + double reducedSize = initialSize; + for (int i = 0; i < npcItems.length; i++) { + boolean currIsRel = isRelativeUnit.execute(layoutItems, i); + relativeItems[i] = currIsRel; + if (!currIsRel) { + npcItems[i] = unitsToInches.convertDimension(layoutItems, i, conversionCtx, isWidth); + reducedSize -= npcItems[i]; + } + } + return reducedSize; + } + + private RAbstractDoubleVector castDoubleVector(Object obj) { + return (RAbstractDoubleVector) castDoubleVector.execute(obj); + } + + private double castScalar(Object obj) { + return (double) castScalarDouble.execute(obj); + } + + private static RDoubleVector scalar(double val) { + return RDataFactory.createDoubleVectorFromScalar(val); + } + + private static void safePutToEnv(RList pushedViewPort, Object pushedVPDatum, REnvironment children) { + try { + children.put(RRuntime.asString(pushedVPDatum), pushedViewPort); + } catch (PutException e) { + throw RInternalError.shouldNotReachHere("Cannot update children environment in a view port list"); + } + } + + // Note: unlike the GnuR conterpart of this method, we expect the LayoutPos to have the NULL + // positions replaced with nrow/ncol already. + private ViewPortLocation calcViewportLocationFromLayout(LayoutPos pos, RList parentVP, Size parentSize) { + // unlike in GnuR, we maintain parent viewport widths/heights in inches like anything else + double[] widths = castDoubleVector(parentVP.getDataAt(ViewPort.PVP_WIDTHS)).materialize().getDataWithoutCopying(); + double[] heights = castDoubleVector(parentVP.getDataAt(ViewPort.PVP_HEIGHTS)).materialize().getDataWithoutCopying(); + double totalWidth = sum(widths, 0, pos.layoutSize.ncol); + double totalHeight = sum(heights, 0, pos.layoutSize.nrow); + double width = sum(widths, pos.colMin, pos.colMax - pos.colMin + 1); + double height = sum(heights, pos.rowMin, pos.rowMax - pos.rowMin + 1); + double left = parentSize.getWidth() * pos.layoutSize.hjust - totalWidth * pos.layoutSize.hjust + sum(widths, 0, pos.colMin); + double bottom = parentSize.getHeight() * pos.layoutSize.vjust + (1 - pos.layoutSize.vjust) * totalHeight - sum(heights, 0, pos.rowMax + 1); + ViewPortLocation result = new ViewPortLocation(); + result.width = newUnit(width, Unit.INCHES); + result.height = newUnit(height, Unit.INCHES); + result.x = newUnit(left, Unit.INCHES); + result.y = newUnit(bottom, Unit.INCHES); + result.hjust = result.vjust = 0; + return result; + } + + private LayoutPos getLayoutPos(RList vp, RList parent) { + LayoutSize size = LayoutSize.fromViewPort(parent); + Object rowObj = vp.getDataAt(ViewPort.VP_VALIDLPOSROW); + int rowMin = 1; + int rowMax = size.nrow; + if (rowObj instanceof RAbstractIntVector) { + rowMin = ((RAbstractIntVector) rowObj).getDataAt(0); + rowMax = ((RAbstractIntVector) rowObj).getDataAt(1); + if (rowMin < 1 || rowMax > size.nrow) { + throw error(Message.GENERIC, "invalid 'layout.pos.row'"); + } + } + Object colObj = vp.getDataAt(ViewPort.VP_VALIDLPOSCOL); + int colMin = 1; + int colMax = size.ncol; + if (colObj instanceof RAbstractIntVector) { + colMin = ((RAbstractIntVector) colObj).getDataAt(0); + colMax = ((RAbstractIntVector) colObj).getDataAt(1); + if (colMin < 1 || colMax > size.ncol) { + throw error(Message.GENERIC, "invalid 'layout.pos.row'"); + } + } + // the indexes in LayoutPos are to be interpreted as 0-based + return new LayoutPos(colMin - 1, colMax - 1, rowMin - 1, rowMax - 1, size); + } + + private static boolean isNull(Object value) { + return value == null || value == RNull.instance; + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPortBuiltin.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPortBuiltin.java new file mode 100644 index 0000000000000000000000000000000000000000..d8b2359414dd6ac40bab72f1e23d2375f8f3d421 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPortBuiltin.java @@ -0,0 +1,51 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.library.fastrGrid; + +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.logicalValue; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean; + +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.runtime.builtins.RBehavior; +import com.oracle.truffle.r.runtime.builtins.RBuiltin; +import com.oracle.truffle.r.runtime.builtins.RBuiltinKind; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RNull; + +/** + * On the top of what {@link DoSetViewPort} node does, this node sets the resulting view port as the + * current view port in the current {@link GridState} instance. This builtin allows us to write some + * of the grid code in R. + */ +@RBuiltin(name = ".fastr.grid.doSetViewPort", parameterNames = {"vp", "hasParent", "pushing"}, kind = RBuiltinKind.INTERNAL, behavior = RBehavior.COMPLEX) +public abstract class DoSetViewPortBuiltin extends RBuiltinNode { + @Child private DoSetViewPort doSetViewPort = new DoSetViewPort(); + + static { + Casts casts = new Casts(DoSetViewPortBuiltin.class); + casts.arg("vp").mustBe(RList.class); + casts.arg("hasParent").mustBe(logicalValue()).asLogicalVector().findFirst().map(toBoolean()); + casts.arg("pushing").mustBe(logicalValue()).asLogicalVector().findFirst().map(toBoolean()); + } + + @Specialization + RNull doIt(RList pushedVP, boolean hasParent, boolean pushing) { + RList vp = doSetViewPort.doSetViewPort(pushedVP, hasParent, pushing); + GridContext.getContext().getGridState().setViewPort(vp); + return RNull.instance; + } + + public static DoSetViewPortBuiltin create() { + return DoSetViewPortBuiltinNodeGen.create(); + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..e177c722b19cefe51bc3679c57b7ba22255b7908 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DrawArrowsNode.java @@ -0,0 +1,99 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +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.asInt; + +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.r.library.fastrGrid.Unit.UnitConversionContext; +import com.oracle.truffle.r.library.fastrGrid.Unit.UnitToInchesNode; +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.model.RAbstractContainer; + +class DrawArrowsNode extends Node { + // Structure of an arrow description + private static final int ARROWANGLE = 0; + private static final int ARROWLENGTH = 1; + private static final int ARROWENDS = 2; + private static final int ARROWTYPE = 3; + // known values of ARROWTYPE + private static final int ARROWTYPE_LINES = 1; + private static final int ARROWTYPE_POLYGON = 2; + + @Child private UnitToInchesNode unitToInches = Unit.createToInchesNode(); + + /** + * Draws arrows at the start and end of given lines. + * + * @param x x-positions of the line(s) + * @param y y-positions of the line(s) + * @param startIndex consider arrays x,y to start from this index + * @param length consider arrays x,y to have this length + * @param parentIndex the index of the line we are drawing, this is used for choosing the right + * index into vectors extracted from arrow + * @param arrow list with various attributes of the arrow + * @param start should we draw start arrow if the arrow list says so. Otherwise never draw it. + * @param end should we draw end arrow if the arrow list says so. Otherwise never draw it. + * @param conversionCtx needed for unit conversions. + */ + public void drawArrows(double[] x, double[] y, int startIndex, int length, int parentIndex, RList arrow, boolean start, boolean end, UnitConversionContext conversionCtx) { + assert x.length == y.length; + int endsVal = asInt(arrow.getDataAt(ARROWENDS), parentIndex); + boolean first = endsVal != 2; + boolean last = endsVal != 1; + if ((!first || !start) && (!last || !end)) { + // if we are not going to draw any arrow anyway, just finish + return; + } + // extract angle, length in inches and arrow type from 'arrow' + double angle = asDouble(arrow.getDataAt(ARROWANGLE), parentIndex); + int arrowType = asInt(arrow.getDataAt(ARROWTYPE), parentIndex); + RAbstractContainer lengthVec = asAbstractContainer(arrow.getDataAt(ARROWLENGTH)); + double arrowLength = unitToInches.convertHeight(lengthVec, parentIndex, conversionCtx); + arrowLength = Math.max(arrowLength, unitToInches.convertWidth(lengthVec, parentIndex, conversionCtx)); + // draw the arrows + GridDevice device = conversionCtx.device; + DrawingContext drawingCtx = conversionCtx.drawingContext; + if (first && start) { + drawArrow(drawingCtx, device, arrowType, x[startIndex], y[startIndex], x[startIndex + 1], y[startIndex + 1], angle, arrowLength); + } + if (last && end) { + int n = startIndex + length; + drawArrow(drawingCtx, device, arrowType, x[n - 1], y[n - 1], x[n - 2], y[n - 2], angle, arrowLength); + } + } + + private void drawArrow(DrawingContext drawingCtx, GridDevice device, int arrowType, double x0, double y0, double x1, double y1, double angle, double length) { + double a = Math.toRadians(angle); + double xc = x1 - x0; + double yc = y1 - y0; + double rot = Math.atan2(yc, xc); + double[] vertx = new double[3]; + double[] verty = new double[3]; + vertx[0] = x0 + length * Math.cos(rot + a); + verty[0] = y0 + length * Math.sin(rot + a); + vertx[1] = x0; + verty[1] = y0; + vertx[2] = x0 + length * Math.cos(rot - a); + verty[2] = y0 + length * Math.sin(rot - a); + if (arrowType == ARROWTYPE_LINES) { + device.drawPolyLines(drawingCtx, vertx, verty, 0, 3); + } else if (arrowType == ARROWTYPE_POLYGON) { + device.drawPolyLines(drawingCtx, vertx, verty, 0, 3); + // TODO: real polygon + } + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/EdgeDetection.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/EdgeDetection.java new file mode 100644 index 0000000000000000000000000000000000000000..b9d4070415da9c45435dc397973f973b1bd156c3 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/EdgeDetection.java @@ -0,0 +1,223 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.library.fastrGrid; + +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.fmax; +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.fmin; +import static com.oracle.truffle.r.runtime.nmath.MathConstants.M_PI; +import static com.oracle.truffle.r.runtime.nmath.RMath.fmax2; +import static com.oracle.truffle.r.runtime.nmath.RMath.fmin2; +import static com.oracle.truffle.r.runtime.nmath.TOMS708.fabs; + +import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; +import com.oracle.truffle.r.runtime.RInternalError; + +/** + * Contains static method related to edge detection for bounds calculations. + */ +final class EdgeDetection { + private EdgeDetection() { + // only static members + } + + /** + * Do two lines intersect? Algorithm from Paul Bourke + * (http://www.swin.edu.au/astronomy/pbourke/geometry/lineline2d/index.html) + */ + private static boolean linesIntersect(double x1, double x2, double x3, double x4, + double y1, double y2, double y3, double y4) { + double denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); + double ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)); + // If the lines are parallel ... + if (denom == 0) { + // If the lines are coincident ... + if (ua == 0) { + // If the lines are vertical ... + if (x1 == x2) { + // Compare y-values + if (!((y1 < y3 && fmax2(y1, y2) < fmin2(y3, y4)) || (y3 < y1 && fmax2(y3, y4) < fmin2(y1, y2)))) { + return true; + } + } else { + // Compare x-values + if (!((x1 < x3 && fmax2(x1, x2) < fmin2(x3, x4)) || (x3 < x1 && fmax2(x3, x4) < fmin2(x1, x2)))) { + return true; + } + } + } + } else { + // ... otherwise, calculate where the lines intersect ... + double ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)); + ua = ua / denom; + ub = ub / denom; + // Check for overlap + if ((ua > 0 && ua < 1) && (ub > 0 && ub < 1)) { + return true; + } + } + return false; + } + + private static boolean edgesIntersect(double x1, double x2, double y1, double y2, Rectangle r) { + return linesIntersect(x1, x2, r.x[0], r.x[1], y1, y2, r.y[0], r.y[1]) || + linesIntersect(x1, x2, r.x[1], r.x[2], y1, y2, r.y[1], r.y[2]) || + linesIntersect(x1, x2, r.x[2], r.x[3], y1, y2, r.y[2], r.y[3]) || + linesIntersect(x1, x2, r.x[3], r.x[0], y1, y2, r.y[3], r.y[0]); + } + + static Point rectEdge(double xmin, double ymin, double xmax, double ymax, double theta) { + double xm = (xmin + xmax) / 2; + double ym = (ymin + ymax) / 2; + double dx = (xmax - xmin) / 2; + double dy = (ymax - ymin) / 2; + /* + * GNUR fixme: Special case 0 width or 0 height + */ + // Special case angles + if (theta == 0) { + return new Point(xmax, ym); + } else if (theta == 270) { + return new Point(xm, ymin); + } else if (theta == 180) { + return new Point(xmin, ym); + } else if (theta == 90) { + return new Point(xm, ymax); + } else { + double cutoff = dy / dx; + double angle = theta / 180 * M_PI; + double tanTheta = Math.tan(angle); + double cosTheta = Math.cos(angle); + double sinTheta = Math.sin(angle); + if (fabs(tanTheta) < cutoff) { /* Intersect with side */ + if (cosTheta > 0) { /* Right side */ + return new Point(xmax, ym + tanTheta * dx); + } else { /* Left side */ + return new Point(xmin, ym - tanTheta * dx); + } + } else { /* Intersect with top/bottom */ + if (sinTheta > 0) { /* Top */ + return new Point(ymax, xm + dy / tanTheta); + } else { /* Bottom */ + return new Point(ymin, xm - dy / tanTheta); + } + } + } + } + + static Point polygonEdge(double[] x, double[] y, int n, double theta) { + // centre of the polygon + double xmin = fmin(Double.MAX_VALUE, x); + double xmax = fmax(Double.MIN_VALUE, x); + double ymin = fmin(Double.MAX_VALUE, y); + double ymax = fmax(Double.MIN_VALUE, y); + double xm = (xmin + xmax) / 2; + double ym = (ymin + ymax) / 2; + + // Special case zero-width or zero-height + if (fabs(xmin - xmax) < 1e-6) { + double resultY = theta == 90 ? ymax : theta == 270 ? ymin : ym; + return new Point(xmin, resultY); + } + if (fabs(ymin - ymax) < 1e-6) { + double resultX = theta == 0 ? xmax : theta == 180 ? xmin : xm; + return new Point(resultX, ymin); + } + + /* + * Find edge that intersects line from centre at angle theta + */ + boolean found = false; + double angle = theta / 180 * M_PI; + double vangle1; + double vangle2; + int v1 = 0; + int v2 = 1; + for (int i = 0; i < n; i++) { + v1 = i; + v2 = v1 + 1; + if (v2 == n) { + v2 = 0; + } + /* + * Result of atan2 is in range -PI, PI so convert to 0, 360 to correspond to angle + */ + vangle1 = Math.atan2(y[v1] - ym, x[v1] - xm); + if (vangle1 < 0) { + vangle1 = vangle1 + 2 * M_PI; + } + vangle2 = Math.atan2(y[v2] - ym, x[v2] - xm); + if (vangle2 < 0) { + vangle2 = vangle2 + 2 * M_PI; + } + /* + * If vangle1 < vangle2 then angles are either side of 0 so check is more complicated + */ + if ((vangle1 >= vangle2 && + vangle1 >= angle && vangle2 < angle) || + (vangle1 < vangle2 && + ((vangle1 >= angle && 0 <= angle) || + (vangle2 < angle && 2 * M_PI >= angle)))) { + found = true; + break; + } + } + /* + * Find intersection point of "line from centre to bounding rect" and edge + */ + if (!found) { + throw RError.error(RError.NO_CALLER, Message.GENERIC, "polygon edge not found"); + } + double x3 = x[v1]; + double y3 = y[v1]; + double x4 = x[v2]; + double y4 = y[v2]; + Point tmp = rectEdge(xmin, ymin, xmax, ymax, theta); + double x2 = tmp.x; + double y2 = tmp.y; + double numa = ((x4 - x3) * (ym - y3) - (y4 - y3) * (xm - x3)); + double denom = ((y4 - y3) * (x2 - xm) - (x4 - x3) * (y2 - ym)); + double ua = numa / denom; + if (!Double.isFinite(ua)) { + /* + * Should only happen if lines are parallel, which shouldn't happen! Unless, perhaps the + * polygon has zero extent vertically or horizontally ... ? + */ + throw RInternalError.shouldNotReachHere("polygon edge not found (zero-width or zero-height?)"); + } + /* + * numb = ((x2 - x1)*(y1 - y3) - (y2 - y1)*(x1 - x3)); ub = numb/denom; + */ + return new Point(xm + ua * (x2 - xm), ym + ua * (y2 - ym)); + } + + /** + * An arbitrarily-oriented rectangle. The vertices are assumed to be in order going + * anticlockwise around the rectangle. + */ + public static final class Rectangle { + public final double[] x; + public final double[] y; + + Rectangle(Point p1, Point p2, Point p3, Point p4) { + x = new double[]{p1.x, p2.x, p3.x, p4.x}; + y = new double[]{p1.y, p2.y, p3.y, p4.y}; + } + + public boolean intersects(Rectangle r2) { + return edgesIntersect(this.x[0], this.x[1], this.y[0], this.y[1], r2) || + edgesIntersect(this.x[1], this.x[2], this.y[1], this.y[2], r2) || + edgesIntersect(this.x[2], this.x[3], this.y[2], this.y[3], r2) || + edgesIntersect(this.x[3], this.x[0], this.y[3], this.y[0], r2); + } + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..5863de72a47db700e3e773967266d68c1312da39 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/FastRGridExternalLookup.java @@ -0,0 +1,151 @@ +/* + * 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; + +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; +import com.oracle.truffle.r.nodes.builtin.RInternalCodeBuiltinNode; +import com.oracle.truffle.r.runtime.RInternalCode; +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RNull; + +/** + * Implements the lookup for externals replaced by the FastR grid package. + */ +public class FastRGridExternalLookup { + + public static RExternalBuiltinNode lookupDotExternal(String name) { + switch (name) { + case "devholdflush": + return new IgnoredGridExternal(RNull.instance); + case "PDF": + return new IgnoredGridExternal(RNull.instance); + default: + return null; + } + } + + public static RExternalBuiltinNode lookupDotExternal2(String name) { + switch (name) { + case "C_par": + return new CPar(); + case "X11": + return new InitWindowedDevice(); + default: + return null; + } + } + + public static RExternalBuiltinNode lookupDotCall(String name) { + switch (name) { + case "L_gridDirty": + return new LGridDirty(); + case "L_initGrid": + return LInitGrid.create(); + case "L_newpage": + return new LNewPage(); + case "L_convert": + return LConvert.create(); + + // Viewport management + case "L_upviewport": + return LUpViewPort.create(); + case "L_initViewportStack": + return new LInitViewPortStack(); + case "L_unsetviewport": + return LUnsetViewPort.create(); + case "L_setviewport": + case "L_downviewport": + return getExternalFastRGridBuiltinNode(name); + + // Drawing primitives + case "L_rect": + return LRect.create(); + case "L_lines": + return LLines.create(); + case "L_polygon": + return LPolygon.create(); + case "L_text": + return LText.create(); + case "L_textBounds": + return LTextBounds.create(); + case "L_segments": + return LSegments.create(); + case "L_circle": + return LCircle.create(); + case "L_points": + return LPoints.create(); + + // Simple grid state access + case "L_getGPar": + return new GridStateGetNode(GridState::getGpar); + case "L_setGPar": + return GridStateSetNode.create((state, val) -> state.setGpar((RList) val)); + case "L_getCurrentGrob": + return new GridStateGetNode(GridState::getCurrentGrob); + case "L_setCurrentGrob": + return GridStateSetNode.create(GridState::setCurrentGrob); + case "L_currentViewport": + return new GridStateGetNode(GridState::getViewPort); + case "L_initGPar": + return new LInitGPar(); + + // Display list stuff: not implemented atm + case "L_getDisplayList": + return new IgnoredGridExternal(RDataFactory.createList()); + case "L_getDLindex": + return new IgnoredGridExternal(0); + case "L_getDLon": + case "L_getEngineDLon": + return new IgnoredGridExternal(RRuntime.LOGICAL_FALSE); + case "L_initDisplayList": + case "L_newpagerecording": + case "L_setDisplayList": + case "L_setDLelt": + case "L_setDLindex": + case "L_setDLon": + return new IgnoredGridExternal(RNull.instance); + + // These methods do not use graphics system or any global state. For now, + // we can re-use the native implementation, which in the future should be rewritten + // to managed code. + case "L_validUnits": + return null; + default: + if (name.startsWith("L_")) { + throw RInternalError.shouldNotReachHere("Unimplemented grid external " + name); + } else { + return null; + } + } + } + + private static RExternalBuiltinNode getExternalFastRGridBuiltinNode(String name) { + return new RInternalCodeBuiltinNode(RContext.getInstance(), "grid", RInternalCode.loadSourceRelativeTo(LInitGrid.class, "fastrGrid.R"), name); + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..41d785ee1fcffc9bfc4c4e39a4a719d10aadb226 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GPar.java @@ -0,0 +1,212 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +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 java.util.Arrays; + +import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext; +import com.oracle.truffle.r.library.fastrGrid.device.GridColor; +import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RNull; +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; + +/** + * 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. + */ +public final class GPar { + private static final int GP_FILL = 0; + private static final int GP_COL = 1; + private static final int GP_GAMMA = 2; + private static final int GP_LTY = 3; + private static final int GP_LWD = 4; + + /** + * Multiplier added to the final font size. + */ + private static final int GP_CEX = 5; + + /** + * Font size in points, however, the real font size will be this multiplied by {@link #GP_CEX}. + */ + private static final int GP_FONTSIZE = 6; + + /** + * Size of the line in terms of a multiply of "one line". The final real size of a line is + * fontsize*cex*lineheight. + */ + private static final int GP_LINEHEIGHT = 7; + private static final int GP_FONT = 8; + private static final int GP_FONTFAMILY = 9; + private static final int GP_ALPHA = 10; + private static final int GP_LINEEND = 11; + private static final int GP_LINEJOIN = 12; + private static final int GP_LINEMITRE = 13; + private static final int GP_LEX = 14; + private static final int GP_FONTFACE = 15; + private static final int GP_LENGTH = 16; + private static final String[] NAMES = new String[]{ + "fill", + "col", + "gamma", + "lty", + "lwd", + "cex", + "fontsize", + "lineheight", + "font", + "fontfamily", + "alpha", + "lineend", + "linejoin", + "linemitre", + "lex", + "fontface" // TODO: could not find this name in grid sources + }; + private static final RStringVector NAMES_VECTOR = (RStringVector) RDataFactory.createStringVector(NAMES, RDataFactory.COMPLETE_VECTOR).makeSharedPermanent(); + + public static RList createNew() { + Object[] data = new Object[GP_LENGTH]; + Arrays.fill(data, RNull.instance); + data[GP_FILL] = "transparent"; + data[GP_COL] = "black"; + data[GP_GAMMA] = newDoubleVec(0); + data[GP_LTY] = "solid"; + data[GP_LWD] = newDoubleVec(1); + data[GP_CEX] = newDoubleVec(1); + data[GP_FONTSIZE] = newDoubleVec(16); + data[GP_LINEHEIGHT] = newDoubleVec(1.2); + data[GP_FONT] = RDataFactory.createIntVectorFromScalar(1); // TODO: font constants? + data[GP_FONTFAMILY] = ""; // means default font (probably) + data[GP_ALPHA] = newDoubleVec(1); + data[GP_LINEEND] = "round"; + data[GP_LINEJOIN] = "round"; + data[GP_LINEMITRE] = newDoubleVec(10); + data[GP_LEX] = newDoubleVec(1); + return RDataFactory.createList(data, NAMES_VECTOR); + } + + 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 GParDrawingContext(RList list) { + data = list.getDataWithoutCopying(); + } + + @Override + public GridLineType getLineType() { + Object lty = data[GP_LTY]; + if (lty == null || lty == RNull.instance) { + return GridLineType.SOLID; + } + String name = RRuntime.asString(lty); + if (name != null) { + return lineTypeFromName(name); + } + RAbstractContainer ltyVec = asAbstractContainer(lty); + int num; + if (ltyVec.getLength() == 0) { + num = RRuntime.INT_NA; + } else if (ltyVec instanceof RAbstractDoubleVector) { + double realVal = ((RAbstractDoubleVector) ltyVec).getDataAt(0); + num = RRuntime.isNA(realVal) ? RRuntime.INT_NA : (int) realVal; + } else if (ltyVec instanceof RAbstractIntVector) { + num = ((RAbstractIntVector) ltyVec).getDataAt(0); + } else { + num = RRuntime.INT_NA; + } + + if (RRuntime.isNA(num)) { + throw RError.error(RError.NO_CALLER, Message.GENERIC, "Invalid line type."); + } + return GridLineType.fromInt(num); + } + + @Override + public GridColor getColor() { + 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]); + } + + @Override + public double getLineHeight() { + return asDouble(data[GP_LINEHEIGHT]); + } + + @Override + public GridColor getFillColor() { + 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])); + } + + private GridLineType lineTypeFromName(String name) { + switch (name) { + case "solid": + return GridLineType.SOLID; + case "dashed": + return GridLineType.DASHED; + case "dotted": + return GridLineType.DOTTED; + case "dotdashed": + return GridLineType.DOTDASHED; + case "longdash": + return GridLineType.LONGDASH; + case "twodash": + return GridLineType.TWODASH; + case "blank": + return GridLineType.BLANK; + default: + // TODO: implement hex digits as line style + throw RError.error(RError.NO_CALLER, Message.GENERIC, "Unexpected line type '" + name + "'."); + } + } + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridColorUtils.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridColorUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..1fc036ea84d2814955a45b3294f477d44dd81581 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridColorUtils.java @@ -0,0 +1,745 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (c) 1997-2014, The R Core Team + * Copyright (c) 2003, The R Foundation + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.library.fastrGrid; + +import java.util.HashMap; +import java.util.Locale; + +import com.oracle.truffle.r.library.fastrGrid.device.GridColor; +import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; + +public class GridColorUtils { + private static HashMap<String, Object> synonymToColor; + + /** + * Converts the representation of color used within R, e.g. as value for + * {@code gpar(col='value')}, to our internal representation that grid device should understand. + * The acceptable color formats are: name of known color, HTML style hex value, and HTML style + * hex value including alpha. + */ + public static GridColor gridColorFromString(String value) { + if (value.startsWith("#") && (value.length() == 7 || value.length() == 9)) { + return parseHex(value); + } + + Object result = findByName(value); + if (result == null) { + throw RError.error(RError.NO_CALLER, Message.GENERIC, "Invalid color '" + value + "'."); + } + if (result instanceof String) { + return parseHex((String) result); + } + assert result instanceof GridColor : "synonyms map should only contain Strings and GridColors"; + return (GridColor) result; + } + + public static String gridColorToRString(GridColor color) { + if (color.getAlpha() == GridColor.OPAQUE_ALPHA) { + return String.format("#%02x%02x%02x", color.getRed(), color.getGreen(), color.getBlue()); + } + return String.format("#%02x%02x%02x%02x", color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); + } + + private static GridColor parseHex(String value) { + // hex format, e.g. #ffffff + int red = Integer.parseInt(value.substring(1, 3), 16); + int green = Integer.parseInt(value.substring(3, 5), 16); + int blue = Integer.parseInt(value.substring(5, 7), 16); + int alpha = GridColor.OPAQUE_ALPHA; + if (value.length() == 9) { + alpha = Integer.parseInt(value.substring(7, 9), 16); + } + return new GridColor(red, green, blue, alpha); + } + + private static Object findByName(String synonym) { + if (synonymToColor == null) { + initialize(); + } + return synonymToColor.get(normalizeColorName(synonym)); + } + + // GnuR compares the user given color name to the dictionary ignoring spaces and case. We remove + // the spaces and make it lowercase and then use normal string comparison. + private static String normalizeColorName(String synonym) { + boolean isNormalized = true; + for (int i = 0; i < synonym.length(); i++) { + char c = synonym.charAt(i); + isNormalized &= (!Character.isAlphabetic(c) || Character.isLowerCase(c)) && c != ' '; + } + return isNormalized ? synonym : synonym.replace(" ", "").toLowerCase(Locale.ROOT); + } + + private static void initialize() { + synonymToColor = new HashMap<>(700); + synonymToColor.put("transparent", GridColor.TRANSPARENT); + synonymToColor.put("NA", GridColor.TRANSPARENT); + synonymToColor.put("white", "#FFFFFF"); + synonymToColor.put("aliceblue", "#F0F8FF"); + synonymToColor.put("antiquewhite", "#FAEBD7"); + synonymToColor.put("antiquewhite1", "#FFEFDB"); + synonymToColor.put("antiquewhite2", "#EEDFCC"); + synonymToColor.put("antiquewhite3", "#CDC0B0"); + synonymToColor.put("antiquewhite4", "#8B8378"); + synonymToColor.put("aquamarine", "#7FFFD4"); + synonymToColor.put("aquamarine1", "#7FFFD4"); + synonymToColor.put("aquamarine2", "#76EEC6"); + synonymToColor.put("aquamarine3", "#66CDAA"); + synonymToColor.put("aquamarine4", "#458B74"); + synonymToColor.put("azure", "#F0FFFF"); + synonymToColor.put("azure1", "#F0FFFF"); + synonymToColor.put("azure2", "#E0EEEE"); + synonymToColor.put("azure3", "#C1CDCD"); + synonymToColor.put("azure4", "#838B8B"); + synonymToColor.put("beige", "#F5F5DC"); + synonymToColor.put("bisque", "#FFE4C4"); + synonymToColor.put("bisque1", "#FFE4C4"); + synonymToColor.put("bisque2", "#EED5B7"); + synonymToColor.put("bisque3", "#CDB79E"); + synonymToColor.put("bisque4", "#8B7D6B"); + synonymToColor.put("black", "#000000"); + synonymToColor.put("blanchedalmond", "#FFEBCD"); + synonymToColor.put("blue", "#0000FF"); + synonymToColor.put("blue1", "#0000FF"); + synonymToColor.put("blue2", "#0000EE"); + synonymToColor.put("blue3", "#0000CD"); + synonymToColor.put("blue4", "#00008B"); + synonymToColor.put("blueviolet", "#8A2BE2"); + synonymToColor.put("brown", "#A52A2A"); + synonymToColor.put("brown1", "#FF4040"); + synonymToColor.put("brown2", "#EE3B3B"); + synonymToColor.put("brown3", "#CD3333"); + synonymToColor.put("brown4", "#8B2323"); + synonymToColor.put("burlywood", "#DEB887"); + synonymToColor.put("burlywood1", "#FFD39B"); + synonymToColor.put("burlywood2", "#EEC591"); + synonymToColor.put("burlywood3", "#CDAA7D"); + synonymToColor.put("burlywood4", "#8B7355"); + synonymToColor.put("cadetblue", "#5F9EA0"); + synonymToColor.put("cadetblue1", "#98F5FF"); + synonymToColor.put("cadetblue2", "#8EE5EE"); + synonymToColor.put("cadetblue3", "#7AC5CD"); + synonymToColor.put("cadetblue4", "#53868B"); + synonymToColor.put("chartreuse", "#7FFF00"); + synonymToColor.put("chartreuse1", "#7FFF00"); + synonymToColor.put("chartreuse2", "#76EE00"); + synonymToColor.put("chartreuse3", "#66CD00"); + synonymToColor.put("chartreuse4", "#458B00"); + synonymToColor.put("chocolate", "#D2691E"); + synonymToColor.put("chocolate1", "#FF7F24"); + synonymToColor.put("chocolate2", "#EE7621"); + synonymToColor.put("chocolate3", "#CD661D"); + synonymToColor.put("chocolate4", "#8B4513"); + synonymToColor.put("coral", "#FF7F50"); + synonymToColor.put("coral1", "#FF7256"); + synonymToColor.put("coral2", "#EE6A50"); + synonymToColor.put("coral3", "#CD5B45"); + synonymToColor.put("coral4", "#8B3E2F"); + synonymToColor.put("cornflowerblue", "#6495ED"); + synonymToColor.put("cornsilk", "#FFF8DC"); + synonymToColor.put("cornsilk1", "#FFF8DC"); + synonymToColor.put("cornsilk2", "#EEE8CD"); + synonymToColor.put("cornsilk3", "#CDC8B1"); + synonymToColor.put("cornsilk4", "#8B8878"); + synonymToColor.put("cyan", "#00FFFF"); + synonymToColor.put("cyan1", "#00FFFF"); + synonymToColor.put("cyan2", "#00EEEE"); + synonymToColor.put("cyan3", "#00CDCD"); + synonymToColor.put("cyan4", "#008B8B"); + synonymToColor.put("darkblue", "#00008B"); + synonymToColor.put("darkcyan", "#008B8B"); + synonymToColor.put("darkgoldenrod", "#B8860B"); + synonymToColor.put("darkgoldenrod1", "#FFB90F"); + synonymToColor.put("darkgoldenrod2", "#EEAD0E"); + synonymToColor.put("darkgoldenrod3", "#CD950C"); + synonymToColor.put("darkgoldenrod4", "#8B6508"); + synonymToColor.put("darkgray", "#A9A9A9"); + synonymToColor.put("darkgreen", "#006400"); + synonymToColor.put("darkgrey", "#A9A9A9"); + synonymToColor.put("darkkhaki", "#BDB76B"); + synonymToColor.put("darkmagenta", "#8B008B"); + synonymToColor.put("darkolivegreen", "#556B2F"); + synonymToColor.put("darkolivegreen1", "#CAFF70"); + synonymToColor.put("darkolivegreen2", "#BCEE68"); + synonymToColor.put("darkolivegreen3", "#A2CD5A"); + synonymToColor.put("darkolivegreen4", "#6E8B3D"); + synonymToColor.put("darkorange", "#FF8C00"); + synonymToColor.put("darkorange1", "#FF7F00"); + synonymToColor.put("darkorange2", "#EE7600"); + synonymToColor.put("darkorange3", "#CD6600"); + synonymToColor.put("darkorange4", "#8B4500"); + synonymToColor.put("darkorchid", "#9932CC"); + synonymToColor.put("darkorchid1", "#BF3EFF"); + synonymToColor.put("darkorchid2", "#B23AEE"); + synonymToColor.put("darkorchid3", "#9A32CD"); + synonymToColor.put("darkorchid4", "#68228B"); + synonymToColor.put("darkred", "#8B0000"); + synonymToColor.put("darksalmon", "#E9967A"); + synonymToColor.put("darkseagreen", "#8FBC8F"); + synonymToColor.put("darkseagreen1", "#C1FFC1"); + synonymToColor.put("darkseagreen2", "#B4EEB4"); + synonymToColor.put("darkseagreen3", "#9BCD9B"); + synonymToColor.put("darkseagreen4", "#698B69"); + synonymToColor.put("darkslateblue", "#483D8B"); + synonymToColor.put("darkslategray", "#2F4F4F"); + synonymToColor.put("darkslategray1", "#97FFFF"); + synonymToColor.put("darkslategray2", "#8DEEEE"); + synonymToColor.put("darkslategray3", "#79CDCD"); + synonymToColor.put("darkslategray4", "#528B8B"); + synonymToColor.put("darkslategrey", "#2F4F4F"); + synonymToColor.put("darkturquoise", "#00CED1"); + synonymToColor.put("darkviolet", "#9400D3"); + synonymToColor.put("deeppink", "#FF1493"); + synonymToColor.put("deeppink1", "#FF1493"); + synonymToColor.put("deeppink2", "#EE1289"); + synonymToColor.put("deeppink3", "#CD1076"); + synonymToColor.put("deeppink4", "#8B0A50"); + synonymToColor.put("deepskyblue", "#00BFFF"); + synonymToColor.put("deepskyblue1", "#00BFFF"); + synonymToColor.put("deepskyblue2", "#00B2EE"); + synonymToColor.put("deepskyblue3", "#009ACD"); + synonymToColor.put("deepskyblue4", "#00688B"); + synonymToColor.put("dimgray", "#696969"); + synonymToColor.put("dimgrey", "#696969"); + synonymToColor.put("dodgerblue", "#1E90FF"); + synonymToColor.put("dodgerblue1", "#1E90FF"); + synonymToColor.put("dodgerblue2", "#1C86EE"); + synonymToColor.put("dodgerblue3", "#1874CD"); + synonymToColor.put("dodgerblue4", "#104E8B"); + synonymToColor.put("firebrick", "#B22222"); + synonymToColor.put("firebrick1", "#FF3030"); + synonymToColor.put("firebrick2", "#EE2C2C"); + synonymToColor.put("firebrick3", "#CD2626"); + synonymToColor.put("firebrick4", "#8B1A1A"); + synonymToColor.put("floralwhite", "#FFFAF0"); + synonymToColor.put("forestgreen", "#228B22"); + synonymToColor.put("gainsboro", "#DCDCDC"); + synonymToColor.put("ghostwhite", "#F8F8FF"); + synonymToColor.put("gold", "#FFD700"); + synonymToColor.put("gold1", "#FFD700"); + synonymToColor.put("gold2", "#EEC900"); + synonymToColor.put("gold3", "#CDAD00"); + synonymToColor.put("gold4", "#8B7500"); + synonymToColor.put("goldenrod", "#DAA520"); + synonymToColor.put("goldenrod1", "#FFC125"); + synonymToColor.put("goldenrod2", "#EEB422"); + synonymToColor.put("goldenrod3", "#CD9B1D"); + synonymToColor.put("goldenrod4", "#8B6914"); + synonymToColor.put("gray", "#BEBEBE"); + synonymToColor.put("gray0", "#000000"); + synonymToColor.put("gray1", "#030303"); + synonymToColor.put("gray2", "#050505"); + synonymToColor.put("gray3", "#080808"); + synonymToColor.put("gray4", "#0A0A0A"); + synonymToColor.put("gray5", "#0D0D0D"); + synonymToColor.put("gray6", "#0F0F0F"); + synonymToColor.put("gray7", "#121212"); + synonymToColor.put("gray8", "#141414"); + synonymToColor.put("gray9", "#171717"); + synonymToColor.put("gray10", "#1A1A1A"); + synonymToColor.put("gray11", "#1C1C1C"); + synonymToColor.put("gray12", "#1F1F1F"); + synonymToColor.put("gray13", "#212121"); + synonymToColor.put("gray14", "#242424"); + synonymToColor.put("gray15", "#262626"); + synonymToColor.put("gray16", "#292929"); + synonymToColor.put("gray17", "#2B2B2B"); + synonymToColor.put("gray18", "#2E2E2E"); + synonymToColor.put("gray19", "#303030"); + synonymToColor.put("gray20", "#333333"); + synonymToColor.put("gray21", "#363636"); + synonymToColor.put("gray22", "#383838"); + synonymToColor.put("gray23", "#3B3B3B"); + synonymToColor.put("gray24", "#3D3D3D"); + synonymToColor.put("gray25", "#404040"); + synonymToColor.put("gray26", "#424242"); + synonymToColor.put("gray27", "#454545"); + synonymToColor.put("gray28", "#474747"); + synonymToColor.put("gray29", "#4A4A4A"); + synonymToColor.put("gray30", "#4D4D4D"); + synonymToColor.put("gray31", "#4F4F4F"); + synonymToColor.put("gray32", "#525252"); + synonymToColor.put("gray33", "#545454"); + synonymToColor.put("gray34", "#575757"); + synonymToColor.put("gray35", "#595959"); + synonymToColor.put("gray36", "#5C5C5C"); + synonymToColor.put("gray37", "#5E5E5E"); + synonymToColor.put("gray38", "#616161"); + synonymToColor.put("gray39", "#636363"); + synonymToColor.put("gray40", "#666666"); + synonymToColor.put("gray41", "#696969"); + synonymToColor.put("gray42", "#6B6B6B"); + synonymToColor.put("gray43", "#6E6E6E"); + synonymToColor.put("gray44", "#707070"); + synonymToColor.put("gray45", "#737373"); + synonymToColor.put("gray46", "#757575"); + synonymToColor.put("gray47", "#787878"); + synonymToColor.put("gray48", "#7A7A7A"); + synonymToColor.put("gray49", "#7D7D7D"); + synonymToColor.put("gray50", "#7F7F7F"); + synonymToColor.put("gray51", "#828282"); + synonymToColor.put("gray52", "#858585"); + synonymToColor.put("gray53", "#878787"); + synonymToColor.put("gray54", "#8A8A8A"); + synonymToColor.put("gray55", "#8C8C8C"); + synonymToColor.put("gray56", "#8F8F8F"); + synonymToColor.put("gray57", "#919191"); + synonymToColor.put("gray58", "#949494"); + synonymToColor.put("gray59", "#969696"); + synonymToColor.put("gray60", "#999999"); + synonymToColor.put("gray61", "#9C9C9C"); + synonymToColor.put("gray62", "#9E9E9E"); + synonymToColor.put("gray63", "#A1A1A1"); + synonymToColor.put("gray64", "#A3A3A3"); + synonymToColor.put("gray65", "#A6A6A6"); + synonymToColor.put("gray66", "#A8A8A8"); + synonymToColor.put("gray67", "#ABABAB"); + synonymToColor.put("gray68", "#ADADAD"); + synonymToColor.put("gray69", "#B0B0B0"); + synonymToColor.put("gray70", "#B3B3B3"); + synonymToColor.put("gray71", "#B5B5B5"); + synonymToColor.put("gray72", "#B8B8B8"); + synonymToColor.put("gray73", "#BABABA"); + synonymToColor.put("gray74", "#BDBDBD"); + synonymToColor.put("gray75", "#BFBFBF"); + synonymToColor.put("gray76", "#C2C2C2"); + synonymToColor.put("gray77", "#C4C4C4"); + synonymToColor.put("gray78", "#C7C7C7"); + synonymToColor.put("gray79", "#C9C9C9"); + synonymToColor.put("gray80", "#CCCCCC"); + synonymToColor.put("gray81", "#CFCFCF"); + synonymToColor.put("gray82", "#D1D1D1"); + synonymToColor.put("gray83", "#D4D4D4"); + synonymToColor.put("gray84", "#D6D6D6"); + synonymToColor.put("gray85", "#D9D9D9"); + synonymToColor.put("gray86", "#DBDBDB"); + synonymToColor.put("gray87", "#DEDEDE"); + synonymToColor.put("gray88", "#E0E0E0"); + synonymToColor.put("gray89", "#E3E3E3"); + synonymToColor.put("gray90", "#E5E5E5"); + synonymToColor.put("gray91", "#E8E8E8"); + synonymToColor.put("gray92", "#EBEBEB"); + synonymToColor.put("gray93", "#EDEDED"); + synonymToColor.put("gray94", "#F0F0F0"); + synonymToColor.put("gray95", "#F2F2F2"); + synonymToColor.put("gray96", "#F5F5F5"); + synonymToColor.put("gray97", "#F7F7F7"); + synonymToColor.put("gray98", "#FAFAFA"); + synonymToColor.put("gray99", "#FCFCFC"); + synonymToColor.put("gray100", "#FFFFFF"); + synonymToColor.put("green", "#00FF00"); + synonymToColor.put("green1", "#00FF00"); + synonymToColor.put("green2", "#00EE00"); + synonymToColor.put("green3", "#00CD00"); + synonymToColor.put("green4", "#008B00"); + synonymToColor.put("greenyellow", "#ADFF2F"); + synonymToColor.put("grey", "#BEBEBE"); + synonymToColor.put("grey0", "#000000"); + synonymToColor.put("grey1", "#030303"); + synonymToColor.put("grey2", "#050505"); + synonymToColor.put("grey3", "#080808"); + synonymToColor.put("grey4", "#0A0A0A"); + synonymToColor.put("grey5", "#0D0D0D"); + synonymToColor.put("grey6", "#0F0F0F"); + synonymToColor.put("grey7", "#121212"); + synonymToColor.put("grey8", "#141414"); + synonymToColor.put("grey9", "#171717"); + synonymToColor.put("grey10", "#1A1A1A"); + synonymToColor.put("grey11", "#1C1C1C"); + synonymToColor.put("grey12", "#1F1F1F"); + synonymToColor.put("grey13", "#212121"); + synonymToColor.put("grey14", "#242424"); + synonymToColor.put("grey15", "#262626"); + synonymToColor.put("grey16", "#292929"); + synonymToColor.put("grey17", "#2B2B2B"); + synonymToColor.put("grey18", "#2E2E2E"); + synonymToColor.put("grey19", "#303030"); + synonymToColor.put("grey20", "#333333"); + synonymToColor.put("grey21", "#363636"); + synonymToColor.put("grey22", "#383838"); + synonymToColor.put("grey23", "#3B3B3B"); + synonymToColor.put("grey24", "#3D3D3D"); + synonymToColor.put("grey25", "#404040"); + synonymToColor.put("grey26", "#424242"); + synonymToColor.put("grey27", "#454545"); + synonymToColor.put("grey28", "#474747"); + synonymToColor.put("grey29", "#4A4A4A"); + synonymToColor.put("grey30", "#4D4D4D"); + synonymToColor.put("grey31", "#4F4F4F"); + synonymToColor.put("grey32", "#525252"); + synonymToColor.put("grey33", "#545454"); + synonymToColor.put("grey34", "#575757"); + synonymToColor.put("grey35", "#595959"); + synonymToColor.put("grey36", "#5C5C5C"); + synonymToColor.put("grey37", "#5E5E5E"); + synonymToColor.put("grey38", "#616161"); + synonymToColor.put("grey39", "#636363"); + synonymToColor.put("grey40", "#666666"); + synonymToColor.put("grey41", "#696969"); + synonymToColor.put("grey42", "#6B6B6B"); + synonymToColor.put("grey43", "#6E6E6E"); + synonymToColor.put("grey44", "#707070"); + synonymToColor.put("grey45", "#737373"); + synonymToColor.put("grey46", "#757575"); + synonymToColor.put("grey47", "#787878"); + synonymToColor.put("grey48", "#7A7A7A"); + synonymToColor.put("grey49", "#7D7D7D"); + synonymToColor.put("grey50", "#7F7F7F"); + synonymToColor.put("grey51", "#828282"); + synonymToColor.put("grey52", "#858585"); + synonymToColor.put("grey53", "#878787"); + synonymToColor.put("grey54", "#8A8A8A"); + synonymToColor.put("grey55", "#8C8C8C"); + synonymToColor.put("grey56", "#8F8F8F"); + synonymToColor.put("grey57", "#919191"); + synonymToColor.put("grey58", "#949494"); + synonymToColor.put("grey59", "#969696"); + synonymToColor.put("grey60", "#999999"); + synonymToColor.put("grey61", "#9C9C9C"); + synonymToColor.put("grey62", "#9E9E9E"); + synonymToColor.put("grey63", "#A1A1A1"); + synonymToColor.put("grey64", "#A3A3A3"); + synonymToColor.put("grey65", "#A6A6A6"); + synonymToColor.put("grey66", "#A8A8A8"); + synonymToColor.put("grey67", "#ABABAB"); + synonymToColor.put("grey68", "#ADADAD"); + synonymToColor.put("grey69", "#B0B0B0"); + synonymToColor.put("grey70", "#B3B3B3"); + synonymToColor.put("grey71", "#B5B5B5"); + synonymToColor.put("grey72", "#B8B8B8"); + synonymToColor.put("grey73", "#BABABA"); + synonymToColor.put("grey74", "#BDBDBD"); + synonymToColor.put("grey75", "#BFBFBF"); + synonymToColor.put("grey76", "#C2C2C2"); + synonymToColor.put("grey77", "#C4C4C4"); + synonymToColor.put("grey78", "#C7C7C7"); + synonymToColor.put("grey79", "#C9C9C9"); + synonymToColor.put("grey80", "#CCCCCC"); + synonymToColor.put("grey81", "#CFCFCF"); + synonymToColor.put("grey82", "#D1D1D1"); + synonymToColor.put("grey83", "#D4D4D4"); + synonymToColor.put("grey84", "#D6D6D6"); + synonymToColor.put("grey85", "#D9D9D9"); + synonymToColor.put("grey86", "#DBDBDB"); + synonymToColor.put("grey87", "#DEDEDE"); + synonymToColor.put("grey88", "#E0E0E0"); + synonymToColor.put("grey89", "#E3E3E3"); + synonymToColor.put("grey90", "#E5E5E5"); + synonymToColor.put("grey91", "#E8E8E8"); + synonymToColor.put("grey92", "#EBEBEB"); + synonymToColor.put("grey93", "#EDEDED"); + synonymToColor.put("grey94", "#F0F0F0"); + synonymToColor.put("grey95", "#F2F2F2"); + synonymToColor.put("grey96", "#F5F5F5"); + synonymToColor.put("grey97", "#F7F7F7"); + synonymToColor.put("grey98", "#FAFAFA"); + synonymToColor.put("grey99", "#FCFCFC"); + synonymToColor.put("grey100", "#FFFFFF"); + synonymToColor.put("honeydew", "#F0FFF0"); + synonymToColor.put("honeydew1", "#F0FFF0"); + synonymToColor.put("honeydew2", "#E0EEE0"); + synonymToColor.put("honeydew3", "#C1CDC1"); + synonymToColor.put("honeydew4", "#838B83"); + synonymToColor.put("hotpink", "#FF69B4"); + synonymToColor.put("hotpink1", "#FF6EB4"); + synonymToColor.put("hotpink2", "#EE6AA7"); + synonymToColor.put("hotpink3", "#CD6090"); + synonymToColor.put("hotpink4", "#8B3A62"); + synonymToColor.put("indianred", "#CD5C5C"); + synonymToColor.put("indianred1", "#FF6A6A"); + synonymToColor.put("indianred2", "#EE6363"); + synonymToColor.put("indianred3", "#CD5555"); + synonymToColor.put("indianred4", "#8B3A3A"); + synonymToColor.put("ivory", "#FFFFF0"); + synonymToColor.put("ivory1", "#FFFFF0"); + synonymToColor.put("ivory2", "#EEEEE0"); + synonymToColor.put("ivory3", "#CDCDC1"); + synonymToColor.put("ivory4", "#8B8B83"); + synonymToColor.put("khaki", "#F0E68C"); + synonymToColor.put("khaki1", "#FFF68F"); + synonymToColor.put("khaki2", "#EEE685"); + synonymToColor.put("khaki3", "#CDC673"); + synonymToColor.put("khaki4", "#8B864E"); + synonymToColor.put("lavender", "#E6E6FA"); + synonymToColor.put("lavenderblush", "#FFF0F5"); + synonymToColor.put("lavenderblush1", "#FFF0F5"); + synonymToColor.put("lavenderblush2", "#EEE0E5"); + synonymToColor.put("lavenderblush3", "#CDC1C5"); + synonymToColor.put("lavenderblush4", "#8B8386"); + synonymToColor.put("lawngreen", "#7CFC00"); + synonymToColor.put("lemonchiffon", "#FFFACD"); + synonymToColor.put("lemonchiffon1", "#FFFACD"); + synonymToColor.put("lemonchiffon2", "#EEE9BF"); + synonymToColor.put("lemonchiffon3", "#CDC9A5"); + synonymToColor.put("lemonchiffon4", "#8B8970"); + synonymToColor.put("lightblue", "#ADD8E6"); + synonymToColor.put("lightblue1", "#BFEFFF"); + synonymToColor.put("lightblue2", "#B2DFEE"); + synonymToColor.put("lightblue3", "#9AC0CD"); + synonymToColor.put("lightblue4", "#68838B"); + synonymToColor.put("lightcoral", "#F08080"); + synonymToColor.put("lightcyan", "#E0FFFF"); + synonymToColor.put("lightcyan1", "#E0FFFF"); + synonymToColor.put("lightcyan2", "#D1EEEE"); + synonymToColor.put("lightcyan3", "#B4CDCD"); + synonymToColor.put("lightcyan4", "#7A8B8B"); + synonymToColor.put("lightgoldenrod", "#EEDD82"); + synonymToColor.put("lightgoldenrod1", "#FFEC8B"); + synonymToColor.put("lightgoldenrod2", "#EEDC82"); + synonymToColor.put("lightgoldenrod3", "#CDBE70"); + synonymToColor.put("lightgoldenrod4", "#8B814C"); + synonymToColor.put("lightgoldenrodyellow", "#FAFAD2"); + synonymToColor.put("lightgray", "#D3D3D3"); + synonymToColor.put("lightgreen", "#90EE90"); + synonymToColor.put("lightgrey", "#D3D3D3"); + synonymToColor.put("lightpink", "#FFB6C1"); + synonymToColor.put("lightpink1", "#FFAEB9"); + synonymToColor.put("lightpink2", "#EEA2AD"); + synonymToColor.put("lightpink3", "#CD8C95"); + synonymToColor.put("lightpink4", "#8B5F65"); + synonymToColor.put("lightsalmon", "#FFA07A"); + synonymToColor.put("lightsalmon1", "#FFA07A"); + synonymToColor.put("lightsalmon2", "#EE9572"); + synonymToColor.put("lightsalmon3", "#CD8162"); + synonymToColor.put("lightsalmon4", "#8B5742"); + synonymToColor.put("lightseagreen", "#20B2AA"); + synonymToColor.put("lightskyblue", "#87CEFA"); + synonymToColor.put("lightskyblue1", "#B0E2FF"); + synonymToColor.put("lightskyblue2", "#A4D3EE"); + synonymToColor.put("lightskyblue3", "#8DB6CD"); + synonymToColor.put("lightskyblue4", "#607B8B"); + synonymToColor.put("lightslateblue", "#8470FF"); + synonymToColor.put("lightslategray", "#778899"); + synonymToColor.put("lightslategrey", "#778899"); + synonymToColor.put("lightsteelblue", "#B0C4DE"); + synonymToColor.put("lightsteelblue1", "#CAE1FF"); + synonymToColor.put("lightsteelblue2", "#BCD2EE"); + synonymToColor.put("lightsteelblue3", "#A2B5CD"); + synonymToColor.put("lightsteelblue4", "#6E7B8B"); + synonymToColor.put("lightyellow", "#FFFFE0"); + synonymToColor.put("lightyellow1", "#FFFFE0"); + synonymToColor.put("lightyellow2", "#EEEED1"); + synonymToColor.put("lightyellow3", "#CDCDB4"); + synonymToColor.put("lightyellow4", "#8B8B7A"); + synonymToColor.put("limegreen", "#32CD32"); + synonymToColor.put("linen", "#FAF0E6"); + synonymToColor.put("magenta", "#FF00FF"); + synonymToColor.put("magenta1", "#FF00FF"); + synonymToColor.put("magenta2", "#EE00EE"); + synonymToColor.put("magenta3", "#CD00CD"); + synonymToColor.put("magenta4", "#8B008B"); + synonymToColor.put("maroon", "#B03060"); + synonymToColor.put("maroon1", "#FF34B3"); + synonymToColor.put("maroon2", "#EE30A7"); + synonymToColor.put("maroon3", "#CD2990"); + synonymToColor.put("maroon4", "#8B1C62"); + synonymToColor.put("mediumaquamarine", "#66CDAA"); + synonymToColor.put("mediumblue", "#0000CD"); + synonymToColor.put("mediumorchid", "#BA55D3"); + synonymToColor.put("mediumorchid1", "#E066FF"); + synonymToColor.put("mediumorchid2", "#D15FEE"); + synonymToColor.put("mediumorchid3", "#B452CD"); + synonymToColor.put("mediumorchid4", "#7A378B"); + synonymToColor.put("mediumpurple", "#9370DB"); + synonymToColor.put("mediumpurple1", "#AB82FF"); + synonymToColor.put("mediumpurple2", "#9F79EE"); + synonymToColor.put("mediumpurple3", "#8968CD"); + synonymToColor.put("mediumpurple4", "#5D478B"); + synonymToColor.put("mediumseagreen", "#3CB371"); + synonymToColor.put("mediumslateblue", "#7B68EE"); + synonymToColor.put("mediumspringgreen", "#00FA9A"); + synonymToColor.put("mediumturquoise", "#48D1CC"); + synonymToColor.put("mediumvioletred", "#C71585"); + synonymToColor.put("midnightblue", "#191970"); + synonymToColor.put("mintcream", "#F5FFFA"); + synonymToColor.put("mistyrose", "#FFE4E1"); + synonymToColor.put("mistyrose1", "#FFE4E1"); + synonymToColor.put("mistyrose2", "#EED5D2"); + synonymToColor.put("mistyrose3", "#CDB7B5"); + synonymToColor.put("mistyrose4", "#8B7D7B"); + synonymToColor.put("moccasin", "#FFE4B5"); + synonymToColor.put("navajowhite", "#FFDEAD"); + synonymToColor.put("navajowhite1", "#FFDEAD"); + synonymToColor.put("navajowhite2", "#EECFA1"); + synonymToColor.put("navajowhite3", "#CDB38B"); + synonymToColor.put("navajowhite4", "#8B795E"); + synonymToColor.put("navy", "#000080"); + synonymToColor.put("navyblue", "#000080"); + synonymToColor.put("oldlace", "#FDF5E6"); + synonymToColor.put("olivedrab", "#6B8E23"); + synonymToColor.put("olivedrab1", "#C0FF3E"); + synonymToColor.put("olivedrab2", "#B3EE3A"); + synonymToColor.put("olivedrab3", "#9ACD32"); + synonymToColor.put("olivedrab4", "#698B22"); + synonymToColor.put("orange", "#FFA500"); + synonymToColor.put("orange1", "#FFA500"); + synonymToColor.put("orange2", "#EE9A00"); + synonymToColor.put("orange3", "#CD8500"); + synonymToColor.put("orange4", "#8B5A00"); + synonymToColor.put("orangered", "#FF4500"); + synonymToColor.put("orangered1", "#FF4500"); + synonymToColor.put("orangered2", "#EE4000"); + synonymToColor.put("orangered3", "#CD3700"); + synonymToColor.put("orangered4", "#8B2500"); + synonymToColor.put("orchid", "#DA70D6"); + synonymToColor.put("orchid1", "#FF83FA"); + synonymToColor.put("orchid2", "#EE7AE9"); + synonymToColor.put("orchid3", "#CD69C9"); + synonymToColor.put("orchid4", "#8B4789"); + synonymToColor.put("palegoldenrod", "#EEE8AA"); + synonymToColor.put("palegreen", "#98FB98"); + synonymToColor.put("palegreen1", "#9AFF9A"); + synonymToColor.put("palegreen2", "#90EE90"); + synonymToColor.put("palegreen3", "#7CCD7C"); + synonymToColor.put("palegreen4", "#548B54"); + synonymToColor.put("paleturquoise", "#AFEEEE"); + synonymToColor.put("paleturquoise1", "#BBFFFF"); + synonymToColor.put("paleturquoise2", "#AEEEEE"); + synonymToColor.put("paleturquoise3", "#96CDCD"); + synonymToColor.put("paleturquoise4", "#668B8B"); + synonymToColor.put("palevioletred", "#DB7093"); + synonymToColor.put("palevioletred1", "#FF82AB"); + synonymToColor.put("palevioletred2", "#EE799F"); + synonymToColor.put("palevioletred3", "#CD6889"); + synonymToColor.put("palevioletred4", "#8B475D"); + synonymToColor.put("papayawhip", "#FFEFD5"); + synonymToColor.put("peachpuff", "#FFDAB9"); + synonymToColor.put("peachpuff1", "#FFDAB9"); + synonymToColor.put("peachpuff2", "#EECBAD"); + synonymToColor.put("peachpuff3", "#CDAF95"); + synonymToColor.put("peachpuff4", "#8B7765"); + synonymToColor.put("peru", "#CD853F"); + synonymToColor.put("pink", "#FFC0CB"); + synonymToColor.put("pink1", "#FFB5C5"); + synonymToColor.put("pink2", "#EEA9B8"); + synonymToColor.put("pink3", "#CD919E"); + synonymToColor.put("pink4", "#8B636C"); + synonymToColor.put("plum", "#DDA0DD"); + synonymToColor.put("plum1", "#FFBBFF"); + synonymToColor.put("plum2", "#EEAEEE"); + synonymToColor.put("plum3", "#CD96CD"); + synonymToColor.put("plum4", "#8B668B"); + synonymToColor.put("powderblue", "#B0E0E6"); + synonymToColor.put("purple", "#A020F0"); + synonymToColor.put("purple1", "#9B30FF"); + synonymToColor.put("purple2", "#912CEE"); + synonymToColor.put("purple3", "#7D26CD"); + synonymToColor.put("purple4", "#551A8B"); + synonymToColor.put("red", "#FF0000"); + synonymToColor.put("red1", "#FF0000"); + synonymToColor.put("red2", "#EE0000"); + synonymToColor.put("red3", "#CD0000"); + synonymToColor.put("red4", "#8B0000"); + synonymToColor.put("rosybrown", "#BC8F8F"); + synonymToColor.put("rosybrown1", "#FFC1C1"); + synonymToColor.put("rosybrown2", "#EEB4B4"); + synonymToColor.put("rosybrown3", "#CD9B9B"); + synonymToColor.put("rosybrown4", "#8B6969"); + synonymToColor.put("royalblue", "#4169E1"); + synonymToColor.put("royalblue1", "#4876FF"); + synonymToColor.put("royalblue2", "#436EEE"); + synonymToColor.put("royalblue3", "#3A5FCD"); + synonymToColor.put("royalblue4", "#27408B"); + synonymToColor.put("snewData.addlebrown", "#8B4513"); + synonymToColor.put("salmon", "#FA8072"); + synonymToColor.put("salmon1", "#FF8C69"); + synonymToColor.put("salmon2", "#EE8262"); + synonymToColor.put("salmon3", "#CD7054"); + synonymToColor.put("salmon4", "#8B4C39"); + synonymToColor.put("sandybrown", "#F4A460"); + synonymToColor.put("seagreen", "#2E8B57"); + synonymToColor.put("seagreen1", "#54FF9F"); + synonymToColor.put("seagreen2", "#4EEE94"); + synonymToColor.put("seagreen3", "#43CD80"); + synonymToColor.put("seagreen4", "#2E8B57"); + synonymToColor.put("seashell", "#FFF5EE"); + synonymToColor.put("seashell1", "#FFF5EE"); + synonymToColor.put("seashell2", "#EEE5DE"); + synonymToColor.put("seashell3", "#CDC5BF"); + synonymToColor.put("seashell4", "#8B8682"); + synonymToColor.put("sienna", "#A0522D"); + synonymToColor.put("sienna1", "#FF8247"); + synonymToColor.put("sienna2", "#EE7942"); + synonymToColor.put("sienna3", "#CD6839"); + synonymToColor.put("sienna4", "#8B4726"); + synonymToColor.put("skyblue", "#87CEEB"); + synonymToColor.put("skyblue1", "#87CEFF"); + synonymToColor.put("skyblue2", "#7EC0EE"); + synonymToColor.put("skyblue3", "#6CA6CD"); + synonymToColor.put("skyblue4", "#4A708B"); + synonymToColor.put("slateblue", "#6A5ACD"); + synonymToColor.put("slateblue1", "#836FFF"); + synonymToColor.put("slateblue2", "#7A67EE"); + synonymToColor.put("slateblue3", "#6959CD"); + synonymToColor.put("slateblue4", "#473C8B"); + synonymToColor.put("slategray", "#708090"); + synonymToColor.put("slategray1", "#C6E2FF"); + synonymToColor.put("slategray2", "#B9D3EE"); + synonymToColor.put("slategray3", "#9FB6CD"); + synonymToColor.put("slategray4", "#6C7B8B"); + synonymToColor.put("slategrey", "#708090"); + synonymToColor.put("snow", "#FFFAFA"); + synonymToColor.put("snow1", "#FFFAFA"); + synonymToColor.put("snow2", "#EEE9E9"); + synonymToColor.put("snow3", "#CDC9C9"); + synonymToColor.put("snow4", "#8B8989"); + synonymToColor.put("springgreen", "#00FF7F"); + synonymToColor.put("springgreen1", "#00FF7F"); + synonymToColor.put("springgreen2", "#00EE76"); + synonymToColor.put("springgreen3", "#00CD66"); + synonymToColor.put("springgreen4", "#008B45"); + synonymToColor.put("steelblue", "#4682B4"); + synonymToColor.put("steelblue1", "#63B8FF"); + synonymToColor.put("steelblue2", "#5CACEE"); + synonymToColor.put("steelblue3", "#4F94CD"); + synonymToColor.put("steelblue4", "#36648B"); + synonymToColor.put("tan", "#D2B48C"); + synonymToColor.put("tan1", "#FFA54F"); + synonymToColor.put("tan2", "#EE9A49"); + synonymToColor.put("tan3", "#CD853F"); + synonymToColor.put("tan4", "#8B5A2B"); + synonymToColor.put("thistle", "#D8BFD8"); + synonymToColor.put("thistle1", "#FFE1FF"); + synonymToColor.put("thistle2", "#EED2EE"); + synonymToColor.put("thistle3", "#CDB5CD"); + synonymToColor.put("thistle4", "#8B7B8B"); + synonymToColor.put("tomato", "#FF6347"); + synonymToColor.put("tomato1", "#FF6347"); + synonymToColor.put("tomato2", "#EE5C42"); + synonymToColor.put("tomato3", "#CD4F39"); + synonymToColor.put("tomato4", "#8B3626"); + synonymToColor.put("turquoise", "#40E0D0"); + synonymToColor.put("turquoise1", "#00F5FF"); + synonymToColor.put("turquoise2", "#00E5EE"); + synonymToColor.put("turquoise3", "#00C5CD"); + synonymToColor.put("turquoise4", "#00868B"); + synonymToColor.put("violet", "#EE82EE"); + synonymToColor.put("violetred", "#D02090"); + synonymToColor.put("violetred1", "#FF3E96"); + synonymToColor.put("violetred2", "#EE3A8C"); + synonymToColor.put("violetred3", "#CD3278"); + synonymToColor.put("violetred4", "#8B2252"); + synonymToColor.put("wheat", "#F5DEB3"); + synonymToColor.put("wheat1", "#FFE7BA"); + synonymToColor.put("wheat2", "#EED8AE"); + synonymToColor.put("wheat3", "#CDBA96"); + synonymToColor.put("wheat4", "#8B7E66"); + synonymToColor.put("whitesmoke", "#F5F5F5"); + synonymToColor.put("yellow", "#FFFF00"); + synonymToColor.put("yellow1", "#FFFF00"); + synonymToColor.put("yellow2", "#EEEE00"); + synonymToColor.put("yellow3", "#CDCD00"); + synonymToColor.put("yellow4", "#8B8B00"); + synonymToColor.put("yellowgreen", "#9ACD32"); + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..2980378933908efae26bb8a345024acd57714529 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridContext.java @@ -0,0 +1,50 @@ +/* + * 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; + +import com.oracle.truffle.r.library.fastrGrid.device.GridDevice; +import com.oracle.truffle.r.library.fastrGrid.device.JFrameDevice; + +/** + * Encapsulated the acces to the global grid state. + */ +public final class GridContext { + private static final GridContext INSTANCE = new GridContext(); + private final GridState gridState = new GridState(); + private GridDevice currentDevice; + + public static GridContext getContext() { + return INSTANCE; + } + + public GridState getGridState() { + return gridState; + } + + public GridDevice getCurrentDevice() { + if (currentDevice == null) { + currentDevice = new JFrameDevice(); + } + return currentDevice; + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..2cceaeb82a9845570abd46d2f9f3b9386e55d9de --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridLinesNode.java @@ -0,0 +1,125 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.library.fastrGrid; + +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.asIntVector; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.nodes.Node; +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.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; + +/** + * Common code shared between {@code L_lines} and {@code L_polygon} externals. Both draw a series of + * lines, but only the later connects the last point with the first point and only the former draws + * arrows (which is not implemented yet). Note: the third parameter contains sequences + * {@code 1:max(length(x),length(y))}, where the 'length' dispatches to S3 method giving us unit + * length like {@link com.oracle.truffle.r.library.fastrGrid.Unit.UnitLengthNode}. This means that + * we do not have to use the {@link com.oracle.truffle.r.library.fastrGrid.Unit.UnitLengthNode} to + * get the length. + */ +public abstract class GridLinesNode extends Node { + public static GridLinesNode createLines() { + return new GridLinesImpl(); + } + + public static GridLinesNode createPolygon() { + return new GridLinesPolygon(); + } + + @Child private Unit.UnitToInchesNode unitToInches = Unit.createToInchesNode(); + @Child private GetViewPortTransformNode getViewPortTransform = new GetViewPortTransformNode(); + @Child private DrawArrowsNode drawArrowsNode = new DrawArrowsNode(); + + @TruffleBoundary + void execute(RAbstractVector x, RAbstractVector y, RList lengths, RList arrow) { + GridContext ctx = GridContext.getContext(); + GridDevice dev = ctx.getCurrentDevice(); + + RList currentVP = ctx.getGridState().getViewPort(); + DrawingContext drawingCtx = GPar.asDrawingContext(ctx.getGridState().getGpar()); + ViewPortTransform vpTransform = getViewPortTransform.execute(currentVP, dev); + ViewPortContext vpContext = ViewPortContext.fromViewPort(currentVP); + UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, drawingCtx); + + // Convert the list of vectors of indexes to type-safe array and calculate the max length of + // the vectors. + RAbstractIntVector[] unitIndexesList = new RAbstractIntVector[lengths.getLength()]; + int maxIndexesLen = 0; + for (int i = 0; i < lengths.getLength(); i++) { + unitIndexesList[i] = asIntVector(lengths.getDataAt(i)); + maxIndexesLen = Math.max(maxIndexesLen, unitIndexesList[i].getLength()); + } + + double[] xx = new double[maxIndexesLen + 1]; // plus one for polygons + double[] yy = new double[maxIndexesLen + 1]; + for (RAbstractIntVector unitIndexes : unitIndexesList) { + boolean oldIsFinite = false; + int start = 0; + int unitIndexesLen = unitIndexes.getLength(); + // following loop finds series of valid points (finite x and y values) and draws each + // such series as a polyline + for (int i = 0; i < unitIndexesLen; i++) { + int unitIndex = unitIndexes.getDataAt(i) - 1; // coverting R's 1-based index + Point origLoc = Point.fromUnits(unitToInches, x, y, unitIndex, conversionCtx); + Point loc = TransformMatrix.transLocation(origLoc, vpTransform.transform); + xx[i] = loc.x; + yy[i] = loc.y; + boolean currIsFinite = loc.isFinite(); + boolean lastIter = i == (unitIndexesLen - 1); + if (currIsFinite && !oldIsFinite) { + start = i; // start a new series + } else if (oldIsFinite && (!currIsFinite || lastIter)) { + // draw the previous points series because + // (1) current is invalid point. Note: in (one of) the next iteration(s), the + // oldIsFinite will be false and we will update the start and start a new series + // (2) we are in the last iteration + if (lastIter || i - start > 1) { + // we draw only if the previous series of points was at least of length 3 or + // it's last iteration. This seems slightly weird, but that's how GnuR seems + // to work + drawPolylines(dev, drawingCtx, yy, xx, start, (i - start) + 1); + if (arrow != null) { + // Can draw an arrow at the start if the points include the first point. + // Draw an arrow at the end only if this is the last series + drawArrowsNode.drawArrows(xx, yy, start, (i - start) + 1, unitIndex, arrow, start == 0, lastIter, conversionCtx); + } + } + } + oldIsFinite = currIsFinite; + } + } + } + + abstract void drawPolylines(GridDevice dev, DrawingContext drawingCtx, double[] yy, double[] xx, int start, int length); + + private static final class GridLinesImpl extends GridLinesNode { + @Override + void drawPolylines(GridDevice dev, DrawingContext drawingCtx, double[] yy, double[] xx, int start, int length) { + dev.drawPolyLines(drawingCtx, xx, yy, start, length); + } + } + + private static final class GridLinesPolygon extends GridLinesNode { + @Override + void drawPolylines(GridDevice dev, DrawingContext drawingCtx, double[] yy, double[] xx, int start, int length) { + xx[start + length] = xx[start]; + yy[start + length] = yy[start]; + dev.drawPolyLines(drawingCtx, xx, yy, start, length + 1); + } + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..5d840cbf68fcdea0a1a4b761ee232408bc0d8824 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridState.java @@ -0,0 +1,95 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +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; +import com.oracle.truffle.r.runtime.env.REnvironment; + +public final class GridState { + private RList gpar; + private RList viewPort; + private REnvironment gridEnv; + private double scale = 1; + private boolean deviceInitialized; + + /** + * Current grob being drawn (for determining the list of grobs to search when evaluating a + * grobwidth/height unit via gPath). May be RNull or RList. + */ + private Object currentGrob; + + GridState() { + } + + public void init(REnvironment gridEnv, GridDevice currentDevice) { + this.gridEnv = gridEnv; + this.currentGrob = RNull.instance; + initGPar(currentDevice); + } + + void initGPar(GridDevice currentDevice) { + gpar = GPar.createNew(); + currentDevice.initDrawingContext(GPar.asDrawingContext(gpar)); + } + + public static DrawingContext getInitialGPar(GridDevice device) { + DrawingContext result = GPar.asDrawingContext(GPar.createNew()); + device.initDrawingContext(result); + return result; + } + + public RList getGpar() { + assert gridEnv != null : "GridState not initialized"; + return gpar; + } + + public void setGpar(RList gpar) { + assert gridEnv != null : "GridState not initialized"; + this.gpar = gpar; + } + + public boolean isDeviceInitialized() { + return deviceInitialized; + } + + public void setDeviceInitialized() { + this.deviceInitialized = true; + } + + public RList getViewPort() { + return viewPort; + } + + public void setViewPort(RList viewPort) { + this.viewPort = viewPort; + } + + public REnvironment getGridEnv() { + return gridEnv; + } + + public Object getCurrentGrob() { + return currentGrob; + } + + public void setCurrentGrob(Object currentGrob) { + this.currentGrob = currentGrob; + } + + public double getScale() { + return scale; + } + +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridStateGetNode.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridStateGetNode.java new file mode 100644 index 0000000000000000000000000000000000000000..9006431d6095d25d4a3a97ee0bb2e808565c1eed --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridStateGetNode.java @@ -0,0 +1,49 @@ +/* + * 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; + +import java.util.function.Function; + +import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; + +/** + * Gets a specified attribute of current {@link GridState}. + */ +class GridStateGetNode extends RExternalBuiltinNode.Arg0 { + private final Function<GridState, Object> getter; + + static { + Casts.noCasts(GridStateGetNode.class); + } + + GridStateGetNode(Function<GridState, Object> getter) { + this.getter = getter; + } + + @Override + public Object execute() { + Object result = getter.apply(GridContext.getContext().getGridState()); + assert result != null; + return result; + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridStateSetNode.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridStateSetNode.java new file mode 100644 index 0000000000000000000000000000000000000000..4b07fdcc38dcea0935898ab4c99f38c0a793df1a --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridStateSetNode.java @@ -0,0 +1,53 @@ +/* + * 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; + +import java.util.function.BiConsumer; + +import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; +import com.oracle.truffle.r.runtime.data.RNull; + +/** + * Sets a specified attribute of current {@link GridState}. + */ +public final class GridStateSetNode extends RExternalBuiltinNode.Arg1 { + private final BiConsumer<GridState, Object> setter; + + static { + Casts.noCasts(GridStateSetNode.class); + } + + public static GridStateSetNode create(BiConsumer<GridState, Object> setter) { + return new GridStateSetNode(setter); + } + + private GridStateSetNode(BiConsumer<GridState, Object> setter) { + this.setter = setter; + } + + @Override + public Object execute(Object arg) { + setter.accept(GridContext.getContext().getGridState(), arg); + return RNull.instance; + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..b9d862b0fb7964f21d3a5771acafb996586db78c --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridTextNode.java @@ -0,0 +1,254 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (c) 2001-2015, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.library.fastrGrid; + +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.fmax; +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.fmin; +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.getDataAtMod; +import static com.oracle.truffle.r.library.fastrGrid.TransformMatrix.multiply; +import static com.oracle.truffle.r.library.fastrGrid.TransformMatrix.transLocation; +import static com.oracle.truffle.r.library.fastrGrid.TransformMatrix.translation; +import static com.oracle.truffle.r.library.fastrGrid.device.DrawingContext.INCH_TO_POINTS_FACTOR; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVectorValue; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.profiles.ConditionProfile; +import com.oracle.truffle.r.library.fastrGrid.EdgeDetection.Rectangle; +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.NodeWithArgumentCasts.Casts; +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.nodes.RBaseNode; + +/** + * Implements what is in the original grid code implemented by {@code gridText} function. + * + * Note: the third parameter contains sequences {@code 1:max(length(x),length(y))}, where the + * 'length' dispatches to S3 method giving us unit length like {@link Unit.UnitLengthNode}. + */ +public final class GridTextNode extends RBaseNode { + @Child private Unit.UnitToInchesNode unitToInches = Unit.createToInchesNode(); + @Child private Unit.UnitLengthNode unitLength = Unit.createLengthNode(); + @Child private GetViewPortTransformNode getViewPortTransform = new GetViewPortTransformNode(); + + private final ConditionProfile checkOverlapProfile = ConditionProfile.createBinaryProfile(); + private final boolean draw; + + static void addGridTextCasts(Casts casts) { + casts.arg(0).asStringVector(); + casts.arg(1).mustBe(abstractVectorValue()); + casts.arg(2).mustBe(abstractVectorValue()); + casts.arg(3).mustBe(numericValue()).asDoubleVector(); + casts.arg(4).mustBe(numericValue()).asDoubleVector(); + casts.arg(5).mustBe(numericValue()).asDoubleVector(); + } + + private GridTextNode(boolean draw) { + this.draw = draw; + } + + public static GridTextNode createDraw() { + return new GridTextNode(true); + } + + public static GridTextNode createCalculateBounds() { + return new GridTextNode(false); + } + + @TruffleBoundary + public Object gridText(RAbstractStringVector textVec, RAbstractVector x, RAbstractVector y, RAbstractDoubleVector hjustVec, RAbstractDoubleVector vjustVec, RAbstractDoubleVector rotationVec, + boolean checkOverlapIn, double theta) { + if (textVec.getLength() == 0) { + return RNull.instance; + } + + boolean checkOverlap = checkOverlapProfile.profile(checkOverlapIn); + GridContext ctx = GridContext.getContext(); + GridDevice dev = ctx.getCurrentDevice(); + + RList currentVP = ctx.getGridState().getViewPort(); + DrawingContext drawingCtx = GPar.asDrawingContext(ctx.getGridState().getGpar()); + ViewPortTransform vpTransform = getViewPortTransform.execute(currentVP, dev); + ViewPortContext vpContext = ViewPortContext.fromViewPort(currentVP); + UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, drawingCtx); + + int length = GridUtils.maxLength(unitLength, x, y); + + // following variables will hold the (intermediate) results of bounds checking + int boundsCount = 0; + Point edge = null; + double xmin = Double.MAX_VALUE; + double xmax = Double.MIN_VALUE; + double ymin = Double.MAX_VALUE; + double ymax = Double.MIN_VALUE; + int ntxt = 0; // number of texts that were actually used for bounds computation + EdgeDetection.Rectangle[] bounds = null; + if (checkOverlap || !draw) { + bounds = new EdgeDetection.Rectangle[length]; + } + + for (int i = 0; i < length; i++) { + Point loc = Point.fromUnits(unitToInches, x, y, i, conversionCtx); + if (draw) { + // transformation not necessary for bounds calculation + loc = transLocation(loc, vpTransform.transform); + } + + String text = textVec.getDataAt(i % textVec.getLength()); + double hjust = getDataAtMod(hjustVec, i); + double vjust = getDataAtMod(vjustVec, i); + double rotation = getDataAtMod(rotationVec, i); + + // update bounds if necessary + boolean doDraw = true; + Rectangle trect = null; + if (checkOverlap || !draw) { + trect = textRect(loc, hjust, vjust, rotation, text, drawingCtx, dev); + for (int j = 0; j < boundsCount; j++) { + if (trect.intersects(bounds[j])) { + doDraw = false; + break; + } + } + if (doDraw) { + bounds[boundsCount++] = trect; + } + } + + // actual drawing + if (draw && doDraw) { + text(loc.x, loc.y, text, hjust, vjust, rotation, drawingCtx, dev); + } + + // or bounds checking + if (!draw) { + if (Double.isFinite(loc.x) && Double.isFinite(loc.y)) { + xmin = fmin(xmin, trect.x); + xmax = fmax(xmax, trect.x); + ymin = fmin(ymin, trect.y); + ymax = fmax(ymax, trect.y); + double[] xxx = new double[4]; + double[] yyy = new double[4]; + for (int j = 0; j < 4; j++) { + xxx[j] = trect.x[3 - j]; + yyy[j] = trect.y[3 - j]; + } + // Calculate edgex and edgey for case where this is the only rect + edge = EdgeDetection.polygonEdge(xxx, yyy, 4, theta); + ntxt++; + } + } + } + + if (!draw && ntxt > 0) { + // If there is more than one text, just produce edge based on bounding rect of all text + if (ntxt > 1) { + // Produce edge of rect bounding all text + edge = EdgeDetection.rectEdge(xmin, ymin, xmax, ymax, theta); + } + + double scale = GridContext.getContext().getGridState().getScale(); + double[] result = new double[4]; + result[0] = edge.x / scale; + result[1] = edge.y / scale; + result[2] = (xmax - xmin) / scale; + result[3] = (ymax - ymin) / scale; + return RDataFactory.createDoubleVector(result, RDataFactory.COMPLETE_VECTOR); + } + + // NULL is OK result even for bound checking if there was no text actually "drawn", the R + // wrapper deals with NULL in such case. For actual drawing case, we should always return + // NULL + return RNull.instance; + } + + // transcribed from utils.c + + private EdgeDetection.Rectangle textRect(Point loc, double xadj, double yadj, double rotation, String text, DrawingContext drawingCtx, GridDevice device) { + // TODO: for expressions the h and w are calculated differently + double h = device.getStringHeight(drawingCtx, text); + double w = device.getStringWidth(drawingCtx, text); + + double[][] thisJustification = translation(-xadj * w, -yadj * h); + double[][] thisRotation = TransformMatrix.rotation(rotation); + double[][] transform = multiply(multiply(thisJustification, thisRotation), translation(loc.x, loc.y)); + + Point bl = transLocation(new Point(0, 0), transform); + Point br = transLocation(new Point(w, 0), transform); + Point tr = transLocation(new Point(w, h), transform); + Point tl = transLocation(new Point(0, h), transform); + return new Rectangle(bl, br, tr, tl); + } + + // transcribed from engine.c + + private void text(double x, double y, String text, double xadjIn, double yadj, double rotation, DrawingContext drawingCtx, GridDevice device) { + if (!Double.isFinite(yadj)) { + throw RInternalError.unimplemented("'exact' vertical centering, see engine.c:1700"); + } + double xadj = Double.isFinite(xadjIn) ? xadjIn : 0.5; + + double radRotation = Math.toRadians(rotation); + double cosRot = Math.cos(radRotation); + double sinRot = Math.sin(radRotation); + String[] lines = text.split("\n"); + for (int lineIdx = 0; lineIdx < lines.length; lineIdx++) { + double xoff; + double yoff; + if (lines.length == 1) { + // simplification for single line + xoff = x; + yoff = y; + } else { + yoff = (1 - yadj) * (lines.length - 1) - lineIdx; + // TODO: in the original the following formula uses "dd->dev->cra[1]" + yoff *= (drawingCtx.getFontSize() * drawingCtx.getLineHeight()) / INCH_TO_POINTS_FACTOR; + xoff = -yoff * sinRot; + yoff = yoff * cosRot; + xoff = x + xoff; + yoff = y + yoff; + } + + double xleft = xoff; + double ybottom = yoff; + // now determine bottom-left for THIS line + if (xadj != 0.0 || yadj != 0.0) { + // otherwise simply the initial values for xleft and ybottom are OK + double width = device.getStringWidth(drawingCtx, lines[lineIdx]); + double height = device.getStringHeight(drawingCtx, lines[lineIdx]); + xleft = xoff - (xadj) * width * cosRot + yadj * height * sinRot; + ybottom = yoff - (xadj) * width * sinRot - yadj * height * cosRot; + } + + device.drawString(drawingCtx, xleft, ybottom, radRotation, lines[lineIdx]); + } + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..b57eaaa9942a29cb6a70e1ffdad36095a6c524cd --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridUtils.java @@ -0,0 +1,204 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.library.fastrGrid; + +import static com.oracle.truffle.r.runtime.nmath.RMath.fmax2; +import static com.oracle.truffle.r.runtime.nmath.RMath.fmin2; + +import com.oracle.truffle.api.nodes.ExplodeLoop; +import com.oracle.truffle.r.library.fastrGrid.Unit.UnitLengthNode; +import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; +import com.oracle.truffle.r.runtime.data.RAttributable; +import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RNull; +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.RAbstractVector; + +final class GridUtils { + private GridUtils() { + // only static members + } + + static double justify(double coord, double size, double justification) { + // justification is supposed to be either between 0 and 1 + return coord - size * justification; + } + + /** + * Returns the amount of justification required. I.e. transforms the justification from value + * between 0 and 1 to the value within size. + */ + static double justification(double size, double justification) { + return -size * justification; + } + + static double getDataAtMod(RAbstractDoubleVector vec, int idx) { + return vec.getDataAt(idx % vec.getLength()); + } + + static int getDataAtMod(RAbstractIntVector vec, int idx) { + return vec.getDataAt(idx % vec.getLength()); + } + + @ExplodeLoop + static int maxLength(UnitLengthNode unitLength, RAbstractVector... units) { + int result = 0; + for (RAbstractVector unit : units) { + result = Math.max(result, unitLength.execute(unit)); + } + return result; + } + + @ExplodeLoop + static double fmax(double firstVal, double... vals) { + double result = firstVal; + for (double val : vals) { + result = fmax2(result, val); + } + return result; + } + + @ExplodeLoop + static double fmin(double firstVal, double... vals) { + double result = firstVal; + for (double val : vals) { + result = fmin2(result, val); + } + return result; + } + + static boolean hasRClass(RAttributable obj, String clazz) { + RStringVector classAttr = obj.getClassAttr(); + if (classAttr == null) { + return false; + } + for (int i = 0; i < classAttr.getLength(); i++) { + if (classAttr.getDataAt(i).equals(clazz)) { + return true; + } + } + return false; + } + + static RList asListOrNull(Object value) { + if (value == null || value == RNull.instance) { + return null; + } + if (!(value instanceof RList)) { + throw RError.error(RError.NO_CALLER, Message.GENERIC, "Expected list"); + } + return (RList) value; + } + + static RList asList(Object value) { + if (!(value instanceof RList)) { + throw RError.error(RError.NO_CALLER, Message.GENERIC, "Expected list"); + } + return (RList) value; + } + + static double getDoubleAt(RAbstractVector vector, int index) { + if (vector instanceof RAbstractDoubleVector) { + return ((RAbstractDoubleVector) vector).getDataAt(index); + } else if (vector instanceof RAbstractIntVector) { + return ((RAbstractIntVector) vector).getDataAt(index); + } + throw RError.error(RError.NO_CALLER, Message.GENERIC, "Unexpected non double/integer value"); + } + + static double asDouble(Object val) { + if (val instanceof Double) { + return (double) val; + } else if (val instanceof RAbstractDoubleVector) { + if (((RAbstractDoubleVector) val).getLength() > 0) { + return ((RAbstractDoubleVector) val).getDataAt(0); + } + } else if (val instanceof Integer) { + return (int) val; + } else if (val instanceof RAbstractIntVector) { + if (((RAbstractIntVector) val).getLength() > 0) { + return ((RAbstractIntVector) val).getDataAt(0); + } + } + throw RError.error(RError.NO_CALLER, Message.GENERIC, "Unexpected non double/integer value " + val.getClass().getSimpleName()); + } + + static double asDouble(Object val, int cyclicIndex) { + if (val instanceof Double) { + return (int) val; + } else if (val instanceof RAbstractDoubleVector) { + RAbstractDoubleVector vec = (RAbstractDoubleVector) val; + if (vec.getLength() > 0) { + return vec.getDataAt(cyclicIndex % vec.getLength()); + } + } + throw RError.error(RError.NO_CALLER, Message.GENERIC, "Unexpected non double value " + val.getClass().getSimpleName()); + } + + static int asInt(Object val, int cyclicIndex) { + if (val instanceof Integer) { + return (int) val; + } else if (val instanceof RAbstractIntVector) { + RAbstractIntVector vec = (RAbstractIntVector) val; + if (vec.getLength() > 0) { + return vec.getDataAt(cyclicIndex % vec.getLength()); + } + } + throw RError.error(RError.NO_CALLER, Message.GENERIC, "Unexpected non integer value " + val.getClass().getSimpleName()); + } + + static RAbstractIntVector asIntVector(Object value) { + if (value instanceof Integer) { + return RDataFactory.createIntVectorFromScalar((Integer) value); + } else if (value instanceof RAbstractIntVector) { + return (RAbstractIntVector) value; + } + throw RError.error(RError.NO_CALLER, Message.GENERIC, "Unexpected non integer value " + value.getClass().getSimpleName()); + } + + public static RAbstractDoubleVector asDoubleVector(Object obj) { + if (obj instanceof Double) { + return RDataFactory.createDoubleVectorFromScalar((Double) obj); + } else if (obj instanceof RAbstractDoubleVector) { + return (RAbstractDoubleVector) obj; + } + throw RError.error(RError.NO_CALLER, Message.GENERIC, "Unexpected non double value " + obj.getClass().getSimpleName()); + } + + static RAbstractContainer asAbstractContainer(Object value) { + if (value instanceof Integer) { + return RDataFactory.createIntVectorFromScalar((Integer) value); + } else if (value instanceof Double) { + return RDataFactory.createDoubleVectorFromScalar((Double) value); + } else if (value instanceof RAbstractContainer) { + return (RAbstractContainer) value; + } + throw RError.error(RError.NO_CALLER, Message.GENERIC, "Unexpected non abstract container type " + value.getClass().getSimpleName()); + } + + static double sum(double[] values) { + return sum(values, 0, values.length); + } + + static double sum(double[] values, int from, int length) { + double result = 0; + for (int i = 0; i < length; i++) { + result += values[from + i]; + } + return result; + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/IgnoredGridExternal.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/IgnoredGridExternal.java new file mode 100644 index 0000000000000000000000000000000000000000..9166dac774a24138f1e6b6180d5f7713198ce9f0 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/IgnoredGridExternal.java @@ -0,0 +1,47 @@ +/* + * 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; + +import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; +import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; + +/** + * A node for externals that we ignore, becuase we do not need to implement them or because they + * support functionallity we do not implement yet, especially record/replay. + */ +class IgnoredGridExternal extends RExternalBuiltinNode { + private final Object result; + + static { + Casts.noCasts(IgnoredGridExternal.class); + } + + IgnoredGridExternal(Object result) { + this.result = result; + } + + @Override + protected Object call(RArgsValuesAndNames args) { + return result; + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..4d0183bf8f336f6a5c09ea215f8dca8686f8d445 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LCircle.java @@ -0,0 +1,66 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.library.fastrGrid; + +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVectorValue; + +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; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.nmath.RMath; + +public abstract class LCircle extends RExternalBuiltinNode.Arg3 { + @Child private Unit.UnitToInchesNode unitToInches = Unit.createToInchesNode(); + @Child private Unit.UnitLengthNode unitLength = Unit.createLengthNode(); + @Child private GetViewPortTransformNode getViewPortTransform = new GetViewPortTransformNode(); + + static { + Casts casts = new Casts(LCircle.class); + casts.arg(0).mustBe(abstractVectorValue()); + casts.arg(1).mustBe(abstractVectorValue()); + casts.arg(2).mustBe(abstractVectorValue()); + } + + public static LCircle create() { + return LCircleNodeGen.create(); + } + + @Specialization + @TruffleBoundary + Object doCircle(RAbstractVector xVec, RAbstractVector yVec, RAbstractVector radiusVec) { + GridContext ctx = GridContext.getContext(); + GridDevice dev = ctx.getCurrentDevice(); + + RList currentVP = ctx.getGridState().getViewPort(); + DrawingContext drawingCtx = GPar.asDrawingContext(ctx.getGridState().getGpar()); + ViewPortTransform vpTransform = getViewPortTransform.execute(currentVP, dev); + ViewPortContext vpContext = ViewPortContext.fromViewPort(currentVP); + UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, drawingCtx); + + int length = GridUtils.maxLength(unitLength, xVec, yVec, radiusVec); + for (int i = 0; i < length; i++) { + Size radiusSizes = Size.fromUnits(unitToInches, radiusVec, radiusVec, i, conversionCtx); + 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); + } + 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 new file mode 100644 index 0000000000000000000000000000000000000000..b2300de6ab6313762a0eb3b1d9296566b7af1655 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LConvert.java @@ -0,0 +1,157 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.library.fastrGrid; + +import static com.oracle.truffle.r.library.fastrGrid.Unit.NATIVE; +import static com.oracle.truffle.r.library.fastrGrid.Unit.NPC; +import static com.oracle.truffle.r.library.fastrGrid.Unit.isArithmeticUnit; +import static com.oracle.truffle.r.library.fastrGrid.Unit.isListUnit; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVectorValue; +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.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; +import com.oracle.truffle.r.runtime.data.RList; +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.RAbstractVector; + +public abstract class LConvert extends RExternalBuiltinNode.Arg4 { + @Child private Unit.UnitLengthNode unitLength = Unit.createLengthNode(); + @Child private Unit.UnitToInchesNode unitToInches = Unit.createToInchesNode(); + @Child private GetViewPortTransformNode getViewPortTransform = new GetViewPortTransformNode(); + + static { + Casts casts = new Casts(LConvert.class); + casts.arg(0).mustBe(abstractVectorValue()); + casts.arg(1).mustBe(numericValue()).asIntegerVector(); + casts.arg(2).mustBe(numericValue()).asIntegerVector(); + casts.arg(3).mustBe(numericValue()).asIntegerVector(); + } + + public static LConvert create() { + return LConvertNodeGen.create(); + } + + @Specialization + @TruffleBoundary + Object doConvert(RAbstractVector units, RAbstractIntVector axisFromVec, RAbstractIntVector axisToVec, RAbstractIntVector unitToVec) { + + GridContext ctx = GridContext.getContext(); + GridDevice dev = ctx.getCurrentDevice(); + + RList currentVP = ctx.getGridState().getViewPort(); + DrawingContext drawingCtx = GPar.asDrawingContext(ctx.getGridState().getGpar()); + ViewPortTransform vpTransform = getViewPortTransform.execute(currentVP, dev); + ViewPortContext vpContext = ViewPortContext.fromViewPort(currentVP); + UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, drawingCtx); + + int length = unitLength.execute(units); + double[] result = new double[length]; + + RAbstractIntVector unitIds = GridUtils.asIntVector(units.getAttr(Unit.VALID_UNIT_ATTR)); + boolean fromUnitIsSimple = !isArithmeticUnit(units) && !isListUnit(units); + + for (int i = 0; i < length; i++) { + // scalar values used in current iteration + AxisOrDimension axisFrom = AxisOrDimension.fromInt(axisFromVec.getDataAt(i % axisFromVec.getLength())); + AxisOrDimension axisTo = AxisOrDimension.fromInt(axisToVec.getDataAt(i % axisToVec.getLength())); + boolean compatibleAxes = axisFrom.isHorizontal() == axisTo.isHorizontal(); + double vpToSize = axisTo.isHorizontal() ? vpTransform.size.getWidth() : vpTransform.size.getHeight(); + double vpFromSize = axisFrom.isHorizontal() ? vpTransform.size.getWidth() : vpTransform.size.getHeight(); + int unitTo = unitToVec.getDataAt(i % unitToVec.getLength()); + int fromUnitId = unitIds.getDataAt(i % unitIds.getLength()); + + // actual conversion: + // if the units are both relative, we are converting compatible axes and the vpSize for + // 'from' axis is small, we will not convert through inches, but directly to avoid + // divide by zero, but still do something useful + boolean bothRelative = isRelative(unitTo) && isRelative(fromUnitId); + boolean realativeConversion = bothRelative && fromUnitIsSimple && compatibleAxes && vpFromSize < 1e-6; + if (realativeConversion) { + // if the unit is not "unit.arithmetic" or "unit.list", it must be double vector + RAbstractDoubleVector simpleUnits = (RAbstractDoubleVector) units; + double fromValue = simpleUnits.getDataAt(i % simpleUnits.getLength()); + result[i] = transformFromNPC(tranfromToNPC(fromValue, fromUnitId, axisFrom, vpContext), unitTo, axisTo, vpContext); + } else { + double inches = toInches(units, i, axisFrom, conversionCtx); + 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); + } + } + + return RDataFactory.createDoubleVector(result, RDataFactory.COMPLETE_VECTOR); + } + + private double toInches(RAbstractVector units, int index, AxisOrDimension axisFrom, UnitConversionContext conversionCtx) { + double inches; + if (axisFrom.isHorizontal()) { + if (axisFrom.isDimension()) { + inches = unitToInches.convertWidth(units, index, conversionCtx); + } else { + inches = unitToInches.convertX(units, index, conversionCtx); + } + } else { + if (axisFrom.isDimension()) { + inches = unitToInches.convertHeight(units, index, conversionCtx); + } else { + inches = unitToInches.convertY(units, index, conversionCtx); + } + } + return inches; + } + + private static double tranfromToNPC(double value, int fromUnitId, AxisOrDimension axisFrom, ViewPortContext vpContext) { + if (fromUnitId == Unit.NPC) { + return value; + } + assert fromUnitId == Unit.NATIVE : "relative conversion should only happen when units are NPC or NATIVE"; + boolean isX = axisFrom.isHorizontal(); + double min = isX ? vpContext.xscalemin : vpContext.yscalemin; + double max = isX ? vpContext.xscalemax : vpContext.yscalemax; + if (axisFrom.isDimension()) { + return value / (max - min); + } else { + return (value - min) / (max - min); + } + } + + private static double transformFromNPC(double value, int unitTo, AxisOrDimension axisTo, ViewPortContext vpContext) { + if (unitTo == Unit.NPC) { + return value; + } + assert unitTo == Unit.NATIVE : "relative conversion should only happen when units are NPC or NATIVE"; + boolean isX = axisTo.isHorizontal(); + double min = isX ? vpContext.xscalemin : vpContext.yscalemin; + double max = isX ? vpContext.xscalemax : vpContext.yscalemax; + if (axisTo.isDimension()) { + return value * (max - min); + } else { + return min + value * (max - min); + } + } + + // Note: this is not relative in the same sense as IsRelativeUnitNode. The later checks for + // special NULL unit used only in layouting. + private static boolean isRelative(int unitId) { + return unitId == NPC || unitId == NATIVE; + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LGridDirty.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LGridDirty.java new file mode 100644 index 0000000000000000000000000000000000000000..b385a6091ed9592cb32f2a445ad15b14c9617ed2 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LGridDirty.java @@ -0,0 +1,51 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.library.fastrGrid; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.profiles.ConditionProfile; +import com.oracle.truffle.r.library.fastrGrid.ViewPort.InitViewPortNode; +import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; +import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; +import com.oracle.truffle.r.runtime.data.RNull; + +class LGridDirty extends RExternalBuiltinNode { + @Child private InitViewPortNode initViewPort = new InitViewPortNode(); + private final ConditionProfile initViewPortProfile = ConditionProfile.createCountingProfile(); + + static { + Casts.noCasts(LGridDirty.class); + } + + @Override + public Object call(VirtualFrame frame, RArgsValuesAndNames args) { + GridState gridState = GridContext.getContext().getGridState(); + if (!gridState.isDeviceInitialized()) { + CompilerDirectives.transferToInterpreter(); + GridContext.getContext().getCurrentDevice().openNewPage(); + gridState.setDeviceInitialized(); + } + if (initViewPortProfile.profile(gridState.getViewPort() == null)) { + // this rarely happens, but we do not have a slow-path implementation (yet) + CompilerDirectives.transferToInterpreter(); + gridState.setViewPort(initViewPort.execute(frame)); + } + return RNull.instance; + } + + @Override + protected Object call(RArgsValuesAndNames args) { + // shadowed by the VirtualFrame overload + return null; + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LInitGPar.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LInitGPar.java new file mode 100644 index 0000000000000000000000000000000000000000..152aac26cd945fa35c96e2d2b567e96e78786c25 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LInitGPar.java @@ -0,0 +1,41 @@ +/* + * 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; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; +import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; +import com.oracle.truffle.r.runtime.data.RNull; + +class LInitGPar extends RExternalBuiltinNode { + static { + Casts.noCasts(LInitGPar.class); + } + + @Override + @TruffleBoundary + protected Object call(RArgsValuesAndNames args) { + GridContext.getContext().getGridState().initGPar(GridContext.getContext().getCurrentDevice()); + return RNull.instance; + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LInitGrid.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LInitGrid.java new file mode 100644 index 0000000000000000000000000000000000000000..885ace9762156ae4fba296ebb0e32a710ef8591d --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LInitGrid.java @@ -0,0 +1,37 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.library.fastrGrid; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.env.REnvironment; + +public abstract class LInitGrid extends RExternalBuiltinNode.Arg1 { + static { + Casts casts = new Casts(LInitGrid.class); + casts.arg(0).mustBe(REnvironment.class); + } + + public static LInitGrid create() { + return LInitGridNodeGen.create(); + } + + @Specialization + @TruffleBoundary + public Object doEnv(REnvironment gridEnv) { + GridContext context = GridContext.getContext(); + context.getGridState().init(gridEnv, context.getCurrentDevice()); + return RNull.instance; + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..82c23f06ae2e1d4bb9f76eff3c7c52e6aedac120 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LInitViewPortStack.java @@ -0,0 +1,38 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +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; +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; +import com.oracle.truffle.r.runtime.data.RNull; + +class LInitViewPortStack extends RExternalBuiltinNode { + @Child private InitViewPortNode initViewPortNode = new InitViewPortNode(); + static { + Casts.noCasts(LInitViewPortStack.class); + } + + @Override + public Object call(VirtualFrame frame, @SuppressWarnings("unused") RArgsValuesAndNames args) { + initViewPortNode.execute(frame); + return RNull.instance; + } + + @Override + protected Object call(RArgsValuesAndNames args) { + throw RInternalError.shouldNotReachHere("shadowed by the overload with VirtualFrame"); + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LLines.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LLines.java new file mode 100644 index 0000000000000000000000000000000000000000..e38149b8f1da4283dc5986c7e42032678fcc7b84 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LLines.java @@ -0,0 +1,59 @@ +/* + * 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; + +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVectorValue; + +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; + +public abstract class LLines extends RExternalBuiltinNode.Arg4 { + @Child private GridLinesNode gridLinesNode = GridLinesNode.createLines(); + + static { + Casts casts = new Casts(LLines.class); + casts.arg(0).mustBe(abstractVectorValue()); + casts.arg(1).mustBe(abstractVectorValue()); + casts.arg(2).mustBe(RList.class); + casts.arg(2).allowNull().mustBe(RList.class); + } + + public static LLines create() { + return LLinesNodeGen.create(); + } + + @Specialization + Object doLines(RAbstractVector x, RAbstractVector y, RList lengths, RNull arrowIgnored) { + gridLinesNode.execute(x, y, lengths, null); + return RNull.instance; + } + + @Specialization + Object doLines(RAbstractVector x, RAbstractVector y, RList lengths, @SuppressWarnings("unused") RList arrow) { + gridLinesNode.execute(x, y, lengths, arrow); + return RNull.instance; + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LNewPage.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LNewPage.java new file mode 100644 index 0000000000000000000000000000000000000000..19c7bc6bf6000f67e76e0599cf473fb6999f7c7f --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LNewPage.java @@ -0,0 +1,29 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.library.fastrGrid; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; +import com.oracle.truffle.r.runtime.data.RNull; + +class LNewPage extends RExternalBuiltinNode.Arg0 { + static { + Casts.noCasts(LNewPage.class); + } + + @Override + @TruffleBoundary + public Object execute() { + GridContext.getContext().getCurrentDevice().openNewPage(); + return RNull.instance; + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..fb8977b780450c1967a5dc81b0de4272ea14640a --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LPoints.java @@ -0,0 +1,142 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2015, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.library.fastrGrid; + +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVectorValue; +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.Unit.UnitConversionContext; +import com.oracle.truffle.r.library.fastrGrid.Unit.UnitLengthNode; +import com.oracle.truffle.r.library.fastrGrid.Unit.UnitToInchesNode; +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.GridColor; +import com.oracle.truffle.r.library.fastrGrid.device.GridDevice; +import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; +import com.oracle.truffle.r.runtime.RError.Message; +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; + +public abstract class LPoints extends RExternalBuiltinNode.Arg4 { + private static final double SMALL = 0.25; + private static final double RADIUS = 0.375; + private static final double SQRC = 0.88622692545275801364; /* sqrt(pi / 4) */ + private static final double DMDC = 1.25331413731550025119; /* sqrt(pi / 4) * sqrt(2) */ + private static final double TRC0 = 1.55512030155621416073; /* sqrt(4 * pi/(3 * sqrt(3))) */ + private static final double TRC1 = 1.34677368708859836060; /* TRC0 * sqrt(3) / 2 */ + private static final double TRC2 = 0.77756015077810708036; /* TRC0 / 2 */ + + @Child private GetViewPortTransformNode getViewPortTransform = new GetViewPortTransformNode(); + + @Child private UnitLengthNode unitLength = Unit.createLengthNode(); + @Child private UnitToInchesNode unitToInches = Unit.createToInchesNode(); + + static { + Casts casts = new Casts(LPoints.class); + casts.arg(0).mustBe(abstractVectorValue()); + casts.arg(1).mustBe(abstractVectorValue()); + casts.arg(2).mustBe(numericValue(), Message.GENERIC, "grid.points: pch argument not implemented for characters yet").asIntegerVector(); + casts.arg(3).mustBe(abstractVectorValue()); + } + + public static LPoints create() { + return LPointsNodeGen.create(); + } + + @Specialization + @TruffleBoundary + public Object doPoints(RAbstractVector xVec, RAbstractVector yVec, RAbstractIntVector pchVec, RAbstractVector sizeVec) { + GridContext ctx = GridContext.getContext(); + GridDevice dev = ctx.getCurrentDevice(); + + RList currentVP = ctx.getGridState().getViewPort(); + RList gpar = ctx.getGridState().getGpar(); + DrawingContext drawingCtx = GPar.asDrawingContext(gpar); + double cex = GPar.getCex(gpar); + ViewPortTransform vpTransform = getViewPortTransform.execute(currentVP, dev); + ViewPortContext vpContext = ViewPortContext.fromViewPort(currentVP); + UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, drawingCtx); + + // Note: unlike in other drawing primitives, we only consider length of x + int length = unitLength.execute(xVec); + 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); + } + } + return RNull.instance; + } + + // transcribed from engine.c function GESymbol + + private void drawSymbol(DrawingContext 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; + case 1: + drawOctahedron(drawingCtx, dev, GridColor.TRANSPARENT, size, x, y); + break; + case 16: + drawOctahedron(drawingCtx, dev, drawingCtx.getColor(), size, x, y); + break; + 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); + dev.drawCircle(drawingCtx, x, y, RADIUS * size); + drawingCtx.setFillColor(originalFill); + } + + private static void drawDot(DrawingContext drawingCtx, 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); + + /* + * 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, + * but only on low resolution devices where we can do nothing better. + * + * For this symbol only, size is cex (see engine.c). + * + * Prior to 2.1.0 the offsets were always 0.5. + */ + double xc = cex * 0.005; + double yc = cex * 0.005; + if (cex > 0 && xc < 0.5) { + xc = 0.5; + } + if (cex > 0 && yc < 0.5) { + yc = 0.5; + } + dev.drawRect(drawingCtx, x - xc, y - yc, x + xc, y + yc); + + drawingCtx.setColor(drawingCtx.getFillColor()); + drawingCtx.setFillColor(originalFill); + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LPolygon.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LPolygon.java new file mode 100644 index 0000000000000000000000000000000000000000..a4d8a917bd2bc2387d1faa7cb8b5026ee5fb37c3 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LPolygon.java @@ -0,0 +1,52 @@ +/* + * 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; + +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVectorValue; + +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; + +public abstract class LPolygon extends RExternalBuiltinNode.Arg3 { + @Child private GridLinesNode gridLinesNode = GridLinesNode.createPolygon(); + + static { + Casts casts = new Casts(LPolygon.class); + casts.arg(0).mustBe(abstractVectorValue()); + casts.arg(1).mustBe(abstractVectorValue()); + casts.arg(2).mustBe(RList.class); + } + + public static LPolygon create() { + return LPolygonNodeGen.create(); + } + + @Specialization + Object doLines(RAbstractVector x, RAbstractVector y, RList lengths) { + gridLinesNode.execute(x, y, lengths, null); + return RNull.instance; + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..a666b07edeab7b1d149f15aef7d7e945bdabf69e --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LRect.java @@ -0,0 +1,73 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.library.fastrGrid; + +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.getDataAtMod; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVectorValue; +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.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; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; + +public abstract class LRect extends RExternalBuiltinNode.Arg6 { + @Child private Unit.UnitToInchesNode unitToInches = Unit.createToInchesNode(); + @Child private Unit.UnitLengthNode unitLength = Unit.createLengthNode(); + @Child private GetViewPortTransformNode getViewPortTransform = new GetViewPortTransformNode(); + + static { + Casts casts = new Casts(LRect.class); + casts.arg(0).mustBe(abstractVectorValue()); + casts.arg(1).mustBe(abstractVectorValue()); + casts.arg(2).mustBe(abstractVectorValue()); + casts.arg(3).mustBe(abstractVectorValue()); + casts.arg(4).mustBe(numericValue()).asDoubleVector(); + casts.arg(5).mustBe(numericValue()).asDoubleVector(); + } + + public static LRect create() { + return LRectNodeGen.create(); + } + + @Specialization + @TruffleBoundary + public Object execute(RAbstractVector xVec, RAbstractVector yVec, RAbstractVector wVec, RAbstractVector hVec, RAbstractDoubleVector hjust, RAbstractDoubleVector vjust) { + GridContext ctx = GridContext.getContext(); + GridDevice dev = ctx.getCurrentDevice(); + + RList currentVP = ctx.getGridState().getViewPort(); + DrawingContext drawingCtx = GPar.asDrawingContext(ctx.getGridState().getGpar()); + ViewPortTransform vpTransform = getViewPortTransform.execute(currentVP, dev); + ViewPortContext vpContext = ViewPortContext.fromViewPort(currentVP); + UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, drawingCtx); + + int length = GridUtils.maxLength(unitLength, xVec, yVec, wVec, hVec); + for (int i = 0; i < length; i++) { + Size size = Size.fromUnits(unitToInches, wVec, hVec, i, conversionCtx); + // Note: once this is factored to drawing/recording: this transformation is necessary + // only for drawing + 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()); + } + 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 new file mode 100644 index 0000000000000000000000000000000000000000..1a3dda410ed2fef75fcde352584f3f42e18df404 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LSegments.java @@ -0,0 +1,87 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.library.fastrGrid; + +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVectorValue; + +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; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; + +/** + * Gets (vectors of) 4 coordinates (two points) and draws a line between them, unlike {@link LLines} + * which gets a vector of points and connects them all. + */ +public abstract class LSegments extends RExternalBuiltinNode.Arg5 { + @Child private Unit.UnitToInchesNode unitToInches = Unit.createToInchesNode(); + @Child private Unit.UnitLengthNode unitLength = Unit.createLengthNode(); + @Child private GetViewPortTransformNode getViewPortTransform = new GetViewPortTransformNode(); + @Child private DrawArrowsNode drawArrowsNode = new DrawArrowsNode(); + + static { + Casts casts = new Casts(LSegments.class); + casts.arg(0).mustBe(abstractVectorValue()); + casts.arg(1).mustBe(abstractVectorValue()); + casts.arg(2).mustBe(abstractVectorValue()); + casts.arg(3).mustBe(abstractVectorValue()); + casts.arg(4).allowNull().mustBe(RList.class); + } + + public static LSegments create() { + return LSegmentsNodeGen.create(); + } + + @Specialization + Object doSegments(RAbstractVector x0, RAbstractVector y0, RAbstractVector x1, RAbstractVector y1, RNull arrow) { + return doSegments(x0, y0, x1, y1, (RList) null); + } + + @Specialization + @TruffleBoundary + Object doSegments(RAbstractVector x0, RAbstractVector y0, RAbstractVector x1, RAbstractVector y1, RList arrow) { + GridContext ctx = GridContext.getContext(); + GridDevice dev = ctx.getCurrentDevice(); + + RList currentVP = ctx.getGridState().getViewPort(); + DrawingContext drawingCtx = GPar.asDrawingContext(ctx.getGridState().getGpar()); + ViewPortTransform vpTransform = getViewPortTransform.execute(currentVP, dev); + ViewPortContext vpContext = ViewPortContext.fromViewPort(currentVP); + UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, drawingCtx); + + int length = GridUtils.maxLength(unitLength, x0, y0, x1, y1); + double[] xx = new double[2]; + double[] yy = new double[2]; + for (int i = 0; i < length; i++) { + Point loc1 = TransformMatrix.transLocation(Point.fromUnits(unitToInches, x0, y0, i, conversionCtx), vpTransform.transform); + Point loc2 = TransformMatrix.transLocation(Point.fromUnits(unitToInches, x1, y1, i, conversionCtx), vpTransform.transform); + if (!loc1.isFinite() || !loc2.isFinite()) { + continue; + } + xx[0] = loc1.x; + xx[1] = loc2.x; + yy[0] = loc1.y; + yy[1] = loc2.y; + dev.drawPolyLines(drawingCtx, xx, yy, 0, 2); + if (arrow != null) { + drawArrowsNode.drawArrows(xx, yy, 0, 2, i, arrow, true, true, conversionCtx); + } + } + return RNull.instance; + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LText.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LText.java new file mode 100644 index 0000000000000000000000000000000000000000..c22cf068da8963e2ec89eaa5ba5c1778029b4705 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LText.java @@ -0,0 +1,55 @@ +/* + * 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; + +import static com.oracle.truffle.r.library.fastrGrid.GridTextNode.addGridTextCasts; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.logicalValue; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean; + +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.NodeCost; +import com.oracle.truffle.api.nodes.NodeInfo; +import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; +import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; + +@NodeInfo(cost = NodeCost.NONE) +public abstract class LText extends RExternalBuiltinNode.Arg7 { + static { + Casts casts = new Casts(LText.class); + addGridTextCasts(casts); + casts.arg(6).mustBe(logicalValue()).asLogicalVector().findFirst().map(toBoolean()); + } + + public static LText create() { + return LTextNodeGen.create(); + } + + @Specialization + Object drawText(RAbstractStringVector text, RAbstractVector x, RAbstractVector y, RAbstractDoubleVector hjust, RAbstractDoubleVector vjust, RAbstractDoubleVector rotation, boolean checkOverlap, + @Cached("createDraw()") GridTextNode gridText) { + return gridText.gridText(text, x, y, hjust, vjust, rotation, checkOverlap, 0); + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LTextBounds.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LTextBounds.java new file mode 100644 index 0000000000000000000000000000000000000000..fa1ec97d723de0ecc9ce446b956b9307558f32a5 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LTextBounds.java @@ -0,0 +1,56 @@ +/* + * 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; + +import static com.oracle.truffle.r.library.fastrGrid.GridTextNode.addGridTextCasts; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.constant; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.missingValue; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue; + +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.NodeCost; +import com.oracle.truffle.api.nodes.NodeInfo; +import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; +import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; + +@NodeInfo(cost = NodeCost.NONE) +public abstract class LTextBounds extends RExternalBuiltinNode.Arg7 { + static { + Casts casts = new Casts(LTextBounds.class); + addGridTextCasts(casts); + casts.arg(6).returnIf(missingValue().or(nullValue()), constant(0)).asDoubleVector().findFirst(); + } + + public static LTextBounds create() { + return LTextBoundsNodeGen.create(); + } + + @Specialization + public Object textBounds(RAbstractStringVector text, RAbstractVector x, RAbstractVector y, RAbstractDoubleVector hjust, RAbstractDoubleVector vjust, RAbstractDoubleVector rotation, double theta, + @Cached("createCalculateBounds()") GridTextNode gridText) { + return gridText.gridText(text, x, y, hjust, vjust, rotation, false, theta); + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LUnsetViewPort.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LUnsetViewPort.java new file mode 100644 index 0000000000000000000000000000000000000000..0416b1f6746b01de0853d2a0d1c465683f893660 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LUnsetViewPort.java @@ -0,0 +1,90 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.library.fastrGrid; + +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.asList; +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.asListOrNull; +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.device.GridDevice; +import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; +import com.oracle.truffle.r.runtime.RError.Message; +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.env.REnvironment; +import com.oracle.truffle.r.runtime.env.REnvironment.PutException; + +public abstract class LUnsetViewPort extends RExternalBuiltinNode.Arg1 { + @Child private DoSetViewPort doSetViewPort = new DoSetViewPort(); + + static { + Casts casts = new Casts(LUnsetViewPort.class); + casts.arg(0).mustBe(numericValue()).asIntegerVector().findFirst(); + } + + public static LUnsetViewPort create() { + return LUnsetViewPortNodeGen.create(); + } + + @Specialization + @TruffleBoundary + Object unsetViewPort(int n) { + GridContext ctx = GridContext.getContext(); + GridState gridState = ctx.getGridState(); + + // go n-steps up the view-port tree + RList gvp = gridState.getViewPort(); + RList newVp = gvp; + for (int i = 0; i < n; i++) { + gvp = newVp; + newVp = asListOrNull(gvp.getDataAt(ViewPort.PVP_PARENT)); + if (newVp == null) { + throw error(Message.GENERIC, "cannot pop the top-level viewport ('grid' and 'graphics' output mixed?)"); + } + } + + // gvp will be removed, newVp will be the new view-port + // first update children of newVp -> remove gvp + REnvironment children = (REnvironment) newVp.getDataAt(ViewPort.PVP_CHILDREN); + String gvpName = RRuntime.asString(gvp.getDataAt(ViewPort.VP_NAME)); + safeRemoveFromEnv(children, gvpName); + + // update newVp transform etc. because it will be the current vp, it has to be up to date + GridDevice device = ctx.getCurrentDevice(); + if (ViewPort.updateDeviceSizeInVP(newVp, device)) { + // Note: like in other places calling this, why incremental == true, given that the + // device has changed? Don't we want to recalculate the whole tree? + doSetViewPort.calcViewportTransform(newVp, newVp.getDataAt(ViewPort.PVP_PARENT), true, device, GridState.getInitialGPar(device)); + } + + gridState.setGpar(asList(newVp.getDataAt(ViewPort.PVP_GPAR))); + + // TODO: clipping + gridState.setViewPort(newVp); + + // remove the parent link from the old viewport + gvp.setDataAt(gvp.getInternalStore(), ViewPort.PVP_PARENT, null); + return RNull.instance; + } + + private void safeRemoveFromEnv(REnvironment children, String gvpName) { + try { + children.rm(gvpName); + } catch (PutException e) { + throw RInternalError.shouldNotReachHere("Cannot update view-port children environment"); + } + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LUpViewPort.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LUpViewPort.java new file mode 100644 index 0000000000000000000000000000000000000000..6e51c4b4d8704de111da056926b350af43c9c544 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LUpViewPort.java @@ -0,0 +1,50 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.library.fastrGrid; + +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.gte; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue; +import static com.oracle.truffle.r.nodes.builtin.casts.fluent.CastNodeBuilder.newCastBuilder; + +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; +import com.oracle.truffle.r.nodes.unary.CastNode; +import com.oracle.truffle.r.runtime.RError.Message; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RNull; + +public abstract class LUpViewPort extends RExternalBuiltinNode.Arg1 { + @Child private CastNode castParentToViewPort = newCastBuilder().mustBe(RList.class, Message.GENERIC, "cannot pop the top-level viewport ('grid' and 'graphics' output mixed?)").buildCastNode(); + + static { + Casts casts = new Casts(LUpViewPort.class); + casts.arg(0).mustBe(numericValue()).asIntegerVector().findFirst(1).mustBe(gte(1)); + } + + public static LUpViewPort create() { + return LUpViewPortNodeGen.create(); + } + + @Specialization + Object upViewPort(int n) { + GridState gridState = GridContext.getContext().getGridState(); + RList newViewPort = gridState.getViewPort(); + for (int i = 0; i < n; i++) { + newViewPort = (RList) castParentToViewPort.execute(newViewPort.getDataAt(ViewPort.PVP_PARENT)); + } + gridState.setViewPort(newViewPort); + + // TODO: device changed? => calcViewportTransform for newViewPort + // TODO: update the clipping region + return RNull.instance; + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/Point.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/Point.java new file mode 100644 index 0000000000000000000000000000000000000000..ba2c5135203ec29e6c547b259fdfa90c2a97de14 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/Point.java @@ -0,0 +1,55 @@ +/* + * 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; + +import com.oracle.truffle.r.library.fastrGrid.Unit.UnitConversionContext; +import com.oracle.truffle.r.library.fastrGrid.Unit.UnitToInchesNode; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; + +public final class Point { + final double x; + final double y; + + public Point(double x, double y) { + this.x = x; + this.y = y; + } + + public static Point fromUnits(UnitToInchesNode unitToInches, RAbstractVector x, RAbstractVector y, int index, UnitConversionContext ctx) { + double newX = unitToInches.convertX(x, index, ctx); + double newY = unitToInches.convertY(y, index, ctx); + return new Point(newX, newY); + } + + public Point justify(Size size, double hjust, double vjust) { + return justify(size.getWidth(), size.getHeight(), hjust, vjust); + } + + private Point justify(double width, double height, double hjust, double vjust) { + return new Point(GridUtils.justify(x, width, hjust), GridUtils.justify(y, height, vjust)); + } + + public boolean isFinite() { + return Double.isFinite(x) && Double.isFinite(y); + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/RGridCodeCall.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/RGridCodeCall.java new file mode 100644 index 0000000000000000000000000000000000000000..7f6b3f18ea44819d4211a01a8db831b8213bd8db --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/RGridCodeCall.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; + +import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.r.nodes.builtin.RInternalCodeBuiltinNode; +import com.oracle.truffle.r.runtime.ArgumentsSignature; +import com.oracle.truffle.r.runtime.RArguments; +import com.oracle.truffle.r.runtime.RInternalCode; +import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; +import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor; + +/** + * Allows to call arbitrary R function from {@code fastrGrid.R} source. + */ +class RGridCodeCall extends Node { + private static final FrameDescriptor emptyFrameDescriptor = new FrameDescriptor("<fastrGrid.R tmp frame>"); + @Child private RInternalCodeBuiltinNode child; + + RGridCodeCall(String functionName) { + child = new RInternalCodeBuiltinNode(RContext.getInstance(), "grid", RInternalCode.loadSourceRelativeTo(GPar.class, "fastrGrid.R"), functionName); + } + + static { + FrameSlotChangeMonitor.initializeFunctionFrameDescriptor("<fastrGrid.R tmp frame>", emptyFrameDescriptor); + } + + public Object call(Object arg1) { + return execute(new RArgsValuesAndNames(new Object[]{arg1}, ArgumentsSignature.empty(1))); + } + + public Object execute(RArgsValuesAndNames args) { + Object[] dummyFrameArgs = RArguments.createUnitialized(); + VirtualFrame dummyFrame = Truffle.getRuntime().createVirtualFrame(dummyFrameArgs, emptyFrameDescriptor); + return child.call(dummyFrame, args); + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/Size.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/Size.java new file mode 100644 index 0000000000000000000000000000000000000000..c428af3df6956bf7813712e41955f796e7d2e21f --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/Size.java @@ -0,0 +1,51 @@ +/* + * 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; + +import com.oracle.truffle.r.library.fastrGrid.Unit.UnitConversionContext; +import com.oracle.truffle.r.library.fastrGrid.Unit.UnitToInchesNode; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; + +public final class Size { + private final double width; + private final double height; + + public Size(double width, double height) { + this.width = width; + this.height = height; + } + + public static Size fromUnits(UnitToInchesNode unitToInches, RAbstractVector wVec, RAbstractVector hVec, int index, UnitConversionContext conversionCtx) { + double w = unitToInches.convertWidth(wVec, index, conversionCtx); + double h = unitToInches.convertHeight(hVec, index, conversionCtx); + return new Size(w, h); + } + + public double getWidth() { + return width; + } + + public double getHeight() { + return height; + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/TransformMatrix.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/TransformMatrix.java new file mode 100644 index 0000000000000000000000000000000000000000..e1051c98a46937db800261a3ea626a87c04061f9 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/TransformMatrix.java @@ -0,0 +1,118 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.library.fastrGrid; + +import static com.oracle.truffle.r.runtime.nmath.MathConstants.M_PI; + +/** + * Operations on transformation (3x3) matrices. + */ +final class TransformMatrix { + private TransformMatrix() { + // only static members + } + + static double[][] translation(double tx, double ty) { + double[][] m = identity(); + m[2][0] = tx; + m[2][1] = ty; + return m; + } + + static double[][] multiply(double[][] m1, double[][] m2) { + double[][] m = new double[3][3]; + m[0][0] = m1[0][0] * m2[0][0] + m1[0][1] * m2[1][0] + m1[0][2] * m2[2][0]; + m[0][1] = m1[0][0] * m2[0][1] + m1[0][1] * m2[1][1] + m1[0][2] * m2[2][1]; + m[0][2] = m1[0][0] * m2[0][2] + m1[0][1] * m2[1][2] + m1[0][2] * m2[2][2]; + m[1][0] = m1[1][0] * m2[0][0] + m1[1][1] * m2[1][0] + m1[1][2] * m2[2][0]; + m[1][1] = m1[1][0] * m2[0][1] + m1[1][1] * m2[1][1] + m1[1][2] * m2[2][1]; + m[1][2] = m1[1][0] * m2[0][2] + m1[1][1] * m2[1][2] + m1[1][2] * m2[2][2]; + m[2][0] = m1[2][0] * m2[0][0] + m1[2][1] * m2[1][0] + m1[2][2] * m2[2][0]; + m[2][1] = m1[2][0] * m2[0][1] + m1[2][1] * m2[1][1] + m1[2][2] * m2[2][1]; + m[2][2] = m1[2][0] * m2[0][2] + m1[2][1] * m2[1][2] + m1[2][2] * m2[2][2]; + return m; + } + + static double[][] rotation(double theta) { + double thetarad = theta / 180 * M_PI; + double costheta = Math.cos(thetarad); + double sintheta = Math.sin(thetarad); + double[][] result = identity(); + if (theta == 0) { + return result; + } + result[0][0] = costheta; + result[0][1] = sintheta; + result[1][0] = -sintheta; + result[1][1] = costheta; + return result; + } + + static double[][] identity() { + double[][] result = new double[3][3]; + result[0][0] = 1; + result[1][1] = 1; + result[2][2] = 1; + return result; + } + + private static double[] location(double x, double y) { + return new double[]{x, y, 1}; + } + + private static double[] transLocation(double[] location, double[][] m) { + double[] res = new double[3]; + res[0] = location[0] * m[0][0] + location[1] * m[1][0] + location[2] * m[2][0]; + res[1] = location[0] * m[0][1] + location[1] * m[1][1] + location[2] * m[2][1]; + res[2] = location[0] * m[0][2] + location[1] * m[1][2] + location[2] * m[2][2]; + return res; + } + + static Point transLocation(Point loc, double[][] m) { + double[] newLoc = transLocation(location(loc.x, loc.y), m); + return new Point(locationX(newLoc), locationY(newLoc)); + } + + private static double locationX(double[] loc) { + return loc[0]; + } + + private static double locationY(double[] loc) { + return loc[1]; + } + + /** + * Transforms the internal double matrix to R matrix flat array. + */ + static double[] flatten(double[][] m) { + double[] res = new double[9]; + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + res[i + j * 3] = m[i][j]; + } + } + return res; + } + + /** + * Reverse operation to {@link #flatten(double[][])}. + */ + static double[][] fromFlat(double[] flat) { + double[][] res = new double[3][3]; + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + res[i][j] = flat[i + j * 3]; + } + } + return res; + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..4cb343dfbff085c8f8d78422d5d458984d28a2da --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/Unit.java @@ -0,0 +1,657 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +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.asDoubleVector; +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.asIntVector; +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.asList; +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.asListOrNull; +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.fmax; +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.fmin; +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.getDataAtMod; +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.getDoubleAt; +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.hasRClass; +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.sum; +import static com.oracle.truffle.r.library.fastrGrid.device.DrawingContext.INCH_TO_POINTS_FACTOR; + +import java.util.function.BiFunction; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.r.library.fastrGrid.UnitFactory.UnitLengthNodeGen; +import com.oracle.truffle.r.library.fastrGrid.UnitFactory.UnitToInchesNodeGen; +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.helpers.InheritsCheckNode; +import com.oracle.truffle.r.runtime.ArgumentsSignature; +import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; +import com.oracle.truffle.r.runtime.data.RAttributable; +import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RDoubleVector; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RNull; +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.RAbstractLogicalVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.nodes.RBaseNode; + +/** + * Note: internally in FastR Grid everything is in inches. However, some lists that are exposed to + * the R code should contain values in centimeters, we convert such values immediatelly once they + * enter our system. + */ +public class Unit { + static final String VALID_UNIT_ATTR = "valid.unit"; + + public static final int NPC = 0; + private static final int CM = 1; + public static final int INCHES = 2; + private static final int LINES = 3; + public static final int NATIVE = 4; + private static final int NULL = 5; /* only used in layout specifications */ + private static final int SNPC = 6; + private static final int MM = 7; + /* + * Some units based on TeX's definition thereof + */ + private static final int POINTS = 8; /* 72.27 pt = 1 in */ + public static final int PICAS = 9; /* 1 pc = 12 pt */ + public static final int BIGPOINTS = 10; /* 72 bp = 1 in */ + public static final int DIDA = 11; /* 1157 dd = 1238 pt */ + public static final int CICERO = 12; /* 1 cc = 12 dd */ + public static final int SCALEDPOINTS = 13; /* 65536 sp = 1pt */ + /* + * Some units which require an object to query for a value. + */ + private static final int STRINGWIDTH = 14; + private static final int STRINGHEIGHT = 15; + public static final int STRINGASCENT = 16; + public static final int STRINGDESCENT = 17; + /* + * LINES now means multiples of the line height. This is multiples of the font size. + */ + private static final int CHAR = 18; + private static final int GROBX = 19; + private static final int GROBY = 20; + private static final int GROBWIDTH = 21; + private static final int GROBHEIGHT = 22; + public static final int GROBASCENT = 23; + private static final int GROBDESCENT = 24; + private static final int LAST_NORMAL_UNIT = GROBDESCENT; + /* + * No longer used + */ + private static final int MYLINES = 103; + private static final int MYCHAR = 104; + private static final int MYSTRINGWIDTH = 105; + private static final int MYSTRINGHEIGHT = 106; + + // null layout arithmetic mode + private static final int L_adding = 1; + private static final int L_subtracting = 2; + private static final int L_summing = 3; + private static final int L_plain = 4; + private static final int L_maximising = 5; + private static final int L_minimising = 6; + private static final int L_multiplying = 7; + + // attributes in the unit object and unit classes + private static final String UNIT_ATTR_DATA = "data"; + private static final String UNIT_ATTR_UNIT_ID = "valid.unit"; + private static final String UNIT_CLASS = "unit"; + private static final String UNIT_ARITHMETIC_CLASS = "unit.arithmetic"; + private static final String UNIT_LIST_CLASS = "unit.list"; + + private static final double CM_IN_INCH = 2.54; + + public static double inchesToCm(double inches) { + return inches * CM_IN_INCH; + } + + public static double cmToInches(double cm) { + return cm / CM_IN_INCH; + } + + public static RAbstractDoubleVector newUnit(double value, int unitId) { + assert unitId > 0 && unitId <= LAST_NORMAL_UNIT; + RDoubleVector result = RDataFactory.createDoubleVector(new double[]{value}, RDataFactory.COMPLETE_VECTOR); + result.setClassAttr(RDataFactory.createStringVectorFromScalar(UNIT_CLASS)); + result.setAttr(UNIT_ATTR_UNIT_ID, unitId); + result.setAttr(UNIT_ATTR_DATA, RNull.instance); + return result; + } + + public static UnitLengthNode createLengthNode() { + return UnitLengthNode.create(); + } + + public static UnitToInchesNode createToInchesNode() { + return UnitToInchesNode.create(); + } + + static double convertFromInches(double value, int unitId, double vpSize, double scalemin, double scalemax, boolean isDimension, DrawingContext drawingCtx) { + switch (unitId) { + case NATIVE: + double addition = isDimension ? 0 : scalemin; + return addition + (value / vpSize) * (scalemax - scalemin); + case NPC: + return value / vpSize; + case CM: + return value * CM_IN_INCH; + case MM: + return value * CM_IN_INCH * 10; + case INCHES: + return value; + case POINTS: + return value * INCH_TO_POINTS_FACTOR; + case LINES: + return (value * INCH_TO_POINTS_FACTOR) / (drawingCtx.getFontSize() * drawingCtx.getLineHeight()); + // following units are not supported even by original grid + case SNPC: + case MYCHAR: + case MYLINES: + case STRINGWIDTH: + case MYSTRINGWIDTH: + case STRINGHEIGHT: + case MYSTRINGHEIGHT: + case GROBX: + case GROBY: + case GROBWIDTH: + case GROBHEIGHT: + case NULL: + default: + throw RInternalError.unimplemented("unit type " + unitId + " in convertFromInches"); + } + } + + private static double convertToInches(double value, int unitId, RList data, UnitConversionContext ctx, AxisOrDimension axisOrDim) { + double vpSize = ctx.getViewPortSize(axisOrDim); + switch (unitId) { + case INCHES: + return value; + case NATIVE: + double tmp = axisOrDim.isDimension() ? value : (value - ctx.getScaleMin(axisOrDim)); + return (tmp / (ctx.getScaleMax(axisOrDim) - ctx.getScaleMin(axisOrDim))) * vpSize; + case NPC: + return value * vpSize; + case POINTS: + return value / INCH_TO_POINTS_FACTOR; + case CM: + return value / CM_IN_INCH; + case MM: + return value / (CM_IN_INCH * 10); + case CHAR: + case MYCHAR: + return (value * ctx.drawingContext.getFontSize()) / INCH_TO_POINTS_FACTOR; + case LINES: + case MYLINES: + return (value * ctx.drawingContext.getFontSize() * ctx.drawingContext.getLineHeight()) / INCH_TO_POINTS_FACTOR; + case STRINGWIDTH: + case MYSTRINGWIDTH: + return ctx.device.getStringWidth(ctx.drawingContext, RRuntime.asString(data.getDataAt(0))); + case STRINGHEIGHT: + case MYSTRINGHEIGHT: + return ctx.device.getStringHeight(ctx.drawingContext, RRuntime.asString(data.getDataAt(0))); + case NULL: + return evaluateNullUnit(value, vpSize, ctx.nullLayoutMode, ctx.nullArithmeticMode); + default: + throw RInternalError.unimplemented("unit type " + unitId + " in convertToInches"); + } + } + + private static double evaluateNullUnit(double value, double vpSize, int nullLMode, int nullAMode) { + if (nullLMode > 0) { + return value; + } + switch (nullAMode) { + case L_plain: + case L_adding: + case L_subtracting: + case L_summing: + case L_multiplying: + case L_maximising: + return 0; + case L_minimising: + return vpSize; // Note: GnuR has vpSize in "cm", so this will be in "cm" + // too, does it matter? + } + return value; + } + + static boolean isListUnit(Object unit) { + return unit instanceof RList && hasRClass((RAttributable) unit, UNIT_LIST_CLASS); + } + + static boolean isArithmeticUnit(Object unit) { + return unit instanceof RList && hasRClass((RAttributable) unit, UNIT_ARITHMETIC_CLASS); + } + + private static boolean isGrobUnit(int unitId) { + return unitId >= GROBX && unitId <= GROBDESCENT; + } + + static double pureNullUnitValue(RAbstractContainer unit, int index) { + // TODO: convert to unit visitor + if (unit instanceof RAbstractDoubleVector) { + RAbstractDoubleVector simpleUnit = (RAbstractDoubleVector) unit; + return simpleUnit.getDataAt(index % simpleUnit.getLength()); + } else if (isListUnit(unit)) { + return pureNullUnitValue((RAbstractContainer) ((RList) unit).getDataAt(index % unit.getLength()), 0); + } else if (isArithmeticUnit(unit)) { + ArithmeticUnit expr = ArithmeticUnit.asArithmeticUnit((RList) unit); + switch (expr.op) { + case "+": + return pureNullUnitValue(expr.arg1, index) + pureNullUnitValue(expr.arg2, index); + case "-": + return pureNullUnitValue(expr.arg1, index) - pureNullUnitValue(expr.arg2, index); + case "*": + return asDouble(expr.arg1) * pureNullUnitValue(expr.arg2, index); + case "min": + case "max": + case "sum": + double[] values = new double[expr.arg1.getLength()]; + for (int i = 0; i < values.length; i++) { + values[i] = pureNullUnitValue(expr.arg1, i); + } + switch (expr.op) { + case "min": + return fmin(Double.MAX_VALUE, values); + case "max": + return fmax(Double.MIN_VALUE, values); + case "sum": + return sum(values); + default: + throw RInternalError.shouldNotReachHere("unexpected arithmetic unit operation"); + } + } + + } + throw RInternalError.shouldNotReachHere("unexpected arithmetic unit type"); + } + + private static final class ArithmeticUnit { + public final String op; + public final RAbstractContainer arg1; + public final RAbstractContainer arg2; + + ArithmeticUnit(String op, RAbstractContainer arg1, RAbstractContainer arg2) { + this.op = op; + this.arg1 = arg1; + this.arg2 = arg2; + } + + static ArithmeticUnit asArithmeticUnit(RList unit) { + if (unit.getLength() <= 1) { + throw RError.error(RError.NO_CALLER, Message.GENERIC, "Invalid arithmetic unit (length <= 1)."); + } + // Note: the operator is usually of type character, however in the R code, grid compares + // it to symbols, e.g. `x`. Our implementation here should work with symbols too thanks + // to the asStringVector() conversion. + String op = RRuntime.asString(unit.getDataAt(0)); + RAbstractContainer arg1 = asAbstractContainer(unit.getDataAt(1)); + if (op.equals("+") || op.equals("-") || op.equals("*")) { + if (unit.getLength() != 3) { + throw RError.error(RError.NO_CALLER, Message.GENERIC, "Invalid arithmetic unit with binary operator and missing operand."); + } + return new ArithmeticUnit(op, arg1, asAbstractContainer(unit.getDataAt(2))); + } + if (op.equals("max") || op.equals("min") || op.equals("sum")) { + return new ArithmeticUnit(op, arg1, null); + } + throw RError.error(RError.NO_CALLER, Message.GENERIC, "Unexpected unit operator " + op); + } + + public boolean isBinary() { + return arg2 != null; + } + } + + abstract static class UnitNodeBase extends RBaseNode { + @Child private InheritsCheckNode inheritsArithmeticCheckNode = new InheritsCheckNode(UNIT_ARITHMETIC_CLASS); + @Child private InheritsCheckNode inheritsUnitListCheckNode = new InheritsCheckNode(UNIT_LIST_CLASS); + + boolean isSimple(Object obj) { + return !inheritsArithmeticCheckNode.execute(obj) && !inheritsUnitListCheckNode.execute(obj); + } + + boolean isArithmetic(Object obj) { + return inheritsArithmeticCheckNode.execute(obj); + } + + boolean isUnitList(Object obj) { + return inheritsUnitListCheckNode.execute(obj); + } + } + + public static final class IsRelativeUnitNode extends UnitNodeBase { + @Child private RGridCodeCall isPureNullCall = new RGridCodeCall("isPureNullUnit"); + + public boolean execute(Object unit, int index) { + // Note: converting 0-based java index to 1-based R index + Object result = isPureNullCall.execute(new RArgsValuesAndNames(new Object[]{unit, index + 1}, ArgumentsSignature.empty(2))); + byte resultByte; + if (result instanceof Byte) { + resultByte = (Byte) result; + } else if (result instanceof RAbstractLogicalVector) { + resultByte = ((RAbstractLogicalVector) result).getDataAt(0); + } else { + throw RInternalError.shouldNotReachHere("unexpected result type form isPuteNullUnit"); + } + return RRuntime.fromLogical(resultByte); + } + } + + /** + * Arithmetic unit objects can represent 'vectorized' expressions, in such case the 'length' is + * not simply the length of the underlying vector/list. + */ + public abstract static class UnitLengthNode extends UnitNodeBase { + public static UnitLengthNode create() { + return UnitLengthNodeGen.create(); + } + + public abstract int execute(RAbstractContainer vector); + + @Specialization(guards = "!isArithmetic(value)") + int doNormal(RAbstractContainer value) { + return value.getLength(); + } + + @Specialization(guards = "isArithmetic(list)") + int doArithmetic(RList list, + @Cached("create()") UnitLengthNode recursiveLen) { + ArithmeticUnit arithmeticUnit = ArithmeticUnit.asArithmeticUnit(list); + if (arithmeticUnit.isBinary()) { + return Math.max(recursiveLen.execute(arithmeticUnit.arg1), recursiveLen.execute(arithmeticUnit.arg2)); + } + return 1; // op is max, min, sum + } + } + + /** + * Used to discriminate between x axis, y axis, width, and height when doing unit conversions. + * The order should be the same as used in e.g. {@code L_convert}, which is 0 means x, 1 means + * y, 2 means width, 3 means height. + */ + public enum AxisOrDimension { + X, + Y, + WIDTH, + HEIGHT; + + private static final AxisOrDimension[] enumValues = values(); + + static AxisOrDimension fromInt(int value) { + assert value >= 0 && value < 4; + return enumValues[value]; + } + + public boolean isHorizontal() { + return this == X || this == WIDTH; + } + + public boolean isDimension() { + return this == WIDTH || this == HEIGHT; + } + } + + /** + * Wraps the data necessary for converting a unit to another unit. Note: {@code nullLMode} and + * {@code nullAMode} is only used for converting 'NULL' units and is only explicitly set when + * calculating layout. When e.g. drawing or calculating bounds, both should have default zero + * value. + */ + public static final class UnitConversionContext { + public final Size viewPortSize; + public final ViewPortContext viewPortContext; + public final DrawingContext drawingContext; + 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, DrawingContext drawingContext, int nullLMode, int nullAMode) { + this.viewPortSize = viewPortSize; + this.viewPortContext = viewPortContext; + this.device = device; + this.drawingContext = drawingContext; + this.nullLayoutMode = nullLMode; + this.nullArithmeticMode = nullAMode; + } + + public double getViewPortSize(AxisOrDimension forAxisOrDim) { + return forAxisOrDim.isHorizontal() ? viewPortSize.getWidth() : viewPortSize.getHeight(); + } + + public double getScaleMin(AxisOrDimension forAxisOrDim) { + return forAxisOrDim.isHorizontal() ? viewPortContext.xscalemin : viewPortContext.yscalemin; + } + + public double getScaleMax(AxisOrDimension forAxisOrDim) { + return forAxisOrDim.isHorizontal() ? viewPortContext.xscalemax : viewPortContext.yscalemax; + } + } + + /** + * Normalizes grid unit object to a double value in inches. For convenience the index is + * interpreted as cyclic. + */ + public abstract static class UnitToInchesNode extends UnitNodeBase { + @Child GrobUnitToInches grobUnitToInches; + + public static UnitToInchesNode create() { + return UnitToInchesNodeGen.create(); + } + + public double convertX(RAbstractContainer vector, int index, UnitConversionContext ctx) { + return execute(vector, index, ctx, AxisOrDimension.X); + } + + public double convertY(RAbstractContainer vector, int index, UnitConversionContext ctx) { + return execute(vector, index, ctx, AxisOrDimension.Y); + } + + public double convertWidth(RAbstractContainer vector, int index, UnitConversionContext ctx) { + return execute(vector, index, ctx, AxisOrDimension.WIDTH); + } + + public double convertHeight(RAbstractContainer vector, int index, UnitConversionContext ctx) { + return execute(vector, index, ctx, AxisOrDimension.HEIGHT); + } + + public double convertDimension(RAbstractContainer vector, int index, UnitConversionContext ctx, boolean isWidth) { + return isWidth ? convertWidth(vector, index, ctx) : convertHeight(vector, index, ctx); + } + + public abstract double execute(RAbstractContainer vector, int index, UnitConversionContext ctx, AxisOrDimension axisOrDim); + + @Specialization(guards = "isSimple(value)") + double doNormal(RAbstractVector value, int index, UnitConversionContext ctx, AxisOrDimension axisOrDim) { + int unitId = getDataAtMod(asIntVector(value.getAttr(UNIT_ATTR_UNIT_ID)), index); + double scalarValue = getDoubleAt(value, index % value.getLength()); + if (isGrobUnit(unitId)) { + 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); + } + + @Specialization(guards = "isUnitList(value)") + double doList(RList value, int index, UnitConversionContext ctx, AxisOrDimension axisOrDim, + @Cached("create()") UnitToInchesNode recursiveNode) { + Object unwrapped = value.getDataAt(index % value.getLength()); + if (unwrapped instanceof RAbstractVector) { + return recursiveNode.execute((RAbstractContainer) unwrapped, 0, ctx, axisOrDim); + } + throw error(Message.GENERIC, "Unexpected unit list with non-vector like element at index " + index); + } + + @Specialization(guards = "isArithmetic(list)") + double doArithmetic(RList list, int index, UnitConversionContext ctx, AxisOrDimension axisOrDim, + @Cached("create()") UnitLengthNode unitLengthNode, + @Cached("create()") UnitToInchesNode recursiveNode) { + ArithmeticUnit expr = ArithmeticUnit.asArithmeticUnit(list); + BiFunction<RAbstractContainer, Integer, Double> recursive = (x, newNullAMode) -> recursiveNode.execute(x, index, getNewCtx(ctx, axisOrDim, newNullAMode), axisOrDim); + switch (expr.op) { + case "+": + return recursive.apply(expr.arg1, L_adding) + recursive.apply(expr.arg2, L_adding); + case "-": + return recursive.apply(expr.arg1, L_subtracting) - recursive.apply(expr.arg2, L_subtracting); + case "*": + RAbstractDoubleVector left = asDoubleVector(expr.arg1); + return left.getDataAt(index % left.getLength()) * recursive.apply(expr.arg2, L_multiplying); + default: + break; + } + + // must be aggregate operation + UnitConversionContext newCtx = getNewCtx(ctx, axisOrDim, getNullAMode(expr.op)); + int len = unitLengthNode.execute(expr.arg1); + double[] values = new double[len]; + for (int i = 0; i < len; i++) { + values[i] = recursiveNode.execute(expr.arg1, i, newCtx, axisOrDim); + } + + switch (expr.op) { + case "min": + return GridUtils.fmin(Double.MAX_VALUE, values); + case "max": + return GridUtils.fmax(Double.MAX_VALUE, values); + case "sum": + return GridUtils.sum(values); + default: + throw RInternalError.shouldNotReachHere("The operation should have been validated in asArithmeticUnit method."); + } + } + + // 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, + axisOrDim.isDimension() ? newNullAMode : ctx.nullArithmeticMode); + } + + private static int getNullAMode(String op) { + switch (op) { + case "min": + return L_minimising; + case "max": + return L_maximising; + case "sum": + return L_summing; + } + return L_plain; + } + + private GrobUnitToInches getGrobUnitToInchesNode() { + if (grobUnitToInches == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + grobUnitToInches = insert(new GrobUnitToInches()); + } + return grobUnitToInches; + } + } + + public static final class GrobUnitToInches extends Node { + @Child private RGridCodeCall preDrawCode = new RGridCodeCall("grobConversionPreDraw"); + @Child private RGridCodeCall getUnitXY = new RGridCodeCall("grobConversionGetUnitXY"); + @Child private RGridCodeCall postDrawCode = new RGridCodeCall("grobConversionPostDraw"); + @Child private GetViewPortTransformNode getViewPortTransform = new GetViewPortTransformNode(); + + @Child private IsRelativeUnitNode isRelativeUnit = new IsRelativeUnitNode(); + @Child private UnitToInchesNode unitToInchesNode; + + // transcribed from unit.c function evaluateGrobUnit + + public double execute(double value, int unitId, Object grob, UnitConversionContext conversionCtx) { + GridContext ctx = GridContext.getContext(); + RList currentVP = ctx.getGridState().getViewPort(); + getViewPortTransform.execute(currentVP, conversionCtx.device); + + RList savedGPar = ctx.getGridState().getGpar(); + Object savedGrob = ctx.getGridState().getCurrentGrob(); + + Object updatedGrob = preDrawCode.call(grob); + + /* + * The call to preDraw may have pushed viewports and/or enforced gpar settings, SO we + * need to re-establish the current viewport and gpar settings before evaluating the + * width unit. + */ + currentVP = ctx.getGridState().getViewPort(); + RList currentGP = ctx.getGridState().getGpar(); + ViewPortTransform vpTransform = getViewPortTransform.execute(currentVP, conversionCtx.device); + ViewPortContext vpContext = ViewPortContext.fromViewPort(currentVP); + + // getUnitXY returns a list with either one or two items + RList unitxy = (RList) getUnitXY.execute(new RArgsValuesAndNames(new Object[]{updatedGrob, unitId}, ArgumentsSignature.empty(2))); + double result; + switch (unitId) { + case GROBX: + case GROBY: + if (unitId == GROBY && isRelativeUnit.execute(unitxy.getDataAt(1), 0)) { + double nullUnitValue = pureNullUnitValue((RAbstractContainer) unitxy.getDataAt(1), 0); + result = evaluateNullUnit(nullUnitValue, vpTransform.size.getHeight(), conversionCtx.nullLayoutMode, conversionCtx.nullArithmeticMode); + } else if (isRelativeUnit.execute(unitxy.getDataAt(0), 0)) { + double nullUnitValue = pureNullUnitValue((RAbstractContainer) unitxy.getDataAt(0), 0); + result = evaluateNullUnit(nullUnitValue, vpTransform.size.getWidth(), conversionCtx.nullLayoutMode, conversionCtx.nullArithmeticMode); + } else { + throw RInternalError.unimplemented("GrobUnitToInches from unit.c: 610"); + } + break; + default: + // should still be GROB_SOMETHING unit + if (isRelativeUnit.execute(unitxy.getDataAt(0), 0)) { + // Note: GnuR uses equivalent of vpTransform.size.getWidth() even for + // GROBHEIGHT, bug? + 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)); + initUnitToInchesNode(); + if (unitId == GROBWIDTH) { + result = unitToInchesNode.convertWidth((RAbstractContainer) unitxy.getDataAt(0), 0, newConversionCtx); + } else { + // Note: GnuR uses height transform for both grobascent, grobdescent and + // for height + result = unitToInchesNode.convertHeight((RAbstractContainer) unitxy.getDataAt(0), 0, newConversionCtx); + } + } + break; + } + + postDrawCode.call(updatedGrob); + ctx.getGridState().setGpar(savedGPar); + ctx.getGridState().setCurrentGrob(savedGrob); + return value * result; + } + + private void initUnitToInchesNode() { + if (unitToInchesNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + unitToInchesNode = UnitToInchesNode.create(); + } + } + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/ViewPort.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/ViewPort.java new file mode 100644 index 0000000000000000000000000000000000000000..99fdd428d3e57bfff7a6cff318801655d1b3fdb2 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/ViewPort.java @@ -0,0 +1,166 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.library.fastrGrid; + +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.asDouble; +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.asList; +import static com.oracle.truffle.r.library.fastrGrid.Unit.inchesToCm; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.r.library.fastrGrid.device.GridDevice; +import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode; +import com.oracle.truffle.r.nodes.function.call.RExplicitCallNode; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; +import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RFunction; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; + +/** + * There is a notion of a view point, which is an ordinary list that user creates to define a view + * port. One such list is pushed using {@code pushViewpoint} it is transformed to a 'pushed + * viewpoint', which is a copy of the original view point and it has some additional attributes. + */ +class ViewPort { + /* + * Structure of a viewport + */ + public static final int VP_X = 0; + public static final int VP_Y = 1; + public static final int VP_WIDTH = 2; + public static final int VP_HEIGHT = 3; + public static final int VP_JUST = 4; + public static final int VP_GP = 5; + public static final int VP_CLIP = 6; + public static final int VP_XSCALE = 7; + public static final int VP_YSCALE = 8; + public static final int VP_ANGLE = 9; + public static final int VP_LAYOUT = 10; + public static final int VP_LPOSROW = 11; + public static final int VP_LPOSCOL = 12; + public static final int VP_VALIDJUST = 13; + public static final int VP_VALIDLPOSROW = 14; + public static final int VP_VALIDLPOSCOL = 15; + public static final int VP_NAME = 16; + /* + * Additional structure of a pushedvp + */ + public static final int PVP_PARENTGPAR = 17; + public static final int PVP_GPAR = 18; + public static final int PVP_TRANS = 19; + public static final int PVP_WIDTHS = 20; + public static final int PVP_HEIGHTS = 21; + public static final int PVP_WIDTHCM = 22; + public static final int PVP_HEIGHTCM = 23; + public static final int PVP_ROTATION = 24; + public static final int PVP_CLIPRECT = 25; + public static final int PVP_PARENT = 26; + public static final int PVP_CHILDREN = 27; + public static final int PVP_DEVWIDTHCM = 28; + public static final int PVP_DEVHEIGHTCM = 29; + /* + * Structure of a layout + */ + private static final int LAYOUT_NROW = 0; + private static final int LAYOUT_NCOL = 1; + public static final int LAYOUT_WIDTHS = 2; + public static final int LAYOUT_HEIGHTS = 3; + public static final int LAYOUT_RESPECT = 4; + public static final int LAYOUT_VRESPECT = 5; + public static final int LAYOUT_MRESPECT = 6; + public static final int LAYOUT_JUST = 7; + private static final int LAYOUT_VJUST = 8; + + /** + * Updates the device size in the viewport and returns {@code true} if the size has changed. + */ + public static boolean updateDeviceSizeInVP(RList viewPort, GridDevice device) { + double devWidthCm = inchesToCm(device.getWidth()); + boolean result = false; + if (Math.abs(devWidthCm - asDouble(viewPort.getDataAt(PVP_DEVWIDTHCM))) >= 1e-6) { + viewPort.setDataAt(viewPort.getInternalStore(), PVP_DEVWIDTHCM, devWidthCm); + result = true; + } + double devHeightCm = inchesToCm(device.getHeight()); + if (Math.abs(devHeightCm - asDouble(viewPort.getDataAt(PVP_DEVHEIGHTCM))) >= 1e-6) { + viewPort.setDataAt(viewPort.getInternalStore(), PVP_DEVHEIGHTCM, devHeightCm); + } + return result; + } + + /** + * Represents the integer values extracted from {@link #LAYOUT_NCOL} and {@link #LAYOUT_NROW}. + * In the R world, RNulls are valid values for those, we convert them to -1 to keep type safety. + * The values should be interpreted as 0-based indexes. + */ + public static final class LayoutPos { + public final int colMin; + public final int colMax; + public final int rowMin; + public final int rowMax; + public final LayoutSize layoutSize; + + LayoutPos(int colMin, int colMax, int rowMin, int rowMax, LayoutSize layoutSize) { + this.colMin = colMin; + this.colMax = colMax; + this.rowMin = rowMin; + this.rowMax = rowMax; + this.layoutSize = layoutSize; + } + } + + /** + * The values should be interpreted as 0-based indexes. + */ + public static final class LayoutSize { + public final int ncol; + public final int nrow; + public final double hjust; + public final double vjust; + + private LayoutSize(int nrow, int ncol, double hjust, double vjust) { + this.ncol = ncol; + this.nrow = nrow; + this.hjust = hjust; + this.vjust = vjust; + } + + public static LayoutSize fromViewPort(RList vp) { + RList layout = asList(vp.getDataAt(ViewPort.VP_LAYOUT)); + int ncol = RRuntime.asInteger(layout.getDataAt(ViewPort.LAYOUT_NCOL)); + int nrow = RRuntime.asInteger(layout.getDataAt(ViewPort.LAYOUT_NROW)); + RAbstractDoubleVector just = (RAbstractDoubleVector) layout.getDataAt(ViewPort.LAYOUT_VJUST); + return new LayoutSize(nrow, ncol, just.getDataAt(0), just.getDataAt(1)); + } + } + + public static final class InitViewPortNode extends Node { + @Child private ReadVariableNode readGridTopLevel = ReadVariableNode.create("grid.top.level.vp"); + @Child private RExplicitCallNode callNode = RExplicitCallNode.create(); + @Child private DoSetViewPort doSetViewPort = new DoSetViewPort(); + + public RList execute(VirtualFrame frame) { + RFunction gridTopLevel = (RFunction) readGridTopLevel.execute(frame); + RList topVP = (RList) callNode.execute(frame, gridTopLevel, RArgsValuesAndNames.EMPTY); + + GridDevice device = GridContext.getContext().getCurrentDevice(); + // TODO: properly set the scale according to the current device + Object[] data = topVP.getDataWithoutCopying(); + data[ViewPort.VP_XSCALE] = RDataFactory.createDoubleVector(new double[]{0, device.getWidth()}, RDataFactory.COMPLETE_VECTOR); + data[ViewPort.VP_YSCALE] = RDataFactory.createDoubleVector(new double[]{0, device.getHeight()}, RDataFactory.COMPLETE_VECTOR); + data[ViewPort.PVP_GPAR] = GridContext.getContext().getGridState().getGpar(); + return doSetViewPort.doSetViewPort(topVP, false, true); + } + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/ViewPortContext.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/ViewPortContext.java new file mode 100644 index 0000000000000000000000000000000000000000..0eb93b84f92ae34ba54ddf944a0e867bb9bfde62 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/ViewPortContext.java @@ -0,0 +1,55 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.library.fastrGrid; + +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.asDoubleVector; + +import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; + +public final class ViewPortContext { + public double xscalemin; + public double yscalemin; + public double xscalemax; + public double yscalemax; + + private ViewPortContext() { + } + + public static ViewPortContext createDefault() { + ViewPortContext result = new ViewPortContext(); + result.xscalemin = 0; + result.yscalemin = 0; + result.xscalemax = 1; + result.yscalemax = 1; + return result; + } + + public static ViewPortContext fromViewPort(RList viewPort) { + ViewPortContext result = new ViewPortContext(); + RAbstractDoubleVector x = asDoubleVector(viewPort.getDataAt(ViewPort.VP_XSCALE)); + if (x.getLength() != 2) { + throw RError.error(RError.NO_CALLER, Message.GENERIC, "view-port xscale must be vector of size 2"); + } + result.xscalemin = x.getDataAt(0); + result.xscalemax = x.getDataAt(1); + RAbstractDoubleVector y = asDoubleVector(viewPort.getDataAt(ViewPort.VP_YSCALE)); + if (y.getLength() != 2) { + throw RError.error(RError.NO_CALLER, Message.GENERIC, "view-port yscale must be vector of size 2"); + } + result.yscalemin = y.getDataAt(0); + result.yscalemax = y.getDataAt(1); + return result; + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/ViewPortLocation.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/ViewPortLocation.java new file mode 100644 index 0000000000000000000000000000000000000000..2ea1a4d776efaa252721e8bcf1c58f6f81e81103 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/ViewPortLocation.java @@ -0,0 +1,49 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +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.asDoubleVector; + +import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; +import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; + +/** + * The vectors in this class represent a unit objects, therefore we cannot just have a double value + * for them. However, the unit object should contain only single value. + */ +public class ViewPortLocation { + public RAbstractContainer x; + public RAbstractContainer y; + public RAbstractContainer width; + public RAbstractContainer height; + public double hjust; + public double vjust; + + public static ViewPortLocation fromViewPort(RList viewPort) { + ViewPortLocation r = new ViewPortLocation(); + r.x = asAbstractContainer(viewPort.getDataAt(ViewPort.VP_X)); + r.y = asAbstractContainer(viewPort.getDataAt(ViewPort.VP_Y)); + r.width = asAbstractContainer(viewPort.getDataAt(ViewPort.VP_WIDTH)); + r.height = asAbstractContainer(viewPort.getDataAt(ViewPort.VP_HEIGHT)); + RAbstractDoubleVector just = asDoubleVector(viewPort.getDataAt(ViewPort.VP_VALIDJUST)); + if (just.getLength() != 2) { + throw RError.error(RError.NO_CALLER, Message.GENERIC, "Unexpected size of layout justification vector."); + } + r.hjust = just.getDataAt(0); + r.vjust = just.getDataAt(1); + return r; + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/ViewPortTransform.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/ViewPortTransform.java new file mode 100644 index 0000000000000000000000000000000000000000..0e8ea8aa082fd627a3857caa998e923d758989fc --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/ViewPortTransform.java @@ -0,0 +1,69 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.library.fastrGrid; + +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue; +import static com.oracle.truffle.r.nodes.builtin.casts.fluent.CastNodeBuilder.newCastBuilder; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.r.library.fastrGrid.device.GridDevice; +import com.oracle.truffle.r.nodes.unary.CastNode; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; + +/** + * Holds the data of a viewport needed to perform transformations. + */ +public final class ViewPortTransform { + private final double rotationAngle; + public final double[][] transform; + public final Size size; + + private ViewPortTransform(double width, double height, double rotationAngle, double[][] transform) { + this.size = new Size(width, height); + this.rotationAngle = rotationAngle; + this.transform = transform; + } + + public static final class GetViewPortTransformNode extends Node { + @Child private CastNode castDoubleVector = newCastBuilder().mustBe(numericValue()).asDoubleVector().buildCastNode(); + @Child private CastNode castScalarDouble = newCastBuilder().mustBe(numericValue()).asDoubleVector().findFirst().buildCastNode(); + @Child private DoSetViewPort doSetViewPort; + + public ViewPortTransform execute(RList viewPort, GridDevice device) { + if (ViewPort.updateDeviceSizeInVP(viewPort, device)) { + // Note: GnuR sets incremental parameter to true, but don't we need to recalculate + // the parent(s) as well? + initDoSetViewportNode(); + doSetViewPort.calcViewportTransform(viewPort, viewPort.getDataAt(ViewPort.PVP_PARENT), true, device, GridState.getInitialGPar(device)); + } + double width = Unit.cmToInches(getScalar(viewPort.getDataAt(ViewPort.PVP_WIDTHCM))); + double height = Unit.cmToInches(getScalar(viewPort.getDataAt(ViewPort.PVP_HEIGHTCM))); + double rotationAngle = getScalar(viewPort.getDataAt(ViewPort.VP_ANGLE)); + RAbstractDoubleVector trans = (RAbstractDoubleVector) castDoubleVector.execute(viewPort.getDataAt(ViewPort.PVP_TRANS)); + double[][] transform = TransformMatrix.fromFlat(trans.materialize().getDataWithoutCopying()); + return new ViewPortTransform(width, height, rotationAngle, transform); + } + + private void initDoSetViewportNode() { + if (doSetViewPort == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + doSetViewPort = new DoSetViewPort(); + } + } + + private double getScalar(Object value) { + return (double) castScalarDouble.execute(value); + } + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..f3d42fa703d922981c033f164f3970438fc96131 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/DrawingContext.java @@ -0,0 +1,80 @@ +/* + * 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; + +/** + * Defines parameters for drawing, like color, line style etc. + */ +public interface DrawingContext { + double INCH_TO_POINTS_FACTOR = 72.27; + + enum GridLineType { + // The order is important! + BLANK, + SOLID, + DASHED, + DOTTED, + DOTDASHED, + LONGDASH, + TWODASH; + + private static final int LINE_TYPES_COUNT = 7; + private static final GridLineType[] allValues = values(); + + public static GridLineType fromInt(int num) { + if (num == -1) { + return BLANK; + } + assert num >= 1; + return allValues[(num - 1) % LINE_TYPES_COUNT + 1]; + } + } + + GridLineType getLineType(); + + GridColor getColor(); + + /** + * Alows to set the color drawing color of shape borders, lines and text. + */ + void setColor(GridColor color); + + /** + * Gets the font size in points. + * + * @see #INCH_TO_POINTS_FACTOR + */ + double getFontSize(); + + /** + * Gets the height of a line in multiplies of the base line height. + */ + double getLineHeight(); + + GridColor getFillColor(); + + /** + * Alows to set the fill color of shapes. + */ + void setFillColor(GridColor color); +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..e4cdd7517aca69d5ef477e040ab81279f046e6b4 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/GridColor.java @@ -0,0 +1,58 @@ +/* + * 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; + +/** + * Simple color representation, so that the device interface does not have to depend on a specific + * GUI framework. + */ +public class GridColor { + public static final int OPAQUE_ALPHA = 0xff; + private static final int TRANSPARENT_ALPHA = 0; + public static final GridColor TRANSPARENT = new GridColor(0, 0, 0, TRANSPARENT_ALPHA); + + private final int value; + + public GridColor(int red, int green, int blue, int alpha) { + value = ((alpha & 0xFF) << 24) | + ((red & 0xFF) << 16) | + ((green & 0xFF) << 8) | + (blue & 0xFF); + } + + public int getRed() { + return (value >> 16) & 0xFF; + } + + public int getGreen() { + return (value >> 8) & 0xFF; + } + + public int getBlue() { + return value & 0xFF; + } + + public int getAlpha() { + return (value >> 24) & 0xff; + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..9e37a873bb46214d7035d2fefb13467cd7df174e --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/GridDevice.java @@ -0,0 +1,79 @@ +/* + * 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.INCH_TO_POINTS_FACTOR; + +/** + * Abstract device that can draw primitive shapes and text. All sizes and coordinates are specified + * in inches and angles in radians unless stated otherwise. + */ +public interface GridDevice { + void openNewPage(); + + void drawRect(DrawingContext ctx, double leftX, double topY, double width, double height); + + /** + * Connects given points with a line, there has to be at least two points in order to actually + * draw somethig. + */ + void drawPolyLines(DrawingContext ctx, double[] x, double[] y, int startIndex, int length); + + 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 + * wise, the centre of the rotation should be the bottom left corer. + */ + void drawString(DrawingContext ctx, double leftX, double bottomY, double rotationAnticlockWise, String text); + + /** + * @return The width of the device in inches. + */ + double getWidth(); + + /** + * @return The height of the device in inches. + */ + double getHeight(); + + /** + * May change the default values the of the initial drawing context instance. + * + * @param ctx instance of drawing context to be altered. + */ + default void initDrawingContext(DrawingContext ctx) { + // nop + } + + double getStringWidth(DrawingContext ctx, String text); + + /** + * Gets the height of a line of text in inches, the default implementation uses only the + * parameters from the drawing context, but we allow the device to override this calculation + * with something more precise. + */ + default double getStringHeight(DrawingContext ctx, @SuppressWarnings("unused") String text) { + return (ctx.getLineHeight() * ctx.getFontSize()) / INCH_TO_POINTS_FACTOR; + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..8821b8dd0f0d05d46e9d860e594b480aebe22065 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/JFrameDevice.java @@ -0,0 +1,262 @@ +/* + * 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.INCH_TO_POINTS_FACTOR; + +import java.awt.BasicStroke; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.HeadlessException; +import java.awt.Paint; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.Toolkit; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.geom.AffineTransform; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Path2D; +import java.awt.geom.Rectangle2D; +import java.util.function.Supplier; + +import javax.swing.JFrame; +import javax.swing.JPanel; + +import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext.GridLineType; +import com.oracle.truffle.r.runtime.RInternalError; + +public class JFrameDevice implements GridDevice { + // Grid's coordinate system has origin in left bottom corner and y axis grows from bottom to + // top. Moreover, the grid system uses inches as units. We use transformation to adjust the java + // coordinate system to the grid one. However, in the case of text rendering, we cannot simply + // turn upside down the y-axis, because the text would be upside down too, so for text rendering + // only, we reset the transformation completely and transform the coordinates ourselves + private static final double POINTS_IN_INCH = 72.; + + private static BasicStroke solidStroke; + private static BasicStroke blankStroke; + private static BasicStroke dashedStroke; + private static BasicStroke longdashedStroke; + private static BasicStroke twodashedStroke; + private static BasicStroke dotdashedStroke; + private static BasicStroke dottedStroke; + + private FastRFrame currentFrame; + private Graphics2D graphics; + + @Override + public void openNewPage() { + initStrokes(); + 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); + } else { + noTranform(() -> { + graphics.clearRect(0, 0, currentFrame.getWidth(), currentFrame.getHeight()); + return null; + }); + } + } + + @Override + public void drawRect(DrawingContext ctx, double leftX, double topY, double width, double height) { + setContext(ctx); + drawShape(ctx, new Rectangle2D.Double(leftX, topY, width, height)); + } + + @Override + public void drawPolyLines(DrawingContext ctx, double[] x, double[] y, int startIndex, int length) { + assert startIndex >= 0 && startIndex < x.length && startIndex < y.length : "startIndex out of bounds"; + assert length > 0 && (startIndex + length) <= Math.min(x.length, y.length) : "length out of bounds"; + setContext(ctx); + Path2D.Double path = new Path2D.Double(); + path.moveTo(x[startIndex], y[startIndex]); + for (int i = startIndex + 1; i < length; i++) { + path.lineTo(x[i], y[i]); + } + graphics.draw(path); + } + + @Override + public void drawCircle(DrawingContext ctx, double centerX, double centerY, double radius) { + setContext(ctx); + drawShape(ctx, new Ellipse2D.Double(centerX - radius, centerY - radius, radius * 2d, radius * 2d)); + } + + @Override + public void drawString(DrawingContext ctx, double leftX, double bottomY, double rotationAnticlockWise, String text) { + setContext(ctx); + noTranform(() -> { + AffineTransform tr = graphics.getTransform(); + tr.translate((float) (leftX * POINTS_IN_INCH), (float) (currentFrame.getContentPane().getHeight() - bottomY * POINTS_IN_INCH)); + tr.rotate(-rotationAnticlockWise); + graphics.setTransform(tr); + setFontSize(ctx); + graphics.drawString(text, 0, 0); + return null; + }); + } + + @Override + public double getWidth() { + return currentFrame.getContentPane().getWidth() / POINTS_IN_INCH; + } + + @Override + public double getHeight() { + return currentFrame.getContentPane().getHeight() / POINTS_IN_INCH; + } + + @Override + public double getStringWidth(DrawingContext ctx, String text) { + setContext(ctx); + return noTranform(() -> { + setFontSize(ctx); + int swingUnits = graphics.getFontMetrics(graphics.getFont()).stringWidth(text); + return swingUnits / POINTS_IN_INCH; + }); + } + + @Override + public double getStringHeight(DrawingContext ctx, String text) { + setContext(ctx); + return noTranform(() -> { + setFontSize(ctx); + int swingUnits = graphics.getFont().getSize(); + return swingUnits / POINTS_IN_INCH; + }); + } + + private void drawShape(DrawingContext drawingCtx, Shape shape) { + Paint paint = graphics.getPaint(); + graphics.setPaint(fromGridColor(drawingCtx.getFillColor())); + graphics.fill(shape); + graphics.setPaint(paint); + graphics.draw(shape); + } + + private void setContext(DrawingContext ctx) { + graphics.setColor(fromGridColor(ctx.getColor())); + graphics.setStroke(fromGridLineType(ctx.getLineType())); + } + + private void setFontSize(DrawingContext ctx) { + float fontSize = (float) ((ctx.getFontSize() / INCH_TO_POINTS_FACTOR) * POINTS_IN_INCH); + graphics.setFont(graphics.getFont().deriveFont(fontSize)); + } + + private <T> T noTranform(Supplier<T> action) { + AffineTransform transform = graphics.getTransform(); + graphics.setTransform(new AffineTransform()); + T result = action.get(); + graphics.setTransform(transform); + return result; + } + + private static Color fromGridColor(GridColor color) { + return new Color(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); + } + + private static BasicStroke fromGridLineType(GridLineType type) { + switch (type) { + case SOLID: + return solidStroke; + case BLANK: + return blankStroke; + case DASHED: + return dashedStroke; + case DOTDASHED: + return dotdashedStroke; + case DOTTED: + return dottedStroke; + case TWODASH: + return twodashedStroke; + case LONGDASH: + return longdashedStroke; + default: + throw RInternalError.shouldNotReachHere("unexpected value of GridLineType enum"); + } + } + + private static void initStrokes() { + if (solidStroke != null) { + return; + } + float defaultWidth = (float) (1. / POINTS_IN_INCH); + float dashSize = (float) (10. / POINTS_IN_INCH); + float dotSize = (float) (2. / POINTS_IN_INCH); + solidStroke = new BasicStroke((float) (1f / POINTS_IN_INCH)); + blankStroke = new BasicStroke(0f); + dashedStroke = new BasicStroke(defaultWidth, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10f, new float[]{dashSize}, 0f); + dottedStroke = new BasicStroke(defaultWidth, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10f, new float[]{dotSize}, 0f); + dotdashedStroke = new BasicStroke(defaultWidth, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10f, new float[]{dotSize, dashSize}, 0f); + twodashedStroke = new BasicStroke(defaultWidth, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10f, new float[]{dashSize / 2f, dashSize}, 0f); + longdashedStroke = new BasicStroke(defaultWidth, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10f, new float[]{2f * dashSize}, 0f); + } + + private 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(); + + FastRFrame() throws HeadlessException { + super("FastR"); + addCloseListener(); + createUI(); + center(); + } + + private void createUI() { + setLayout(new BorderLayout()); + setSize(framePreferredSize); + add(fastRComponent, BorderLayout.CENTER); + fastRComponent.setPreferredSize(getSize()); + } + + private void addCloseListener() { + addWindowFocusListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + dispose(); + } + }); + } + + private void center() { + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + Dimension frameSize = getSize(); + int x = (screenSize.width - frameSize.width) / 2; + int y = (screenSize.height - frameSize.height) / 2; + setLocation(x, y); + } + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/fastrGrid.R b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/fastrGrid.R new file mode 100644 index 0000000000000000000000000000000000000000..30a16598eaf5a19953b64fe03b5bf148e992072b --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/fastrGrid.R @@ -0,0 +1,176 @@ + +# Returns list with elements [[1]] - depth, zero if not found, [[2]] - the viewport, NULL if not found +find.viewport <- function(name, strict, pvp, depth) { + if (length(ls(env=pvp$children)) == 0) { + return(list(FALSE, NULL)) + } else if (exists(name, env=pvp$children, inherits=FALSE)) { + return(list(depth, get(name, env=pvp$children, inherits=FALSE))) + } else if (strict) { + return(list(FALSE, NULL)) + } else { + return(find.in.children(name, pvp$children, depth + 1L)) + } +} + +# Note: in GnuR this takes "strict" from find.viewport and forwards it to recursive calls to find.viewport, +# however, strict must be constant FALSE if find.in.children is called, so we leave it out. +find.in.children <- function(name, children, depth) { + cpvps <- ls(env=children) + ncpvp <- length(cpvps) + count <- 0L + found <- FALSE + while (count < ncpvp && !found) { + result <- find.viewport(name, FALSE, get(cpvps[count + 1L], env=children), depth) + if (result[[1L]]) { + return(result); + } + count <- count + 1L + } + list(FALSE, NULL) # not found +} + +L_downviewport <- function(name, strict) { + currVp <- .Call(grid:::L_currentViewport) + result <- find.viewport(name, strict, currVp, 1L); + if (result[[1]]) { + .Internal(.fastr.grid.doSetViewPort(result[[2L]], FALSE, FALSE)); + return(result[[1L]]) + } else { + stop(paste0("Viewport '", name, "' was not found")); + } +} + +L_setviewport <- function(vp, hasParent) { + pushedVP <- grid:::pushedvp(vp); + .Internal(.fastr.grid.doSetViewPort(pushedVP, hasParent, TRUE)); +} + +L_unsetviewport <- function(n) { + gvp <- .Call(grid:::L_currentViewport) + newVp <- gvp; + for (i in 1:n) { + gvp <- newVp; + newVp <- gvp$parent; + if (is.null(newVp)) { + error("cannot pop the top-level viewport ('grid' and 'graphics' output mixed?)") + } + } + # remove +} + +################################################### +# Helper functions to deal with null and grob units +# these functions are invoked from Java directly + +# Should be in sync with constants in Unit java class +L_GROBX <- 19 +L_GROBY <- 20 +L_GROBWIDTH <- 21 +L_GROBHEIGHT <- 22 +L_GROBASCENT <- 23 +L_GROBDESCENT <- 24 + +indexMod <- function(i, mod) ((i - 1) %% mod) + 1 + +# if the grob is gPath, use it to find an actual grob +# savedgrob - the grob from grid context +findGrob <- function(grob, savedgrob) { + if (inherits(grob, "gPath")) { + if (is.null(savedgrob)) { + return(grid:::findGrobinDL(grob$name)) + } else { + return(grid:::findGrobinChildren(grob$name, savedgrob$children)) + } + } + grob +} + +# this is called from FastR, it is simpler to implement this whole function in R. +# GnuR uses series of install -> lang2 -> eval calls to achieve this from C. +isPureNullUnit <- function(unit, index) { + if (inherits(unit, "unit.arithmetic")) { + return(isPureNullUnitArithmetic(unit, index)); + } else if (inherits(unit, "unit.list")) { + return(isPureNullUnit(unit[[indexMod(index, length(unit))]], 1)) + } + unitIdVec <- attr(unit, "valid.unit") + unitId <- unitIdVec[[indexMod(index, length(unitIdVec))]] + if (unitId == L_GROBWIDTH) { + return(isPureNullUnitGrobDim(unit, index, grid:::width)) + } else if (unitId == L_GROBHEIGHT) { + return(isPureNullUnitGrobDim(unit, index, grid:::height)) + } + unitId == 5 # L_NULL +} + +getUnitData <- function(unit, index) { + result <- attr(unit, "data") + if (!is.list(result)) { + return(result) + } + result[[indexMod(index, length(result))]] +} + +isPureNullUnitGrobDim <- function(unit, index, dimFunction) { + # Can a grob have "null" width/height? + # to be sure we cover everything, we keep the check here (like in GnuR) + savedgpar <- .Call(grid:::L_getGPar) + savedgrob <- .Call(grid:::L_getCurrentGrob) + + grob <- findGrob(getUnitData(unit, index), savedgrob) + + updatedgrob <- grid:::preDraw(grob) + result <- isPureNullUnit(dimFunction(updatedgrob), 1) + grid:::postDraw(updatedgrob) + + .Call(grid:::L_setGPar, savedgpar) + .Call(grid:::L_setCurrentGrob, savedgrob) + result +} + +isPureNullUnitArithmetic <- function(x, index) { + if (x$fname %in% c('+', '-')) { + # can this ever happen when Ops.unit raises error for two null units added/subtracted? + # to be sure we cover everything, we keep the check here (like in GnuR) + return(isPureNullUnit(x$arg1, index) && isPureNullUnit(x$arg2, index)) + } else if (x$fname == '*') { + return(isPureNullUnit(x$arg2, index)) + } else if (x$fname %in% c('min', 'max', 'sum')) { + return(all(sapply(seq_along(x$arg1), function(i) isPureNullUnit(x$arg1, i)))) + } else { + error("unimplemented unit function"); + } +} + +# tests: +# isPureNullUnit(grid:::unit.list(unit(c(1,2,3),c('mm', 'cm', 'null'))), 1) == FALSE +# isPureNullUnit(grid:::unit.list(unit(c(1,2,3),c('mm', 'cm', 'null'))), 3) == TRUE +# isPureNullUnit(3*unit(1,'mm'), 2) == FALSE +# isPureNullUnit(3*unit(1,'null'), 2) == TRUE +# isPureNullUnit(min(unit(1,'null')), 1) == TRUE +# { gt <- grid.text("Hi there"); isPureNullUnit(unit(1, "grobwidth", gt), 1) } == FALSE +# { gt <- grid.text("Hi there"); isPureNullUnit(unit(1, "grobheight", gt), 1) } == FALSE + +grobConversionPreDraw <- function(grobIn) { + grob <- findGrob(grobIn, .Call(grid:::L_getCurrentGrob)) + grid:::preDraw(grob) +} + +grobConversionGetUnitXY <- function(grob, unitId) { + if (unitId == L_GROBX || unitId == L_GROBY) { + return(list(grid:::xDetails(grob), grid:::yDetails(grob))) + } else if (unitId == L_GROBWIDTH) { + return(list(grid:::width(grob))) + } else if (unitId == L_GROBHEIGHT) { + return(list(grid:::height(grob))) + } else if (unitId == L_GROBDESCENT) { + return(list(grid:::descentDetails(grob))) + } else if (unitId == L_GROBASCENT) { + return(list(grid:::ascentDetails(grob))) + } + error("grobConversionGetUnitXY: not a grob unit.") +} + +grobConversionPostDraw <- function(grob) { + grid:::postDraw(grob) +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/InitWindowedDevice.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/InitWindowedDevice.java new file mode 100644 index 0000000000000000000000000000000000000000..d6314346b22dd1fc81e28524a31f56f0b1a27bc6 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/InitWindowedDevice.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.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.r.library.fastrGrid.GridContext; +import com.oracle.truffle.r.library.fastrGrid.GridState; +import com.oracle.truffle.r.library.fastrGrid.graphics.RGridGraphicsAdapter; +import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; +import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; +import com.oracle.truffle.r.runtime.data.RNull; + +/** + * Node that handles the {@code C_X11} external calls. Those calls may be initiated from either the + * {@code X11} function or FastR specific {@code awt} function. In either case the result is that + * the AWT window is opened and ready for drawing. + */ +public final class InitWindowedDevice extends RExternalBuiltinNode { + static { + Casts.noCasts(InitWindowedDevice.class); + } + + @Override + @TruffleBoundary + protected Object call(RArgsValuesAndNames args) { + GridState gridState = GridContext.getContext().getGridState(); + if (!gridState.isDeviceInitialized()) { + GridContext.getContext().getCurrentDevice().openNewPage(); + gridState.setDeviceInitialized(); + } + RGridGraphicsAdapter.setCurrentDevice(args.getLength() == 0 ? "awt" : "X11cairo"); + return RNull.instance; + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..16a15ce9b2ba2313874a6d1e22eca5c237f15dfc --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/R/fastrGridDevices.R @@ -0,0 +1,30 @@ +# 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. + +eval(expression({ + # This should be preffered way of starting the FastR java device. + # For compatibility reasons, both X11 and awt end up calling C_X11. + # In the future, this function may support extra parameters like a + # reference to java 2D graphics object, which will be used for the drawing. + awt <- function(...) { + .External2(grDevices:::C_X11) + } +}), asNamespace("grDevices")) \ No newline at end of file diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/package-info.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..f8363aacb3318093101e3a1d9ea3b3e1509a9a5e --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/package-info.java @@ -0,0 +1,31 @@ +/* + * 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. + */ +/** + * Compatibility layer for grDevices packages. + * + * With FastR grid we use {@link com.oracle.truffle.r.library.fastrGrid.device.GridDevice} instead + * of the abstraction used by GnuR. This is compatibility layer that provides implementation of some + * of the externals that manipulate the device and forwards them to corresponding methods on FastR + * grid side. + */ +package com.oracle.truffle.r.library.fastrGrid.grDevices; diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/graphics/CPar.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/graphics/CPar.java new file mode 100644 index 0000000000000000000000000000000000000000..e4b6fd0f7e2e4f7a777aceb713ceaef3941a37fd --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/graphics/CPar.java @@ -0,0 +1,75 @@ +/* + * 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.graphics; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.r.library.fastrGrid.GridContext; +import com.oracle.truffle.r.library.fastrGrid.device.GridDevice; +import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; +import com.oracle.truffle.r.runtime.RError; +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.RDataFactory; +import com.oracle.truffle.r.runtime.data.RList; + +public class CPar extends RExternalBuiltinNode { + static { + Casts.noCasts(CPar.class); + } + + @Override + @TruffleBoundary + protected Object call(RArgsValuesAndNames args) { + if (args.getSignature().getNonNullCount() > 0) { + throw error(Message.GENERIC, "Using par for setting device parameters is not supported in FastR grid emulation mode."); + } + + GridDevice device = GridContext.getContext().getCurrentDevice(); + Object[] names = args.getArguments(); + // unwrap list if it is the first argument + if (names.length == 1) { + Object first = args.getArgument(0); + if (first instanceof RList) { + names = ((RList) first).getDataWithoutCopying(); + } + } + + Object[] result = new Object[names.length]; + String[] resultNames = new String[names.length]; + for (int i = 0; i < names.length; i++) { + resultNames[i] = RRuntime.asString(names[i]); + result[i] = getParam(resultNames[i], device); + } + return RDataFactory.createList(result, RDataFactory.createStringVector(resultNames, RDataFactory.COMPLETE_VECTOR)); + } + + private Object getParam(String name, GridDevice device) { + switch (name) { + case "din": + return RDataFactory.createDoubleVector(new double[]{device.getWidth(), device.getHeight()}, RDataFactory.COMPLETE_VECTOR); + default: + throw RError.nyi(RError.NO_CALLER, "C_Par paramter '" + name + "'"); + } + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/graphics/RGridGraphicsAdapter.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/graphics/RGridGraphicsAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..4d4629bc7f1e29d3c33ec63f6b7ad9a7ad8324b3 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/graphics/RGridGraphicsAdapter.java @@ -0,0 +1,73 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka + * Copyright (C) 1998 Ross Ihaka + * Copyright (c) 1998--2014, The R Core Team + * Copyright (c) 2002--2010, The R Foundation + * Copyright (C) 2005--2006, Morten Welinder + * Copyright (c) 2014, 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.library.fastrGrid.graphics; + +import com.oracle.truffle.r.library.fastrGrid.FastRGridExternalLookup; +import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; +import com.oracle.truffle.r.runtime.ROptions; +import com.oracle.truffle.r.runtime.ROptions.OptionsException; +import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RPairList; +import com.oracle.truffle.r.runtime.env.REnvironment; + +/** + * Initialization of graphics package emulation for the purposes of FastR grid package + * implementation. + * + * FastR exposes two devices: the null device and 'awt' device, and adds function 'awt' to the + * grDevices package. The 'awt' function ends up calling 'C_X11' (the same as the 'X11' function + * from grDevices), we capture that call in {@link FastRGridExternalLookup} and replace it with our + * own logic. This way we also "implement" 'X11' device with java awt should anyone try to activate + * it. + * + * Moreover, we change the value of option "device" to our "awt" function so that when e.g. lattice + * tries to open the default device it uses 'awt'. If the future this should be either 'awt' for + * interactive sessions, or some image format device for batch sessions. We should also honor the + * R_INTERACTIVE_DEVICE and R_DEFAULT_DEVICE environment variables. + */ +public class RGridGraphicsAdapter { + private static final String NULL_DEVICE = "null device"; + /** + * The graphics devices system maintains two variables .Device and .Devices in the base + * environment both are always set: .Devices gives a list of character vectors of the names of + * open devices, .Device is the element corresponding to the currently active device. The null + * device will always be open. + */ + private static final String DOT_DEVICE = ".Device"; + private static final String DOT_DEVICES = ".Devices"; + + public static void initialize() { + setCurrentDevice(NULL_DEVICE); + ROptions.ContextStateImpl options = RContext.getInstance().stateROptions; + try { + options.setValue("device", "awt"); + } catch (OptionsException e) { + RError.warning(RError.NO_CALLER, Message.GENERIC, "FastR could not set the 'device' options to awt."); + } + } + + public static void setCurrentDevice(String name) { + REnvironment baseEnv = REnvironment.baseEnv(); + baseEnv.safePut(DOT_DEVICE, name); + Object devices = baseEnv.get(DOT_DEVICES); + if (devices instanceof RPairList) { + ((RPairList) devices).appendToEnd(RDataFactory.createPairList(name)); + } else { + baseEnv.safePut(DOT_DEVICES, RDataFactory.createPairList(name)); + } + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/graphics/package-info.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/graphics/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..4e19a7b99e7e0e5242d1b4783c80c3083f754354 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/graphics/package-info.java @@ -0,0 +1,29 @@ +/* + * 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. + */ +/** + * Compatibility layer for graphics package. + * + * Some R code that uses mainly grid for drawing resorts to several graphics package functions, + * especially in order to control or query information about device(s). + */ +package com.oracle.truffle.r.library.fastrGrid.graphics; diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/DevicesCCalls.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/DevicesCCalls.java deleted file mode 100644 index d7ba80d07c943bd2112a373a122927c0bb1da8dd..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/DevicesCCalls.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka - * Copyright (C) 1998 Ross Ihaka - * Copyright (c) 1998--2014, The R Core Team - * Copyright (c) 2002--2010, The R Foundation - * Copyright (C) 2005--2006, Morten Welinder - * Copyright (c) 2014, 2017, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.library.grDevices; - -import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.emptyStringVector; -import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue; -import static com.oracle.truffle.r.nodes.builtin.casts.fluent.CastNodeBuilder.newCastBuilder; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.r.library.grDevices.DevicesCCallsFactory.C_DevOffNodeGen; -import com.oracle.truffle.r.library.grDevices.pdf.PdfGraphicsDevice; -import com.oracle.truffle.r.library.graphics.core.GraphicsEngineImpl; -import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; -import com.oracle.truffle.r.nodes.unary.CastNode; -import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; -import com.oracle.truffle.r.runtime.data.RNull; -import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; - -public class DevicesCCalls { - public abstract static class C_DevOff extends RExternalBuiltinNode.Arg1 { - public static C_DevOff create() { - return C_DevOffNodeGen.create(); - } - - static { - Casts casts = new Casts(C_DevOff.class); - casts.arg(0).asIntegerVector().findFirst(); - } - - @Specialization - public Object doCall(int deviceIndex) { - GraphicsEngineImpl.getInstance().killGraphicsDeviceByIndex(deviceIndex); - return RNull.instance; - } - } - - public static final class C_DevCur extends RExternalBuiltinNode.Arg0 { - - @Override - @TruffleBoundary - public Object execute() { - return GraphicsEngineImpl.getInstance().getCurrentGraphicsDeviceIndex(); - } - } - - public static final class C_PDF extends RExternalBuiltinNode { - - @Child private CastNode extractFontsNode = newCastBuilder().mapNull(emptyStringVector()).mustBe(stringValue()).asStringVector().buildCastNode(); - @Child private CastNode asStringNode = newCastBuilder().asStringVector().findFirst().buildCastNode(); - @Child private CastNode asDoubleNode = newCastBuilder().asDoubleVector().findFirst().buildCastNode(); - @Child private CastNode asLogicalNode = newCastBuilder().asLogicalVector().findFirst().buildCastNode(); - @Child private CastNode asIntNode = newCastBuilder().asIntegerVector().findFirst().buildCastNode(); - - static { - Casts.noCasts(C_PDF.class); - } - - @SuppressWarnings("unused") - @Override - @TruffleBoundary - public Object call(RArgsValuesAndNames args) { - new PdfGraphicsDevice(extractParametersFrom(args)); - // todo implement devices addition - return RNull.instance; - } - - private PdfGraphicsDevice.Parameters extractParametersFrom(RArgsValuesAndNames args) { - PdfGraphicsDevice.Parameters result = new PdfGraphicsDevice.Parameters(); - result.filePath = asString(args.getArgument(0)); - result.paperSize = asString(args.getArgument(1)); - result.fontFamily = asString(args.getArgument(2)); - result.encoding = asString(args.getArgument(3)); - result.bg = asString(args.getArgument(4)); - result.fg = asString(args.getArgument(5)); - result.width = asDouble(castVector(args.getArgument(6))); - result.height = asDouble(castVector(args.getArgument(7))); - result.pointSize = asDouble(castVector(args.getArgument(8))); - result.oneFile = asLogical(castVector(args.getArgument(9))); - result.pageCenter = asLogical(castVector(args.getArgument(10))); - result.title = asString(args.getArgument(11)); - result.fonts = extractFontsFrom(args.getArgument(12)); - - result.majorVersion = asInt(castVector(args.getArgument(13))); - result.minorVersion = asInt(castVector(args.getArgument(14))); - result.colormodel = asString(args.getArgument(15)); - result.useDingbats = asLogical(castVector(args.getArgument(16))); - result.useKerning = asLogical(castVector(args.getArgument(17))); - result.fillOddEven = asLogical(castVector(args.getArgument(18))); - result.compress = asLogical(castVector(args.getArgument(19))); - return result; - } - - private String asString(Object value) { - return (String) asStringNode.execute(value); - } - - private int asInt(Object value) { - return (Integer) asIntNode.execute(value); - } - - private double asDouble(Object value) { - return (Double) asDoubleNode.execute(value); - } - - private byte asLogical(Object value) { - return (Byte) asLogicalNode.execute(value); - } - - private String[] extractFontsFrom(Object inputArgument) { - return ((RAbstractStringVector) extractFontsNode.execute(inputArgument)).materialize().getDataCopy(); - } - } -} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/NullGraphicsDevice.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/NullGraphicsDevice.java deleted file mode 100644 index 0ec439c90287e887c4869771a65ef7bad33ac17f..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/NullGraphicsDevice.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka - * Copyright (C) 1998 Ross Ihaka - * Copyright (c) 1998--2014, The R Core Team - * Copyright (c) 2002--2010, The R Foundation - * Copyright (C) 2005--2006, Morten Welinder - * Copyright (c) 2014, 2015, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.library.grDevices; - -import com.oracle.truffle.r.library.graphics.core.DrawingParameters; -import com.oracle.truffle.r.library.graphics.core.GraphicsDevice; -import com.oracle.truffle.r.library.graphics.core.geometry.Coordinates; - -public final class NullGraphicsDevice implements GraphicsDevice { - private static final NullGraphicsDevice instance = new NullGraphicsDevice(); - - public static NullGraphicsDevice getInstance() { - return instance; - } - - @Override - public void deactivate() { - throw createExceptionForMethod("deactivate"); - } - - @Override - public void activate() { - throw createExceptionForMethod("activate"); - } - - @Override - public void close() { - throw createExceptionForMethod("close"); - } - - @Override - public DrawingParameters getDrawingParameters() { - throw createExceptionForMethod("getDrawingParameters"); - } - - @Override - public void setMode(Mode newMode) { - throw createExceptionForMethod("setMode"); - } - - @Override - public Mode getMode() { - throw createExceptionForMethod("getMode"); - } - - @Override - public void setClipRect(double x1, double y1, double x2, double y2) { - throw createExceptionForMethod("setClipRect"); - } - - @Override - public void drawPolyline(Coordinates coordinates, DrawingParameters drawingParameters) { - throw createExceptionForMethod("drawPolyline"); - } - - private static RuntimeException createExceptionForMethod(String methodName) { - return new IllegalStateException("Call to " + methodName + " of Null-device"); - } -} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/fastrgd/FastRGraphicsDevice.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/fastrgd/FastRGraphicsDevice.java deleted file mode 100644 index ca8976b7907f25bacb5b9ac22c8ee65720fc7f19..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/fastrgd/FastRGraphicsDevice.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka - * Copyright (C) 1998 Ross Ihaka - * Copyright (c) 1998--2014, The R Core Team - * Copyright (c) 2002--2010, The R Foundation - * Copyright (C) 2005--2006, Morten Welinder - * Copyright (c) 2014, 2016, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.library.grDevices.fastrgd; - -import static com.oracle.truffle.r.library.graphics.core.geometry.AxisDirection.EAST; -import static com.oracle.truffle.r.library.graphics.core.geometry.AxisDirection.NORTH; - -import java.util.Arrays; -import java.util.function.Function; - -import com.oracle.truffle.r.library.graphics.FastRFrame; -import com.oracle.truffle.r.library.graphics.core.DrawingParameters; -import com.oracle.truffle.r.library.graphics.core.GraphicsDevice; -import com.oracle.truffle.r.library.graphics.core.drawables.DrawableObject; -import com.oracle.truffle.r.library.graphics.core.drawables.PolylineDrawableObject; -import com.oracle.truffle.r.library.graphics.core.drawables.StringDrawableObject; -import com.oracle.truffle.r.library.graphics.core.geometry.Axis; -import com.oracle.truffle.r.library.graphics.core.geometry.CoordinateSystem; -import com.oracle.truffle.r.library.graphics.core.geometry.Coordinates; -import com.oracle.truffle.r.library.graphics.core.geometry.CoordinatesFactory; -import com.oracle.truffle.r.library.graphics.core.geometry.DoubleCoordinates; - -/** - * Default interactive FastR graphics device. - */ -public class FastRGraphicsDevice implements GraphicsDevice { - private static final double GNUR_DEFAULT_MAX_X = 1; - private static final Axis GNUR_DEFAULT_X_AXIS = new Axis(0, GNUR_DEFAULT_MAX_X, EAST); - private static final Axis GNUR_DEFAULT_Y_AXIS = new Axis(0, 1, NORTH); - private static final double MARGIN = GNUR_DEFAULT_MAX_X * 0.1; // the margin for each side of - // 10% of a screen - // compress resulting image to have a small margin on all sides - private static final double COMPRESS_RATION = 1. - MARGIN * 1.8; - - private Mode mode = Mode.GRAPHICS_OFF; - private FastRFrame fastRFrame; - private CoordinateSystem currentCoordinateSystem = new CoordinateSystem(GNUR_DEFAULT_X_AXIS, GNUR_DEFAULT_Y_AXIS); - - @Override - public void deactivate() { - // todo impl - } - - @Override - public void activate() { - // todo impl - } - - @Override - public void close() { - // todo impl - } - - @Override - public DrawingParameters getDrawingParameters() { - return null; - } - - @Override - public void setMode(Mode newMode) { - mode = newMode; - } - - @Override - public Mode getMode() { - return mode; - } - - @Override - public void setClipRect(double x1, double y1, double x2, double y2) { - // todo impl - } - - @Override - public void drawPolyline(Coordinates coordinates, DrawingParameters drawingParameters) { - // todo continue from GEPolyline() of engine.c - Coordinates convertedCoords = CoordinatesFactory.withRatioAndShift(coordinates, COMPRESS_RATION, MARGIN); - addDrawableObject(new PolylineDrawableObject(currentCoordinateSystem, convertedCoords)); - drawBounds(); - drawXYLabelsFor(coordinates); - } - - private void drawBounds() { - // x,y in range [0,1] - double[] boundsXYPairs = {0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0}; - Coordinates bounds = CoordinatesFactory.createByXYPairs(boundsXYPairs); - Coordinates compressedBounds = CoordinatesFactory.withRatioAndShift(bounds, COMPRESS_RATION, MARGIN); - addDrawableObject(new PolylineDrawableObject(currentCoordinateSystem, compressedBounds)); - } - - private void drawXYLabelsFor(Coordinates coordinates) { - drawLabelsForCoordinates(coordinates.getXCoordinatesAsDoubles(), MARGIN, 0.01, // just small - // shift - d -> CoordinatesFactory.createWithSameY(d, 0)); - drawLabelsForCoordinates(coordinates.getYCoordinatesAsDoubles(), 0, MARGIN, d -> CoordinatesFactory.createWithSameX(0, d)); - } - - private void drawLabelsForCoordinates(double[] coordinates, double xShift, double yShift, Function<double[], DoubleCoordinates> xYConverter) { - int length = coordinates.length; - double[] sortedCoords = new double[length]; - // copy to avoid side-effects on a caller side - System.arraycopy(coordinates, 0, sortedCoords, 0, length); - Arrays.sort(sortedCoords); - String[] labels = composeLabelsFor(sortedCoords); - DoubleCoordinates xYCoords = xYConverter.apply(sortedCoords); - Coordinates shiftedCoords = CoordinatesFactory.withRatioAndShift(xYCoords, COMPRESS_RATION, xShift, yShift); - addDrawableObject(new StringDrawableObject(currentCoordinateSystem, shiftedCoords, labels)); - } - - private static String[] composeLabelsFor(double[] doubles) { - return Arrays.stream(doubles).mapToObj(String::valueOf).toArray(String[]::new); - } - - private FastRFrame getFastRFrame() { - if (fastRFrame == null || !fastRFrame.isVisible()) { - fastRFrame = new FastRFrame(); - fastRFrame.setVisible(true); - } - return fastRFrame; - } - - private void addDrawableObject(DrawableObject drawableObject) { - getFastRFrame().getFastRComponent().addDrawableObject(drawableObject); - } -} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/pdf/PdfGraphicsDevice.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/pdf/PdfGraphicsDevice.java deleted file mode 100644 index 9b7302823dec1669faa446b3a71a2723d628cbe4..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/pdf/PdfGraphicsDevice.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka - * Copyright (C) 1998 Ross Ihaka - * Copyright (c) 1998--2014, The R Core Team - * Copyright (c) 2002--2010, The R Foundation - * Copyright (C) 2005--2006, Morten Welinder - * Copyright (c) 2014, 2015, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.library.grDevices.pdf; - -import com.oracle.truffle.r.library.graphics.core.DrawingParameters; -import com.oracle.truffle.r.library.graphics.core.GraphicsDevice; -import com.oracle.truffle.r.library.graphics.core.geometry.Coordinates; -import com.oracle.truffle.r.runtime.RRuntime; - -public class PdfGraphicsDevice implements GraphicsDevice { - @SuppressWarnings("unused") private final Parameters deviceParameters; - - public PdfGraphicsDevice(Parameters deviceParameters) { - this.deviceParameters = deviceParameters; - } - - @Override - public void deactivate() { - - } - - @Override - public void activate() { - - } - - @Override - public void close() { - - } - - @Override - public DrawingParameters getDrawingParameters() { - return null; - } - - @Override - public void setMode(Mode newMode) { - - } - - @Override - public Mode getMode() { - return null; - } - - @Override - public void setClipRect(double x1, double y1, double x2, double y2) { - - } - - @Override - public void drawPolyline(Coordinates coordinates, DrawingParameters drawingParameters) { - - } - - public static class Parameters { - public String filePath; - public String paperSize = "special"; - public String fontFamily = "Helvetica"; - public String encoding = "default"; - public String bg = "transparent"; - public String fg = "black"; - public double width = 7.; - public double height = 7.; - public double pointSize = 12.; - public byte oneFile = RRuntime.LOGICAL_TRUE; - public byte pageCenter = RRuntime.LOGICAL_TRUE; - public String title = "R Graphics Output"; - public String[] fonts; - public int majorVersion = 1; - public int minorVersion = 4; - public String colormodel = "srgb"; - public byte useDingbats = RRuntime.LOGICAL_TRUE; - public byte useKerning = RRuntime.LOGICAL_TRUE; - public byte fillOddEven = RRuntime.LOGICAL_FALSE; - public byte compress = RRuntime.LOGICAL_TRUE; - } -} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/BaseGraphicsSystem.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/BaseGraphicsSystem.java deleted file mode 100644 index 77d572f534a7ef158c16829b4d7fa953fbaca328..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/BaseGraphicsSystem.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka - * Copyright (C) 1998 Ross Ihaka - * Copyright (c) 1998--2014, The R Core Team - * Copyright (c) 2002--2010, The R Foundation - * Copyright (C) 2005--2006, Morten Welinder - * Copyright (c) 2014, 2015, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.library.graphics; - -import com.oracle.truffle.r.library.graphics.core.AbstractGraphicsSystem; - -/** - * Denotes to the 'base' in GNUR terms graphics system. - */ -public class BaseGraphicsSystem extends AbstractGraphicsSystem { - private final GraphicsEventsListener graphicsEventsListener = (graphicsEvent, graphicsDevice) -> { - }; - - @Override - public GraphicsEventsListener getGraphicsEventsListener() { - return graphicsEventsListener; - } -} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/FastRComponent.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/FastRComponent.java deleted file mode 100644 index 5f395fecd1afe721a1f2f435c417169f7b88fcd0..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/FastRComponent.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka - * Copyright (C) 1998 Ross Ihaka - * Copyright (c) 1998--2014, The R Core Team - * Copyright (c) 2002--2010, The R Foundation - * Copyright (C) 2005--2006, Morten Welinder - * Copyright (c) 2014, 2016, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.library.graphics; - -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import javax.swing.JComponent; - -import com.oracle.truffle.r.library.graphics.core.drawables.DrawableObject; -import com.oracle.truffle.r.library.graphics.core.geometry.CoordinateSystem; - -public class FastRComponent extends JComponent { - - private static final long serialVersionUID = 1L; - - private final List<DrawableObject> displayList = Collections.synchronizedList(new ArrayList<>()); - - private boolean shouldDraw; - private CoordinateSystem coordinateSystem; - - /** - * Note! Called from ED thread. - */ - @Override - public void doLayout() { - super.doLayout(); - Dimension size = getSize(); - coordinateSystem = new CoordinateSystem(0, size.getWidth(), 0, size.getHeight()); - shouldDraw = true; - recalculateDisplayList(); - } - - private void recalculateDisplayList() { - synchronized (displayList) { - displayList.stream().forEach(drawableObject -> drawableObject.recalculateForDrawingIn(coordinateSystem)); - } - } - - /** - * Note! Called from ED thread. - */ - @Override - protected void paintComponent(Graphics g) { - super.paintComponent(g); - Graphics2D g2 = (Graphics2D) g; - if (shouldDraw) { - drawDisplayListOn(g2); - } - } - - private void drawDisplayListOn(Graphics2D g2) { - synchronized (displayList) { - displayList.stream().forEach(drawableObject -> drawableObject.drawOn(g2)); - } - } - - public void addDrawableObject(DrawableObject drawableObject) { - synchronized (displayList) { - displayList.add(drawableObject); - } - shouldDraw = true; - if (coordinateSystem != null) { - drawableObject.recalculateForDrawingIn(coordinateSystem); - repaint(); - } - } -} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/FastRFrame.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/FastRFrame.java deleted file mode 100644 index 9f1463e8549ecc02f5eca556a94f7e22426d590b..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/FastRFrame.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2014, 2016, 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.graphics; - -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.awt.HeadlessException; -import java.awt.Toolkit; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; - -import javax.swing.JFrame; - -public class FastRFrame extends JFrame { - - private static final long serialVersionUID = 1L; - - private final Dimension framePreferredSize = new Dimension(500, 500); - private final FastRComponent fastRComponent = new FastRComponent(); - - public FastRFrame() throws HeadlessException { - super("FastR"); - addCloseListener(); - createUI(); - center(); - } - - private void createUI() { - setLayout(new BorderLayout()); - setSize(framePreferredSize); - add(fastRComponent, BorderLayout.CENTER); - fastRComponent.setPreferredSize(getSize()); - } - - private void addCloseListener() { - addWindowFocusListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - dispose(); - } - }); - } - - private void center() { - Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); - Dimension frameSize = getSize(); - int x = (screenSize.width - frameSize.width) / 2; - int y = (screenSize.height - frameSize.height) / 2; - setLocation(x, y); - } - - public FastRComponent getFastRComponent() { - return fastRComponent; - } -} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/GraphicsCCalls.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/GraphicsCCalls.java deleted file mode 100644 index adee6f49eac5deef5d74256f2190bad20ace8108..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/GraphicsCCalls.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka - * Copyright (C) 1998 Ross Ihaka - * Copyright (c) 1998--2014, The R Core Team - * Copyright (c) 2002--2010, The R Foundation - * Copyright (C) 2005--2006, Morten Welinder - * Copyright (c) 2014, 2017, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.library.graphics; - -import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.doubleValue; -import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.size; -import static com.oracle.truffle.r.nodes.builtin.casts.fluent.CastNodeBuilder.newCastBuilder; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.r.library.graphics.core.DrawingParameters; -import com.oracle.truffle.r.library.graphics.core.GraphicsDevice; -import com.oracle.truffle.r.library.graphics.core.GraphicsEngine; -import com.oracle.truffle.r.library.graphics.core.GraphicsEngineImpl; -import com.oracle.truffle.r.library.graphics.core.geometry.Coordinates; -import com.oracle.truffle.r.library.graphics.core.geometry.CoordinatesFactory; -import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; -import com.oracle.truffle.r.nodes.unary.CastNode; -import com.oracle.truffle.r.runtime.RRuntime; -import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; -import com.oracle.truffle.r.runtime.data.RDataFactory; -import com.oracle.truffle.r.runtime.data.RDoubleVector; -import com.oracle.truffle.r.runtime.data.RNull; - -public class GraphicsCCalls { - public static final class C_PlotXY extends RExternalBuiltinNode { - - @Child private CastNode castXYNode = newCastBuilder().mustBe(doubleValue().and(size(2))).asDoubleVector().buildCastNode(); - - static { - Casts.noCasts(C_PlotXY.class); - } - - @Override - @TruffleBoundary - public RNull call(RArgsValuesAndNames args) { - RDoubleVector xyVector = (RDoubleVector) castXYNode.execute(args.getArgument(0)); - getGraphicsEngine().setCurrentGraphicsDeviceMode(GraphicsDevice.Mode.GRAPHICS_ON); - drawWithLines(xyVector); - return RNull.instance; - } - - private static void drawWithLines(RDoubleVector xyVector) { - // todo implement coordinate systems units conversion like in GConvert (graphics.c) - setClipRect(); - DrawingParameters adoptedParameters = adoptCurrentDeviceDrawingParameters(); - Coordinates coordinates = CoordinatesFactory.createByXYVector(xyVector); - getGraphicsEngine().drawPolyline(coordinates, adoptedParameters); - } - - private static DrawingParameters adoptCurrentDeviceDrawingParameters() { - // todo Now adoption as for today. Transcribe from gcontextFromGM() (graphics.c) - return getCurrentGraphicsDevice().getDrawingParameters(); - } - - private static void setClipRect() { - // todo Transcrive from Gclip() (graphics.c) - getGraphicsEngine().setCurrentGraphicsDeviceClipRect(0, 0, 0, 0); - } - - private static GraphicsDevice getCurrentGraphicsDevice() { - return getGraphicsEngine().getCurrentGraphicsDevice(); - } - - private static GraphicsEngine getGraphicsEngine() { - return GraphicsEngineImpl.getInstance(); - } - } - - public static final class C_Par extends RExternalBuiltinNode { - - static { - Casts.noCasts(C_Par.class); - } - - @Override - @TruffleBoundary - public Object call(RArgsValuesAndNames args) { - // pch - return RDataFactory.createIntVectorFromScalar(1); - } - } - - @SuppressWarnings("unused") - public static final class C_mtext extends RExternalBuiltinNode { - private Object text; - private double side = 3.; - private double line = 0.; - private boolean outer = true; - private double adj = RRuntime.DOUBLE_NA; - private double at = RRuntime.DOUBLE_NA; - private double padj = RRuntime.DOUBLE_NA; - private double cex = RRuntime.DOUBLE_NA; - private double col = RRuntime.DOUBLE_NA; - private double font = RRuntime.DOUBLE_NA; - - @Child private CastNode firstDoubleCast = newCastBuilder().asDoubleVector().findFirst().buildCastNode(); - - static { - Casts.noCasts(C_mtext.class); - } - - @Override - @TruffleBoundary - public Object call(RArgsValuesAndNames args) { - extractArgumentsFrom(args); - return RNull.instance; - } - - private void extractArgumentsFrom(RArgsValuesAndNames args) { - // text = args.getArgument(0); // postpone for now - side = extractFirstDoubleValueFrom(args.getArgument(1)); - line = extractFirstDoubleValueFrom(args.getArgument(2)); - // outer = extractFirstDoubleValueFrom(args.getArgument(3)); - at = extractFirstDoubleValueFrom(args.getArgument(4)); - adj = extractFirstDoubleValueFrom(args.getArgument(5)); - padj = extractFirstDoubleValueFrom(args.getArgument(6)); - cex = extractFirstDoubleValueFrom(args.getArgument(7)); - // col = extractFirstDoubleValueFrom(args.getArgument(8)); - font = extractFirstDoubleValueFrom(args.getArgument(9)); - } - - private double extractFirstDoubleValueFrom(Object arg) { - return (Double) firstDoubleCast.execute(arg); - } - } -} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/RGraphics.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/RGraphics.java index 11c4a71ce6b38c8afb385a9a5be2670ce5a16a14..7e9d763981801aa287fc67072cd539d53e96ce6e 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/RGraphics.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/RGraphics.java @@ -16,50 +16,24 @@ package com.oracle.truffle.r.library.graphics; import java.util.concurrent.atomic.AtomicBoolean; -import com.oracle.truffle.r.library.graphics.core.GraphicsEngine; -import com.oracle.truffle.r.library.graphics.core.GraphicsEngineImpl; +import com.oracle.truffle.r.library.fastrGrid.graphics.RGridGraphicsAdapter; import com.oracle.truffle.r.runtime.FastROptions; -import com.oracle.truffle.r.runtime.context.ConsoleHandler; -import com.oracle.truffle.r.runtime.context.RContext; -import com.oracle.truffle.r.runtime.data.RDataFactory; -import com.oracle.truffle.r.runtime.data.RPairList; -import com.oracle.truffle.r.runtime.data.RStringVector; -import com.oracle.truffle.r.runtime.env.REnvironment; -import com.oracle.truffle.r.runtime.ffi.DLL; import com.oracle.truffle.r.runtime.ffi.CallRFFI; +import com.oracle.truffle.r.runtime.ffi.DLL; import com.oracle.truffle.r.runtime.ffi.NativeCallInfo; /** - * A placeholder to keep {@code REngine} limited to calling the {@link #initialize} method. Two - * possible implementations are available: - * <ul> - * <li>Native graphics from GnuR</li> - * <li>Internal (Java) graphics, very incomplete implementation</li> - * </ul> - * The default is native graphics, selected by a startup option. Graphics is not virtualized, so - * multiple contexts all share the same underlying implementation which is initialized exactly once. - * + * A placeholder to keep {@code REngine} limited to calling the {@link #initialize} method. The code + * in R has a hard-coded invocation to InitGraphics in it. This initialization either invokes it + * too, or it runs a Java version of it if the internal grid package implementation is to be used. */ public class RGraphics { - private static final RStringVector NULL_DEVICE = RDataFactory.createStringVectorFromScalar("null device"); - /** - * The graphics devices system maintains two variables .Device and .Devices in the base - * environment both are always set: .Devices gives a list of character vectors of the names of - * open devices, .Device is the element corresponding to the currently active device. The null - * device will always be open. - */ - private static final String DOT_DEVICE = ".Device"; - private static final String DOT_DEVICES = ".Devices"; private static final AtomicBoolean initialized = new AtomicBoolean(); public static void initialize() { if (initialized.compareAndSet(false, true)) { - if (FastROptions.UseInternalGraphics.getBooleanValue()) { - REnvironment baseEnv = REnvironment.baseEnv(); - baseEnv.safePut(DOT_DEVICE, NULL_DEVICE); - RPairList devices = RDataFactory.createPairList(NULL_DEVICE); - baseEnv.safePut(DOT_DEVICES, devices); - registerBaseGraphicsSystem(); + if (FastROptions.UseInternalGridGraphics.getBooleanValue()) { + RGridGraphicsAdapter.initialize(); } else { DLL.DLLInfo dllInfo = DLL.findLibrary("graphics"); DLL.SymbolHandle symbolHandle = DLL.findSymbol("InitGraphics", dllInfo); @@ -68,18 +42,4 @@ public class RGraphics { } } } - - private static void registerBaseGraphicsSystem() { - try { - getGraphicsEngine().registerGraphicsSystem(new BaseGraphicsSystem()); - } catch (Exception e) { - e.printStackTrace(); - ConsoleHandler consoleHandler = RContext.getInstance().getConsoleHandler(); - consoleHandler.println("Unable to register base graphics system"); - } - } - - private static GraphicsEngine getGraphicsEngine() { - return GraphicsEngineImpl.getInstance(); - } } diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/AbstractGraphicsSystem.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/AbstractGraphicsSystem.java deleted file mode 100644 index b401568ffa06f437c046cded9d3cbc363ed84de2..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/AbstractGraphicsSystem.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka - * Copyright (C) 1998 Ross Ihaka - * Copyright (c) 1998--2014, The R Core Team - * Copyright (c) 2002--2010, The R Foundation - * Copyright (C) 2005--2006, Morten Welinder - * Copyright (c) 2014, 2015, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.library.graphics.core; - -public abstract class AbstractGraphicsSystem implements GraphicsSystem { - private final GraphicsSystemParameters graphicsSystemParameters = new GraphicsSystemParameters(); - private int id; - - protected GraphicsSystemParameters getGraphicsSystemParameters() { - return graphicsSystemParameters; - } - - @Override - public void setId(int id) { - this.id = id; - } - - @Override - public int getId() { - return id; - } -} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/DrawingParameters.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/DrawingParameters.java deleted file mode 100644 index 69a1d7075210e9646fe22300db31d18f1678b7ab..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/DrawingParameters.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka - * Copyright (C) 1998 Ross Ihaka - * Copyright (c) 1998--2014, The R Core Team - * Copyright (c) 2002--2010, The R Foundation - * Copyright (C) 2005--2006, Morten Welinder - * Copyright (c) 2014, 2015, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.library.graphics.core; - -// todo implement GEContext data structure (GraphicsEngine.h) -public final class DrawingParameters { -} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/GraphicsDevice.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/GraphicsDevice.java deleted file mode 100644 index 91e07584d7ea7e37edfe40fa83075849642823cb..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/GraphicsDevice.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka - * Copyright (C) 1998 Ross Ihaka - * Copyright (c) 1998--2014, The R Core Team - * Copyright (c) 2002--2010, The R Foundation - * Copyright (C) 2005--2006, Morten Welinder - * Copyright (c) 2014, 2016, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.library.graphics.core; - -import com.oracle.truffle.r.library.graphics.core.geometry.Coordinates; - -public interface GraphicsDevice { - void deactivate(); - - void activate(); - - void close(); - - DrawingParameters getDrawingParameters(); - - void setMode(Mode newMode); - - Mode getMode(); - - void setClipRect(double x1, double y1, double x2, double y2); - - void drawPolyline(Coordinates coordinates, DrawingParameters drawingParameters); - - enum Mode { - GRAPHICS_ON, // allow graphics output - GRAPHICS_OFF // disable graphics output - } -} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/GraphicsEngine.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/GraphicsEngine.java deleted file mode 100644 index 57a70b07e2e802fa89ba89a5af7e0702613c7b31..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/GraphicsEngine.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka - * Copyright (C) 1998 Ross Ihaka - * Copyright (c) 1998--2014, The R Core Team - * Copyright (c) 2002--2010, The R Foundation - * Copyright (C) 2005--2006, Morten Welinder - * Copyright (c) 2014, 2015, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.library.graphics.core; - -import com.oracle.truffle.r.library.graphics.core.geometry.Coordinates; - -public interface GraphicsEngine { - void registerGraphicsSystem(GraphicsSystem newGraphicsSystem) throws Exception; - - void unRegisterGraphicsSystem(GraphicsSystem graphicsSystem); - - void registerGraphicsDevice(GraphicsDevice newGraphicsDevice) throws Exception; - - void unRegisterGraphicsDevice(GraphicsDevice deviceToUnregister); - - int getGraphicsDevicesAmount(); - - /** - * @return true if there is only Null graphics device registered - */ - boolean noGraphicsDevices(); - - /** - * Tries to install one if there is no current device. - * - * @return current {@link GraphicsDevice} - */ - GraphicsDevice getCurrentGraphicsDevice(); - - /** - * @return {@link com.oracle.truffle.r.library.grDevices.NullGraphicsDevice} if unable to find - * other - */ - GraphicsDevice getGraphicsDeviceNextTo(GraphicsDevice graphicsDevice); - - /** - * @return {@link com.oracle.truffle.r.library.grDevices.NullGraphicsDevice} if unable to find - * other - */ - GraphicsDevice getGraphicsDevicePrevTo(GraphicsDevice graphicsDevice); - - void setCurrentGraphicsDeviceMode(GraphicsDevice.Mode mode); - - void setCurrentGraphicsDeviceClipRect(double x1, double y1, double x2, double y2); - - void drawPolyline(Coordinates coordinates, DrawingParameters drawingParameters); - - void killGraphicsDeviceByIndex(int graphicsDeviceIndex); - - int getCurrentGraphicsDeviceIndex(); -} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/GraphicsEngineImpl.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/GraphicsEngineImpl.java deleted file mode 100644 index 5efaee6e6765608e465e3d67d2b606db4dec8c0a..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/GraphicsEngineImpl.java +++ /dev/null @@ -1,316 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka - * Copyright (C) 1998 Ross Ihaka - * Copyright (c) 1998--2014, The R Core Team - * Copyright (c) 2002--2010, The R Foundation - * Copyright (C) 2005--2006, Morten Welinder - * Copyright (c) 2014, 2016, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.library.graphics.core; - -import static com.oracle.truffle.r.library.graphics.core.GraphicsEvent.GE_FINAL_STATE; -import static com.oracle.truffle.r.library.graphics.core.GraphicsEvent.GE_INIT_STATE; - -import com.oracle.truffle.r.library.grDevices.NullGraphicsDevice; -import com.oracle.truffle.r.library.grDevices.fastrgd.FastRGraphicsDevice; -import com.oracle.truffle.r.library.graphics.core.geometry.Coordinates; -import com.oracle.truffle.r.runtime.Utils; - -// todo implement 'active' devices array from devices.c -public final class GraphicsEngineImpl implements GraphicsEngine { - // GNUR: GraphicsEngine.h (original value: 24) - private static final int MAX_GRAPHICS_SYSTEMS_AMOUNT = 48; - private static final int MAX_GRAPHICS_DEVICES_AMOUNT = 64; - private static final int NULL_GRAPHICS_DEVICE_INDEX = 0; - private static final int LAST_GRAPHICS_DEVICE_INDEX = MAX_GRAPHICS_DEVICES_AMOUNT - 1; - private static final int NOT_FOUND = -1; - private static final GraphicsEngine instance = new GraphicsEngineImpl(); - - /** - * According to GNUR devices.c: 0 - null device, 63 - empty. - */ - private final GraphicsDevice[] graphicsDevices = new GraphicsDevice[MAX_GRAPHICS_DEVICES_AMOUNT]; - private final GraphicsSystem[] graphicsSystems = new AbstractGraphicsSystem[MAX_GRAPHICS_SYSTEMS_AMOUNT]; - - private int graphicsSystemsAmount = 0; - private int devicesAmountWithoutNullDevice = 0; - private CurrentGraphicsDevice currentGraphicsDevice = new CurrentGraphicsDevice(NullGraphicsDevice.getInstance(), NULL_GRAPHICS_DEVICE_INDEX); - - public static GraphicsEngine getInstance() { - return instance; - } - - private GraphicsEngineImpl() { - initNullGraphicsDevice(); - } - - /** - * According to GNUR 0 index is for the Null graphics device. - */ - private void initNullGraphicsDevice() { - graphicsDevices[NULL_GRAPHICS_DEVICE_INDEX] = NullGraphicsDevice.getInstance(); - } - - @Override - public void registerGraphicsSystem(GraphicsSystem newGraphicsSystem) throws Exception { - if (newGraphicsSystem == null) { - throw new NullPointerException("Graphics system to register is null"); - } - int index = findElementIndexInArray(null, graphicsSystems); // find null in the - // graphicsSystems - if (NOT_FOUND == index) { - throw handleErrorAndMakeException("too many graphics systems registered"); - } - newGraphicsSystem.setId(index); - graphicsSystems[index] = newGraphicsSystem; - callListenerForEachDevice(newGraphicsSystem.getGraphicsEventsListener(), GE_INIT_STATE); - graphicsSystemsAmount++; - } - - private void callListenerForEachDevice(AbstractGraphicsSystem.GraphicsEventsListener listener, GraphicsEvent event) { - if (noGraphicsDevices()) { - return; - } - for (int i = NULL_GRAPHICS_DEVICE_INDEX + 1; i < LAST_GRAPHICS_DEVICE_INDEX; i++) { - GraphicsDevice graphicsDevice = graphicsDevices[i]; - if (graphicsDevice != null) { - listener.onEvent(event, graphicsDevice); - } - } - } - - // todo transcribe error(_(msg)) from errors.c - private static Exception handleErrorAndMakeException(String message) { - return new Exception(message); - } - - // todo implement in GNUR way - private static void issueWarning(String warningMessage) { - Utils.warn(warningMessage); - } - - @Override - public void unRegisterGraphicsSystem(GraphicsSystem graphicsSystem) { - int graphicsSystemId = graphicsSystem.getId(); - checkGraphicsSystemIndex(graphicsSystemId); - if (graphicsSystemsAmount == 0) { - issueWarning("no graphics system to unregister"); - return; - } - callListenerForEachDevice(graphicsSystem.getGraphicsEventsListener(), GE_FINAL_STATE); - graphicsSystems[graphicsSystemId] = null; - graphicsSystemsAmount--; - } - - private void checkGraphicsSystemIndex(int graphicsSystemIndex) { - if (graphicsSystemIndex < 0 || graphicsSystemIndex >= graphicsSystems.length) { - throw new IllegalArgumentException("Wrong graphics system index: " + graphicsSystemIndex); - } - } - - // todo implement '.Devices' list related logic from GEaddDevices (devices.c) - @Override - public void registerGraphicsDevice(GraphicsDevice newGraphicsDevice) throws Exception { - if (newGraphicsDevice == null) { - throw new NullPointerException("Graphics device to register is null"); - } - if (!noGraphicsDevices()) { - getCurrentGraphicsDevice().deactivate(); - } - int index = findElementIndexInArray(NULL_GRAPHICS_DEVICE_INDEX + 1, LAST_GRAPHICS_DEVICE_INDEX, null, graphicsDevices); - if (index == NOT_FOUND) { - throw handleErrorAndMakeException("too many open devices"); - } - graphicsDevices[index] = newGraphicsDevice; - devicesAmountWithoutNullDevice++; - currentGraphicsDevice = new CurrentGraphicsDevice(newGraphicsDevice, index); - notifyEachGraphicsSystem(newGraphicsDevice, GE_INIT_STATE); - newGraphicsDevice.activate(); - } - - private void notifyEachGraphicsSystem(GraphicsDevice graphicsDevice, GraphicsEvent event) { - for (int i = 0; i < MAX_GRAPHICS_SYSTEMS_AMOUNT; i++) { - GraphicsSystem graphicsSystem = graphicsSystems[i]; - if (graphicsSystem != null) { - graphicsSystem.getGraphicsEventsListener().onEvent(event, graphicsDevice); - } - } - } - - @Override - public void unRegisterGraphicsDevice(GraphicsDevice deviceToUnregister) { - if (deviceToUnregister == null) { - throw new NullPointerException("Graphics device to unregister is null"); - } - doUnregisterGraphicsDevice(deviceToUnregister); - GraphicsDevice nextGraphicsDevice = getGraphicsDeviceNextTo(deviceToUnregister); - int index = findElementIndexInArray(nextGraphicsDevice, graphicsDevices); - currentGraphicsDevice = new CurrentGraphicsDevice(nextGraphicsDevice, index); - nextGraphicsDevice.activate(); - // todo Interesting that in GNUR a GraphicsSystem is not notified when a GraphicsDevice is - // killed - } - - private void doUnregisterGraphicsDevice(GraphicsDevice deviceToUnregister) { - int index = findElementIndexInArray(deviceToUnregister, graphicsDevices); - if (index == NOT_FOUND) { - issueWarning("no graphics device to unregister"); - return; - } - graphicsDevices[index] = null; - devicesAmountWithoutNullDevice--; - currentGraphicsDevice = new CurrentGraphicsDevice(getNullGraphicsDevice(), NULL_GRAPHICS_DEVICE_INDEX); - deviceToUnregister.close(); - } - - @Override - public int getGraphicsDevicesAmount() { - return devicesAmountWithoutNullDevice; - } - - @Override - public boolean noGraphicsDevices() { - return devicesAmountWithoutNullDevice == 0; - } - - @Override - public int getCurrentGraphicsDeviceIndex() { - return currentGraphicsDevice.graphicsDeviceIndex; - } - - @Override - public GraphicsDevice getCurrentGraphicsDevice() { - if (isNullDeviceIsCurrent()) { - try { - // todo transcribe device installation from GNUR GEcurrentDevice (devices.c) - installCurrentGraphicsDevice(); - } catch (Exception e) { - e.printStackTrace(); - } - } - return currentGraphicsDevice.graphicsDevice; - } - - private boolean isNullDeviceIsCurrent() { - return currentGraphicsDevice.graphicsDevice == getNullGraphicsDevice(); - } - - private void installCurrentGraphicsDevice() throws Exception { - registerGraphicsDevice(new FastRGraphicsDevice()); - } - - @Override - public GraphicsDevice getGraphicsDeviceNextTo(GraphicsDevice graphicsDevice) { - if (graphicsDevice == null) { - throw new NullPointerException("Graphics device is null"); - } - int startIndex = findElementIndexInArray(graphicsDevice, graphicsDevices); - if (startIndex == NOT_FOUND) { - return getNullGraphicsDevice(); - } - GraphicsDevice foundDevice = findNotNullGraphicsDevice(startIndex + 1, graphicsDevices.length, SearchDirection.FORWARD); - if (foundDevice == null) { - foundDevice = findNotNullGraphicsDevice(startIndex - 1, NULL_GRAPHICS_DEVICE_INDEX, SearchDirection.BACKWARD); - } - return foundDevice == null ? getNullGraphicsDevice() : foundDevice; - } - - @Override - public void setCurrentGraphicsDeviceMode(GraphicsDevice.Mode newMode) { - GraphicsDevice currentDevice = getCurrentGraphicsDevice(); - if (currentDevice.getMode() != newMode) { - currentDevice.setMode(newMode); - } - } - - @Override - public GraphicsDevice getGraphicsDevicePrevTo(GraphicsDevice graphicsDevice) { - if (graphicsDevice == null) { - throw new NullPointerException("Graphics device is null"); - } - int startIndex = findElementIndexInArray(graphicsDevice, graphicsDevices); - if (startIndex == NOT_FOUND) { - return getNullGraphicsDevice(); - } - GraphicsDevice foundDevice = findNotNullGraphicsDevice(startIndex - 1, NULL_GRAPHICS_DEVICE_INDEX, SearchDirection.BACKWARD); - if (foundDevice == null) { - foundDevice = findNotNullGraphicsDevice(startIndex + 1, graphicsDevices.length, SearchDirection.FORWARD); - } - return foundDevice == null ? getNullGraphicsDevice() : foundDevice; - } - - private static <T> int findElementIndexInArray(T element, T[] array) { - return findElementIndexInArray(0, array.length, element, array); - } - - private static <T> int findElementIndexInArray(int startIndexInclusive, int endIndexNotInclusive, T element, T[] array) { - for (int i = startIndexInclusive; i < endIndexNotInclusive; i++) { - if (array[i] == element) { - return i; - } - } - return NOT_FOUND; - } - - private GraphicsDevice findNotNullGraphicsDevice(int startIndexInclusive, int endIndexNotInclusive, SearchDirection direction) { - switch (direction) { - case FORWARD: - for (int i = startIndexInclusive; i < endIndexNotInclusive; i++) { - GraphicsDevice graphicsDevice = graphicsDevices[i]; - if (graphicsDevice != null) { - return graphicsDevice; - } - } - break; - case BACKWARD: - for (int i = startIndexInclusive; i > endIndexNotInclusive; i--) { - GraphicsDevice graphicsDevice = graphicsDevices[i]; - if (graphicsDevice != null) { - return graphicsDevice; - } - } - } - return getNullGraphicsDevice(); - } - - private GraphicsDevice getNullGraphicsDevice() { - return graphicsDevices[NULL_GRAPHICS_DEVICE_INDEX]; - } - - @Override - public void setCurrentGraphicsDeviceClipRect(double x1, double y1, double x2, double y2) { - // todo transcribe from GESetClip() (engine.c) - getCurrentGraphicsDevice().setClipRect(0, 0, 0, 0); - } - - @Override - public void drawPolyline(Coordinates coordinates, DrawingParameters drawingParameters) { - getCurrentGraphicsDevice().drawPolyline(coordinates, drawingParameters); - } - - @Override - public void killGraphicsDeviceByIndex(int graphicsDeviceIndex) { - // todo TBD - } - - private final class CurrentGraphicsDevice { - private final GraphicsDevice graphicsDevice; - private final int graphicsDeviceIndex; - - private CurrentGraphicsDevice(GraphicsDevice graphicsDevice, int graphicsDeviceIndex) { - this.graphicsDevice = graphicsDevice; - this.graphicsDeviceIndex = graphicsDeviceIndex; - } - } - - private enum SearchDirection { - FORWARD, - BACKWARD - } -} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/GraphicsEvent.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/GraphicsEvent.java deleted file mode 100644 index 5ff9cf1c50ef0a89089439190ac045e43bac3521..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/GraphicsEvent.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka - * Copyright (C) 1998 Ross Ihaka - * Copyright (c) 1998--2014, The R Core Team - * Copyright (c) 2002--2010, The R Foundation - * Copyright (C) 2005--2006, Morten Welinder - * Copyright (c) 2014, 2015, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.library.graphics.core; - -public enum GraphicsEvent { - GE_INIT_STATE, - GE_FINAL_STATE -} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/GraphicsSystem.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/GraphicsSystem.java deleted file mode 100644 index d0011a8c9a42eb6c9af5976901e6d20a283bea67..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/GraphicsSystem.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka - * Copyright (C) 1998 Ross Ihaka - * Copyright (c) 1998--2014, The R Core Team - * Copyright (c) 2002--2010, The R Foundation - * Copyright (C) 2005--2006, Morten Welinder - * Copyright (c) 2014, 2015, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.library.graphics.core; - -public interface GraphicsSystem { - GraphicsEventsListener getGraphicsEventsListener(); - - void setId(int id); - - int getId(); - - public interface GraphicsEventsListener { - void onEvent(GraphicsEvent graphicsEvent, GraphicsDevice graphicsDevice); - } -} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/GraphicsSystemParameters.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/GraphicsSystemParameters.java deleted file mode 100644 index 4d3ead19cad9736f8048aa38d04083add1bc47e4..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/GraphicsSystemParameters.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka - * Copyright (C) 1998 Ross Ihaka - * Copyright (c) 1998--2014, The R Core Team - * Copyright (c) 2002--2010, The R Foundation - * Copyright (C) 2005--2006, Morten Welinder - * Copyright (c) 2014, 2015, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.library.graphics.core; - -import java.util.HashMap; -import java.util.IdentityHashMap; -import java.util.Map; - -class GraphicsSystemParameters { - private final Map<GraphicsDevice, HashMap<String, Object>> parametersByDevices = new IdentityHashMap<>(); - - void addParameterForDevice(GraphicsDevice graphicsDevice, String parameterName, Object parameterValue) { - HashMap<String, Object> parameters = parametersByDevices.get(graphicsDevice); - if (parameters == null) { - parameters = new HashMap<>(); - parametersByDevices.put(graphicsDevice, parameters); - } - parameters.put(parameterName, parameterValue); - } - - Object getParameterForDevice(GraphicsDevice graphicsDevice, int parameterName) { - HashMap<String, Object> parameters = parametersByDevices.get(graphicsDevice); - return parameters == null ? null : parameters.get(parameterName); - } - - void removeAllParametersForDevice(GraphicsDevice graphicsDevice) { - parametersByDevices.remove(graphicsDevice); - } -} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/drawables/CoordinatesDrawableObject.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/drawables/CoordinatesDrawableObject.java deleted file mode 100644 index 4f641d7a79cf822ec0291cb4722a212e2d260587..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/drawables/CoordinatesDrawableObject.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka - * Copyright (C) 1998 Ross Ihaka - * Copyright (c) 1998--2014, The R Core Team - * Copyright (c) 2002--2010, The R Foundation - * Copyright (C) 2005--2006, Morten Welinder - * Copyright (c) 2014, 2015, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.library.graphics.core.drawables; - -import com.oracle.truffle.r.library.graphics.core.geometry.CoordinateSystem; -import com.oracle.truffle.r.library.graphics.core.geometry.Coordinates; -import com.oracle.truffle.r.library.graphics.core.geometry.IntCoordinates; - -/** - * Denotes an object which drawing depends only from {@link Coordinates}. And automates conversion - * from <code>srcCoordinates</code> to <code>dstCoordinates</code>. - */ -public abstract class CoordinatesDrawableObject extends DrawableObject { - private final Coordinates srcCoordinates; - - private Coordinates dstCoordinates; - - protected CoordinatesDrawableObject(CoordinateSystem coordinateSystem, Coordinates coordinates) { - super(coordinateSystem); - this.srcCoordinates = coordinates; - } - - @Override - public void recalculateForDrawingIn(CoordinateSystem dstCoordinateSystem) { - Coordinates converted = dstCoordinateSystem.convertCoordinatesFrom(getSrcCoordinateSystem(), srcCoordinates); - dstCoordinates = new IntCoordinates(converted.getXCoordinatesAsInts(), converted.getYCoordinatesAsInts()); - } - - protected final Coordinates getDstCoordinates() { - return dstCoordinates; - } -} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/drawables/DrawableObject.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/drawables/DrawableObject.java deleted file mode 100644 index ec4b0d5824ce7d9b9c677c3884b9755c06898c5d..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/drawables/DrawableObject.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka - * Copyright (C) 1998 Ross Ihaka - * Copyright (c) 1998--2014, The R Core Team - * Copyright (c) 2002--2010, The R Foundation - * Copyright (C) 2005--2006, Morten Welinder - * Copyright (c) 2014, 2016, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.library.graphics.core.drawables; - -import java.awt.Graphics2D; - -import com.oracle.truffle.r.library.graphics.core.geometry.CoordinateSystem; - -/** - * Denotes an object defined in <code>srcCoordinateSystem</code> that can be drawn in - * <code>dstCoordinateSystem</code> on {@link Graphics2D}. - */ -public abstract class DrawableObject { - private final CoordinateSystem srcCoordinateSystem; - - protected DrawableObject(CoordinateSystem srcCoordinateSystem) { - this.srcCoordinateSystem = srcCoordinateSystem; - } - - public abstract void drawOn(Graphics2D g2); - - /** - * Override to prepare coordinates given in <code>srcCoordinateSystem</code> to be drawn in - * <code>srcCoordinateSystem</code>. - */ - public abstract void recalculateForDrawingIn(CoordinateSystem dstCoordinateSystem); - - protected final CoordinateSystem getSrcCoordinateSystem() { - return srcCoordinateSystem; - } -} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/drawables/PolylineDrawableObject.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/drawables/PolylineDrawableObject.java deleted file mode 100644 index 2cf12e7f6aed8572cb9334b8d4241a24dd505012..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/drawables/PolylineDrawableObject.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka - * Copyright (C) 1998 Ross Ihaka - * Copyright (c) 1998--2014, The R Core Team - * Copyright (c) 2002--2010, The R Foundation - * Copyright (C) 2005--2006, Morten Welinder - * Copyright (c) 2014, 2016, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.library.graphics.core.drawables; - -import java.awt.Graphics2D; - -import com.oracle.truffle.r.library.graphics.core.geometry.CoordinateSystem; -import com.oracle.truffle.r.library.graphics.core.geometry.Coordinates; - -/** - * Able to draw a polyline on {@link Graphics2D}. - */ -public class PolylineDrawableObject extends CoordinatesDrawableObject { - public PolylineDrawableObject(CoordinateSystem coordinateSystem, Coordinates coordinates) { - super(coordinateSystem, coordinates); - } - - @Override - public void drawOn(Graphics2D g2) { - Coordinates coords = getDstCoordinates(); - int[] xCoords = coords.getXCoordinatesAsInts(); - g2.drawPolyline(xCoords, coords.getYCoordinatesAsInts(), xCoords.length); - } -} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/drawables/StringDrawableObject.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/drawables/StringDrawableObject.java deleted file mode 100644 index ccf4e16876bbd90c3b576366407838592916ff4f..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/drawables/StringDrawableObject.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka - * Copyright (C) 1998 Ross Ihaka - * Copyright (c) 1998--2014, The R Core Team - * Copyright (c) 2002--2010, The R Foundation - * Copyright (C) 2005--2006, Morten Welinder - * Copyright (c) 2014, 2016, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.library.graphics.core.drawables; - -import java.awt.Graphics2D; -import java.util.stream.IntStream; - -import com.oracle.truffle.r.library.graphics.core.geometry.CoordinateSystem; -import com.oracle.truffle.r.library.graphics.core.geometry.Coordinates; - -/** - * Able to render a text on {@link Graphics2D}. - */ -public class StringDrawableObject extends CoordinatesDrawableObject { - private final String[] strings; - - public StringDrawableObject(CoordinateSystem coordinateSystem, Coordinates coordinates, String[] strings) { - super(coordinateSystem, coordinates); - this.strings = strings; - } - - @Override - public void drawOn(Graphics2D g2) { - Coordinates dstCoordinates = getDstCoordinates(); - int[] xCoords = dstCoordinates.getXCoordinatesAsInts(); - int[] yCoords = dstCoordinates.getYCoordinatesAsInts(); - IntStream.range(0, strings.length).forEach(i -> g2.drawString(strings[i], xCoords[i], yCoords[i])); - } -} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/Axis.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/Axis.java deleted file mode 100644 index c9a33c65a82da57a5b2f57a5fb1c65dbc2203be4..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/Axis.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka - * Copyright (C) 1998 Ross Ihaka - * Copyright (c) 1998--2014, The R Core Team - * Copyright (c) 2002--2010, The R Foundation - * Copyright (C) 2005--2006, Morten Welinder - * Copyright (c) 2014, 2015, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.library.graphics.core.geometry; - -public final class Axis { - private final double minValue; - private final double maxValue; - private final AxisDirection direction; - - public Axis(double minValue, double maxValue, AxisDirection direction) { - this.minValue = minValue; - this.maxValue = maxValue; - this.direction = direction; - } - - public double getMinValue() { - return minValue; - } - - public double getMaxValue() { - return maxValue; - } - - public AxisDirection getDirection() { - return direction; - } - - public double getRange() { - return maxValue - minValue; - } -} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/AxisDirection.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/AxisDirection.java deleted file mode 100644 index 8099a58058eae00db737d42cc2c75a918ff9fcb0..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/AxisDirection.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka - * Copyright (C) 1998 Ross Ihaka - * Copyright (c) 1998--2014, The R Core Team - * Copyright (c) 2002--2010, The R Foundation - * Copyright (C) 2005--2006, Morten Welinder - * Copyright (c) 2014, 2015, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.library.graphics.core.geometry; - -public enum AxisDirection { - NORTH, - SOUTH, - WEST, - EAST -} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/CoordinateSystem.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/CoordinateSystem.java deleted file mode 100644 index 2c1fca3b817a003160c798290ea87c1d93c0d7f2..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/CoordinateSystem.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka - * Copyright (C) 1998 Ross Ihaka - * Copyright (c) 1998--2014, The R Core Team - * Copyright (c) 2002--2010, The R Foundation - * Copyright (C) 2005--2006, Morten Welinder - * Copyright (c) 2014, 2015, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.library.graphics.core.geometry; - -import java.util.stream.DoubleStream; - -/** - * Denotes X-Y coordinate system by specifying max and min values for X-Y axis. Able to convert - * coordinates given in another {@link CoordinateSystem} - */ -public final class CoordinateSystem { - private final Axis xAxis; - private final Axis yAxis; - - /** - * Uses Java graphics default axis orientation: x increases to the right, y increases to the - * bottom. - */ - public CoordinateSystem(double minX, double maxX, double minY, double maxY) { - this(minX, maxX, minY, maxY, AxisDirection.EAST, AxisDirection.SOUTH); - } - - public CoordinateSystem(double minX, double maxX, double minY, double maxY, AxisDirection xDirection, AxisDirection yDirection) { - this(new Axis(minX, maxX, xDirection), new Axis(minY, maxY, yDirection)); - } - - public CoordinateSystem(Axis xAxis, Axis yAxis) { - this.xAxis = xAxis; - this.yAxis = yAxis; - } - - /** - * Transforms <code> otherCoordinates </code> given in <code> otherCoordinateSystem</code> to - * this coordinate system. Also applies the affine transformation defined by ratio and shifts. - */ - public Coordinates convertCoordinatesFrom(CoordinateSystem otherCoordinateSystem, Coordinates otherCoordinates, double ratio, double xAxisShift, double yAxisShift) { - double[] resultX = convertCoordinatesBetweenAxises(getXAxis(), otherCoordinateSystem.getXAxis(), otherCoordinates.getXCoordinatesAsDoubles(), ratio, xAxisShift); - double[] resultY = convertCoordinatesBetweenAxises(getYAxis(), otherCoordinateSystem.getYAxis(), otherCoordinates.getYCoordinatesAsDoubles(), ratio, yAxisShift); - return new DoubleCoordinates(resultX, resultY); - } - - public Coordinates convertCoordinatesFrom(CoordinateSystem otherCoordinateSystem, Coordinates otherCoordinates) { - double noRatio = 1; - double noShift = 0; - return convertCoordinatesFrom(otherCoordinateSystem, otherCoordinates, noRatio, noShift, noShift); - } - - private static double[] convertCoordinatesBetweenAxises(Axis toAxis, Axis fromAxis, double[] coords, double givenRatio, double givenShift) { - boolean sameDirection = toAxis.getDirection() == fromAxis.getDirection(); - double ratio = toAxis.getRange() / fromAxis.getRange(); - ratio = sameDirection ? ratio : -ratio; - ratio *= givenRatio; // adding given ratio - double shift = sameDirection ? 0 : toAxis.getMaxValue(); - shift += givenShift * ratio; // adding given shift - return applyShiftAndRatio(coords, ratio, shift); - } - - private static double[] applyShiftAndRatio(double[] coords, double ratio, double shift) { - return DoubleStream.of(coords).map(d -> d * ratio + shift).toArray(); - } - - private Axis getXAxis() { - return xAxis; - } - - private Axis getYAxis() { - return yAxis; - } -} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/Coordinates.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/Coordinates.java deleted file mode 100644 index 95396232f26e67252041de67b3653756097f7c7c..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/Coordinates.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka - * Copyright (C) 1998 Ross Ihaka - * Copyright (c) 1998--2014, The R Core Team - * Copyright (c) 2002--2010, The R Foundation - * Copyright (C) 2005--2006, Morten Welinder - * Copyright (c) 2014, 2015, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.library.graphics.core.geometry; - -/** - * Denotes X-Y coordinates. Instances must be immutable objects. - */ -public interface Coordinates { - double[] getXCoordinatesAsDoubles(); - - double[] getYCoordinatesAsDoubles(); - - int[] getXCoordinatesAsInts(); - - int[] getYCoordinatesAsInts(); -} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/CoordinatesFactory.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/CoordinatesFactory.java deleted file mode 100644 index 33e81bb144b46109300d75c7c5881ace2e86b41b..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/CoordinatesFactory.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka - * Copyright (C) 1998 Ross Ihaka - * Copyright (c) 1998--2014, The R Core Team - * Copyright (c) 2002--2010, The R Foundation - * Copyright (C) 2005--2006, Morten Welinder - * Copyright (c) 2014, 2016, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.library.graphics.core.geometry; - -import java.util.Arrays; -import java.util.stream.DoubleStream; -import java.util.stream.IntStream; - -import com.oracle.truffle.r.runtime.data.RDoubleVector; - -public final class CoordinatesFactory { - private CoordinatesFactory() { - } - - public static DoubleCoordinates createWithSameX(double x, double[] yCoords) { - double[] xCoords = createdFilledArray(x, yCoords.length); - return new DoubleCoordinates(xCoords, yCoords); - } - - public static DoubleCoordinates createWithSameY(double[] xCoords, double y) { - double[] yCoords = createdFilledArray(y, xCoords.length); - return new DoubleCoordinates(xCoords, yCoords); - } - - private static double[] createdFilledArray(double value, int size) { - double[] result = new double[size]; - Arrays.fill(result, value); - return result; - } - - public static DoubleCoordinates createByXYVector(RDoubleVector xyVector) { - int length = xyVector.getLength(); - double[] xCoords = IntStream.range(0, length).filter(i -> i % 2 == 0).mapToDouble(xyVector::getDataAt).toArray(); - double[] yCoords = IntStream.range(0, length).filter(i -> i % 2 != 0).mapToDouble(xyVector::getDataAt).toArray(); - return new DoubleCoordinates(xCoords, yCoords); - } - - public static DoubleCoordinates createByXYPairs(double[] xyPairs) { - int length = xyPairs.length; - double[] xCoords = IntStream.range(0, length).filter(i -> i % 2 == 0).mapToDouble(i -> xyPairs[i]).toArray(); - double[] yCoords = IntStream.range(0, length).filter(i -> i % 2 != 0).mapToDouble(i -> xyPairs[i]).toArray(); - return new DoubleCoordinates(xCoords, yCoords); - } - - public static DoubleCoordinates withRatioAndShift(Coordinates coordinates, double ratio, double shift) { - return withRatioAndShift(coordinates, ratio, shift, shift); - } - - public static DoubleCoordinates withRatioAndShift(Coordinates coordinates, double ratio, double xShift, double yShift) { - double[] convertedX = applyRatioAndShiftTo(coordinates.getXCoordinatesAsDoubles(), ratio, xShift); - double[] convertedY = applyRatioAndShiftTo(coordinates.getYCoordinatesAsDoubles(), ratio, yShift); - return new DoubleCoordinates(convertedX, convertedY); - } - - private static double[] applyRatioAndShiftTo(double[] coordinates, double ratio, double shift) { - return DoubleStream.of(coordinates).map(d -> d * ratio + shift).toArray(); - } -} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/DoubleCoordinates.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/DoubleCoordinates.java deleted file mode 100644 index 90dcb51dd61f9b8f234b097f6b5ff97531aff1af..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/DoubleCoordinates.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka - * Copyright (C) 1998 Ross Ihaka - * Copyright (c) 1998--2014, The R Core Team - * Copyright (c) 2002--2010, The R Foundation - * Copyright (C) 2005--2006, Morten Welinder - * Copyright (c) 2014, 2016, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.library.graphics.core.geometry; - -import java.util.stream.DoubleStream; - -public final class DoubleCoordinates implements Coordinates { - - private final double[] xCoords; - private final double[] yCoords; - - public DoubleCoordinates(double[] xCoords, double[] yCoords) { - this.xCoords = xCoords; - this.yCoords = yCoords; - } - - @Override - public double[] getXCoordinatesAsDoubles() { - return xCoords; - } - - @Override - public double[] getYCoordinatesAsDoubles() { - return yCoords; - } - - @Override - public int[] getXCoordinatesAsInts() { - return toInt(getXCoordinatesAsDoubles()); - } - - @Override - public int[] getYCoordinatesAsInts() { - return toInt(getYCoordinatesAsDoubles()); - } - - private static int[] toInt(double[] doubleArray) { - return DoubleStream.of(doubleArray).mapToInt(d -> (int) d).toArray(); - } -} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/IntCoordinates.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/IntCoordinates.java deleted file mode 100644 index cd62ef35fe6eca47082d6314c2852f7daec5f8c1..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/IntCoordinates.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka - * Copyright (C) 1998 Ross Ihaka - * Copyright (c) 1998--2014, The R Core Team - * Copyright (c) 2002--2010, The R Foundation - * Copyright (C) 2005--2006, Morten Welinder - * Copyright (c) 2014, 2015, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.library.graphics.core.geometry; - -import java.util.stream.IntStream; - -public final class IntCoordinates implements Coordinates { - private final int[] xCoords; - private final int[] yCoords; - - public IntCoordinates(int[] xCoords, int[] yCoords) { - this.xCoords = xCoords; - this.yCoords = yCoords; - } - - @Override - public double[] getXCoordinatesAsDoubles() { - return toDouble(xCoords); - } - - @Override - public double[] getYCoordinatesAsDoubles() { - return toDouble(yCoords); - } - - @Override - public int[] getXCoordinatesAsInts() { - return xCoords; - } - - @Override - public int[] getYCoordinatesAsInts() { - return yCoords; - } - - private static double[] toDouble(int[] intArray) { - return IntStream.of(intArray).mapToDouble(i -> i).toArray(); - } -} diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java index 16e97d3504be001bfc427e6ff7b491f67f484b17..ac9d5aa0bc70311575eb482b5521b1207fb2f4fa 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java @@ -25,6 +25,7 @@ package com.oracle.truffle.r.nodes.builtin.base; import java.util.function.Supplier; import com.oracle.truffle.api.frame.MaterializedFrame; +import com.oracle.truffle.r.library.fastrGrid.DoSetViewPortBuiltin; import com.oracle.truffle.r.nodes.RRootNode; import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode; import com.oracle.truffle.r.nodes.binary.BinaryArithmeticNodeGen; @@ -717,6 +718,9 @@ public class BasePackage extends RBuiltinPackage { add(UpdateSubset.class, UpdateSubsetNodeGen::create, UpdateSubset::special); add(UpdateField.class, UpdateFieldNodeGen::create, UpdateField::createSpecial); add(WhileBuiltin.class, WhileBuiltinNodeGen::create); + + // grid intrinsics + add(DoSetViewPortBuiltin.class, DoSetViewPortBuiltin::create); } private void addBinaryArithmetic(Class<?> builtinClass, BinaryArithmeticFactory binaryFactory, UnaryArithmeticFactory unaryFactory) { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java index ab28e791fd8d730b36e6b70e815fb86459e08692..b7bee9a581eb1f2add866a49558752b2e3e1eb72 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java @@ -22,12 +22,7 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.r.library.grDevices.DevicesCCalls; -import com.oracle.truffle.r.library.graphics.GraphicsCCalls; -import com.oracle.truffle.r.library.graphics.GraphicsCCalls.C_Par; -import com.oracle.truffle.r.library.graphics.GraphicsCCalls.C_PlotXY; -import com.oracle.truffle.r.library.grid.GridFunctionsFactory.InitGridNodeGen; -import com.oracle.truffle.r.library.grid.GridFunctionsFactory.ValidUnitsNodeGen; +import com.oracle.truffle.r.library.fastrGrid.FastRGridExternalLookup; import com.oracle.truffle.r.library.methods.MethodsListDispatchFactory.R_M_setPrimitiveMethodsNodeGen; import com.oracle.truffle.r.library.methods.MethodsListDispatchFactory.R_externalPtrPrototypeObjectNodeGen; import com.oracle.truffle.r.library.methods.MethodsListDispatchFactory.R_getClassFromCacheNodeGen; @@ -55,10 +50,10 @@ import com.oracle.truffle.r.library.stats.RandFunctionsNodes.RandFunction3Node; import com.oracle.truffle.r.library.stats.SignrankFreeNode; import com.oracle.truffle.r.library.stats.SplineFunctionsFactory.SplineCoefNodeGen; import com.oracle.truffle.r.library.stats.SplineFunctionsFactory.SplineEvalNodeGen; -import com.oracle.truffle.r.library.stats.deriv.D; -import com.oracle.truffle.r.library.stats.deriv.Deriv; import com.oracle.truffle.r.library.stats.StatsFunctionsNodes; import com.oracle.truffle.r.library.stats.WilcoxFreeNode; +import com.oracle.truffle.r.library.stats.deriv.D; +import com.oracle.truffle.r.library.stats.deriv.Deriv; import com.oracle.truffle.r.library.tools.C_ParseRdNodeGen; import com.oracle.truffle.r.library.tools.DirChmodNodeGen; import com.oracle.truffle.r.library.tools.Rmd5NodeGen; @@ -79,6 +74,7 @@ import com.oracle.truffle.r.nodes.objects.NewObjectNodeGen; import com.oracle.truffle.r.runtime.FastROptions; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RInternalCode; +import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; @@ -240,6 +236,12 @@ public class CallAndExternalFunctions { @TruffleBoundary protected RExternalBuiltinNode lookupBuiltin(RList symbol) { String name = lookupName(symbol); + if (FastROptions.UseInternalGridGraphics.getBooleanValue() && name != null) { + RExternalBuiltinNode gridExternal = FastRGridExternalLookup.lookupDotCall(name); + if (gridExternal != null) { + return gridExternal; + } + } switch (name) { // methods case "R_initMethodDispatch": @@ -629,24 +631,6 @@ public class CallAndExternalFunctions { // parallel case "mc_is_child": return MCIsChildNodeGen.create(); - default: - return FastROptions.UseInternalGraphics.getBooleanValue() ? lookupGraphicsBuiltin(name) : null; - } - } - - private static RExternalBuiltinNode lookupGraphicsBuiltin(String name) { - switch (name) { - // grDevices - case "cairoProps": - return CairoPropsNodeGen.create(); - case "makeQuartzDefault": - return new MakeQuartzDefault(); - - // grid - case "L_initGrid": - return InitGridNodeGen.create(); - case "L_validUnits": - return ValidUnitsNodeGen.create(); default: return null; } @@ -656,7 +640,7 @@ public class CallAndExternalFunctions { * {@code .NAME = NativeSymbolInfo} implemented as a builtin. */ @SuppressWarnings("unused") - @Specialization(limit = "1", guards = {"cached == symbol", "builtin != null"}) + @Specialization(limit = "99", guards = {"cached == symbol", "builtin != null"}) protected Object doExternal(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, Object packageName, @Cached("symbol") RList cached, @Cached("lookupBuiltin(symbol)") RExternalBuiltinNode builtin) { @@ -668,9 +652,10 @@ public class CallAndExternalFunctions { * package) */ @SuppressWarnings("unused") - @Specialization(limit = "2", guards = {"cached == symbol"}) + @Specialization(limit = "2", guards = {"cached == symbol", "builtin == null"}) protected Object callNamedFunction(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, Object packageName, @Cached("symbol") RList cached, + @Cached("lookupBuiltin(symbol)") RExternalBuiltinNode builtin, @Cached("extractSymbolInfo(frame, symbol)") NativeCallInfo nativeCallInfo) { return callRFFINode.execute(nativeCallInfo, args.getArguments()); } @@ -680,8 +665,12 @@ public class CallAndExternalFunctions { * such cases there is this generic version. */ @SuppressWarnings("unused") - @Specialization(replaces = "callNamedFunction") + @Specialization(replaces = {"callNamedFunction", "doExternal"}) protected Object callNamedFunctionGeneric(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, Object packageName) { + RExternalBuiltinNode builtin = lookupBuiltin(symbol); + if (builtin != null) { + throw RInternalError.shouldNotReachHere("Cache for .Calls with FastR reimplementation (lookupBuiltin(...) != null) exceeded the limit"); + } NativeCallInfo nativeCallInfo = extractSymbolInfo(frame, symbol); return callRFFINode.execute(nativeCallInfo, args.getArguments()); } @@ -733,14 +722,10 @@ public class CallAndExternalFunctions { @TruffleBoundary protected RExternalBuiltinNode lookupBuiltin(RList f) { String name = lookupName(f); - if (FastROptions.UseInternalGraphics.getBooleanValue()) { - switch (name) { - case "PDF": - return new DevicesCCalls.C_PDF(); - case "devoff": - return DevicesCCalls.C_DevOff.create(); - case "devcur": - return new DevicesCCalls.C_DevCur(); + if (FastROptions.UseInternalGridGraphics.getBooleanValue()) { + RExternalBuiltinNode gridExternal = FastRGridExternalLookup.lookupDotExternal(name); + if (gridExternal != null) { + return gridExternal; } } switch (name) { @@ -854,13 +839,13 @@ public class CallAndExternalFunctions { @Override @TruffleBoundary protected RExternalBuiltinNode lookupBuiltin(RList symbol) { - if (FastROptions.UseInternalGraphics.getBooleanValue()) { - switch (lookupName(symbol)) { - case "C_par": - return new C_Par(); + String name = lookupName(symbol); + if (FastROptions.UseInternalGridGraphics.getBooleanValue()) { + RExternalBuiltinNode gridExternal = FastRGridExternalLookup.lookupDotExternal2(name); + if (gridExternal != null) { + return gridExternal; } } - String name = lookupName(symbol); switch (name) { // tools case "writetable": @@ -929,14 +914,6 @@ public class CallAndExternalFunctions { @Override @TruffleBoundary protected RExternalBuiltinNode lookupBuiltin(RList f) { - if (FastROptions.UseInternalGraphics.getBooleanValue()) { - switch (lookupName(f)) { - case "C_mtext": - return new GraphicsCCalls.C_mtext(); - case "C_plotXY": - return new C_PlotXY(); - } - } return null; } diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/ExtBuiltinsList.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/ExtBuiltinsList.java index 98eb067b7a6a144ec15572ed5ce698a971c85cd2..1035f57473bb7f0193a228c9faaac48d2cd6fddf 100644 --- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/ExtBuiltinsList.java +++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/ExtBuiltinsList.java @@ -58,12 +58,6 @@ public class ExtBuiltinsList { com.oracle.truffle.r.library.tools.Rmd5NodeGen.class, com.oracle.truffle.r.library.tools.DirChmodNodeGen.class, com.oracle.truffle.r.library.tools.C_ParseRdNodeGen.class, - com.oracle.truffle.r.library.grDevices.DevicesCCallsFactory.C_DevOffNodeGen.class, - com.oracle.truffle.r.library.grDevices.DevicesCCalls.C_DevCur.class, - com.oracle.truffle.r.library.grDevices.DevicesCCalls.C_PDF.class, - com.oracle.truffle.r.library.graphics.GraphicsCCalls.C_PlotXY.class, - com.oracle.truffle.r.library.graphics.GraphicsCCalls.C_Par.class, - com.oracle.truffle.r.library.graphics.GraphicsCCalls.C_mtext.class, com.oracle.truffle.r.library.stats.WilcoxFreeNode.class, com.oracle.truffle.r.library.stats.StatsFunctionsNodesFactory.Function3_2NodeGen.class, com.oracle.truffle.r.library.stats.StatsFunctionsNodesFactory.Function4_1NodeGen.class, diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java index 925e1f39042c3510b80c4d18eb2f1cdbcb18bd93..24f998565a1d465f9bf3e16285bd485ea2cf431a 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java @@ -51,7 +51,7 @@ public enum FastROptions { FullPrecisionSum("Use 128 bit arithmetic in sum builtin", false), InvisibleArgs("Argument writes do not trigger state transitions", true), RefCountIncrementOnly("Disable reference count decrements for experimental state transition implementation", false), - UseInternalGraphics("Whether the internal (Java) graphics subsystem should be used", false), + UseInternalGridGraphics("Whether the internal (Java) grid graphics implementation should be used", false), UseSpecials("Whether the fast-path special call nodes should be created for simple enough arguments.", true), ForceSources("Generate source sections for unserialized code", false), diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java index c999db5a78e8e5a78182682ed4d41e9a57e2801b..32d4e8881858f429fa8a630ce55be34b9f4e4001 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java @@ -211,6 +211,17 @@ public final class RPairList extends RSharingAttributeStorage implements RAbstra return type; } + /** + * Appends given value as the last element of the pairlist. + */ + public void appendToEnd(RPairList value) { + RPairList last = null; + for (RPairList item : this) { + last = item; + } + last.setCdr(value); + } + @Override public boolean isComplete() { // TODO: is it important to get more precise information here? diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastrGrid/GridColorUtilsTests.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastrGrid/GridColorUtilsTests.java new file mode 100644 index 0000000000000000000000000000000000000000..8e43a26774ed8279b5b93faf526f3e1889520dc0 --- /dev/null +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastrGrid/GridColorUtilsTests.java @@ -0,0 +1,93 @@ +/* + * 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.test.library.fastrGrid; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.oracle.truffle.r.library.fastrGrid.GridColorUtils; +import com.oracle.truffle.r.library.fastrGrid.device.GridColor; +import com.oracle.truffle.r.test.TestBase; + +public class GridColorUtilsTests extends TestBase { + @Test + public void convertFromHex() { + GridColor color = GridColorUtils.gridColorFromString("#FF01FE"); + assertEquals(255, color.getRed()); + assertEquals(1, color.getGreen()); + assertEquals(254, color.getBlue()); + assertEquals(255, color.getAlpha()); + } + + @Test + public void convertFromHexWithAlpha() { + GridColor color = GridColorUtils.gridColorFromString("#FF00FE02"); + assertEquals(255, color.getRed()); + assertEquals(0, color.getGreen()); + assertEquals(254, color.getBlue()); + assertEquals(02, color.getAlpha()); + } + + @Test + public void convertSynonymBlack() { + GridColor black = GridColorUtils.gridColorFromString("black"); + assertEquals(0, black.getRed()); + assertEquals(0, black.getGreen()); + assertEquals(0, black.getBlue()); + assertEquals(255, black.getAlpha()); + } + + @Test + public void convertSynonymUpercaseRed() { + GridColor black = GridColorUtils.gridColorFromString("RED"); + assertEquals(255, black.getRed()); + assertEquals(0, black.getGreen()); + assertEquals(0, black.getBlue()); + assertEquals(255, black.getAlpha()); + } + + @Test + public void convertSynonymLightGreenWithSpace() { + GridColor black = GridColorUtils.gridColorFromString("light green"); + assertEquals(0x90, black.getRed()); + assertEquals(0xee, black.getGreen()); + assertEquals(0x90, black.getBlue()); + assertEquals(255, black.getAlpha()); + } + + @Test + public void convertSynonymLightGreen() { + GridColor black = GridColorUtils.gridColorFromString("light green"); + assertEquals(0x90, black.getRed()); + assertEquals(0xee, black.getGreen()); + assertEquals(0x90, black.getBlue()); + assertEquals(255, black.getAlpha()); + } + + @Test + public void convertSynonymTransparent() { + GridColor transparent = GridColorUtils.gridColorFromString("transparent"); + assertEquals(0, transparent.getAlpha()); + } +} diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides index f6786e5110ab80a04fbc540258a0b5e20b71bfcc..d3c6075238f30f0347d2ed8f3bb85f70613cd644 100644 --- a/mx.fastr/copyrights/overrides +++ b/mx.fastr/copyrights/overrides @@ -1,30 +1,5 @@ -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/BaseGraphicsSystem.java,gnu_r_graphics.copyright -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/AbstractGraphicsSystem.java,gnu_r_graphics.copyright -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/drawables/CoordinatesDrawableObject.java,gnu_r_graphics.copyright -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/drawables/DrawableObject.java,gnu_r_graphics.copyright -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/drawables/PolylineDrawableObject.java,gnu_r_graphics.copyright -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/drawables/StringDrawableObject.java,gnu_r_graphics.copyright -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/DrawingParameters.java,gnu_r_graphics.copyright -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/Axis.java,gnu_r_graphics.copyright -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/AxisDirection.java,gnu_r_graphics.copyright -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/Coordinates.java,gnu_r_graphics.copyright -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/CoordinatesFactory.java,gnu_r_graphics.copyright -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/CoordinateSystem.java,gnu_r_graphics.copyright -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/DoubleCoordinates.java,gnu_r_graphics.copyright -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/geometry/IntCoordinates.java,gnu_r_graphics.copyright -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/GraphicsDevice.java,gnu_r_graphics.copyright -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/GraphicsEngine.java,gnu_r_graphics.copyright -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/GraphicsEngineImpl.java,gnu_r_graphics.copyright -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/GraphicsEvent.java,gnu_r_graphics.copyright -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/GraphicsSystem.java,gnu_r_graphics.copyright -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/GraphicsSystemParameters.java,gnu_r_graphics.copyright -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/FastRComponent.java,gnu_r_graphics.copyright -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/GraphicsCCalls.java,gnu_r_graphics.copyright com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/RGraphics.java,gnu_r_graphics.copyright -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/DevicesCCalls.java,gnu_r_graphics.copyright -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/fastrgd/FastRGraphicsDevice.java,gnu_r_graphics.copyright -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/NullGraphicsDevice.java,gnu_r_graphics.copyright -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/pdf/PdfGraphicsDevice.java,gnu_r_graphics.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/graphics/RGridGraphicsAdapter.java,gnu_r_graphics.copyright com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grid/GridFunctions.java,gnu_r_murrel_core.copyright com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java,gnu_r.copyright com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/Slot.java,gnu_r.copyright @@ -766,3 +741,30 @@ com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/p com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PairListPrinter.java,gnu_r_gentleman_ihaka2.copyright com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/deriv/Deriv.java,gnu_r_gentleman_ihaka2.copyright com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/deriv/DerivVisitor.java,gnu_r_gentleman_ihaka2.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LRect.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DrawArrowsNode.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LPoints.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridState.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPortBuiltin.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LUpViewPort.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LNewPage.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LInitGrid.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LInitViewPortStack.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GPar.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/TransformMatrix.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LSegments.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPort.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LUnsetViewPort.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/ViewPort.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridUtils.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/Unit.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/ViewPortLocation.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/ViewPortContext.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridLinesNode.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/ViewPortTransform.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LGridDirty.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridColorUtils.java,gnu_r.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LCircle.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/EdgeDetection.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridTextNode.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LConvert.java,gnu_r_murrel_core.copyright diff --git a/mx.fastr/mx_fastr.py b/mx.fastr/mx_fastr.py index 782257b532a78329e952b39f4c02db0d82a52882..259351b416143f772c52d0fbfb08dc3e71ffb675 100644 --- a/mx.fastr/mx_fastr.py +++ b/mx.fastr/mx_fastr.py @@ -404,7 +404,7 @@ def _test_subpackage(name): return '.'.join((_test_package(), name)) def _simple_generated_unit_tests(): - return ','.join(map(_test_subpackage, ['engine.shell', 'library.base', 'library.grid', 'library.methods', 'library.stats', 'library.utils', 'library.fastr', 'builtins', 'functions', 'parser', 'rng', 'runtime.data', 'S4'])) + return ','.join(map(_test_subpackage, ['engine.shell', 'library.base', 'library.fastrGrid', 'library.methods', 'library.stats', 'library.utils', 'library.fastr', 'builtins', 'functions', 'parser', 'rng', 'runtime.data', 'S4'])) def _simple_unit_tests(): return ','.join([_simple_generated_unit_tests(), _test_subpackage('tck')])