/* * Copyright (c) 2012, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 javafx.scene.canvas; import com.sun.javafx.geom.Arc2D; import com.sun.javafx.geom.IllegalPathStateException; import com.sun.javafx.geom.Path2D; import com.sun.javafx.geom.PathIterator; import com.sun.javafx.geom.transform.Affine2D; import com.sun.javafx.geom.transform.NoninvertibleTransformException; import com.sun.javafx.image.*; import com.sun.javafx.image.impl.ByteBgraPre; import com.sun.javafx.sg.prism.GrowableDataBuffer; import com.sun.javafx.sg.prism.NGCanvas; import com.sun.javafx.text.FontHelper; import com.sun.javafx.tk.Toolkit; import com.sun.scenario.effect.EffectHelper; import javafx.geometry.NodeOrientation; import javafx.geometry.VPos; import javafx.scene.effect.Blend; import javafx.scene.effect.BlendMode; import javafx.scene.effect.Effect; import javafx.scene.image.Image; import javafx.scene.image.PixelFormat; import javafx.scene.image.PixelReader; import javafx.scene.image.PixelWriter; import javafx.scene.paint.Color; import javafx.scene.paint.Paint; import javafx.scene.shape.ArcType; import javafx.scene.shape.FillRule; import javafx.scene.shape.StrokeLineCap; import javafx.scene.shape.StrokeLineJoin; import javafx.scene.text.Font; import javafx.scene.text.TextAlignment; import javafx.scene.transform.Affine; import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.util.Arrays; import java.util.LinkedList; import javafx.scene.text.FontSmoothingType; /** * This class is used to issue draw calls to a {@code Canvas} using a buffer. *
* Each call pushes the necessary parameters onto the buffer * where they will be later rendered onto the image of the {@code Canvas} node * by the rendering thread at the end of a pulse. *
* A {@code Canvas} only contains one {@code GraphicsContext}, and only one buffer. * If it is not attached to any scene, then it can be modified by any thread, * as long as it is only used from one thread at a time. Once a {@code Canvas} * node is attached to a scene, it must be modified on the JavaFX Application * Thread. *
* Calling any method on the {@code GraphicsContext} is considered modifying * its corresponding {@code Canvas} and is subject to the same threading * rules. *
* A {@code GraphicsContext} also manages a stack of state objects that can * be saved or restored at anytime. *
* The {@code GraphicsContext} maintains the following rendering attributes * which affect various subsets of the rendering methods: *
Attribute | *Save/Restore? | *Default value | *Description | *
---|---|---|---|
Common Rendering Attributes | |||
{@link #clip() Clip} | *Yes | *No clipping | ** An anti-aliased intersection of various clip paths to which rendering * is restricted. * |
{@link #setGlobalAlpha(double) Global Alpha} | *Yes | *{@code 1.0} | ** An opacity value that controls the visibility or fading of each rendering * operation. * |
{@link #setGlobalBlendMode(javafx.scene.effect.BlendMode) Global Blend Mode} | *Yes | *{@link BlendMode#SRC_OVER SRC_OVER} | ** A {@link BlendMode} enum value that controls how pixels from each rendering * operation are composited into the existing image. * |
{@link #setTransform(javafx.scene.transform.Affine) Transform} | *Yes | *{@code Identity} | ** A 3x2 2D affine transformation matrix that controls how coordinates are * mapped onto the logical pixels of the canvas image. * |
{@link #setEffect(javafx.scene.effect.Effect) Effect} | *Yes | *{@code null} | ** An {@link Effect} applied individually to each rendering operation. * |
Fill Attributes | |||
{@link #setFill(javafx.scene.paint.Paint) Fill Paint} | *Yes | *{@link Color#BLACK BLACK} | ** The {@link Paint} to be applied to the interior of shapes in a * fill operation. * |
Stroke Attributes | |||
{@link #setStroke(javafx.scene.paint.Paint) Stroke Paint} | *Yes | *{@link Color#BLACK BLACK} | ** The {@link Paint} to be applied to the boundary of shapes in a * stroke operation. * |
{@link #setLineWidth(double) Line Width} | *Yes | *{@code 1.0} | ** The width of the stroke applied to the boundary of shapes in a * stroke operation. * |
{@link #setLineCap(javafx.scene.shape.StrokeLineCap) Line Cap} | *Yes | *{@link StrokeLineCap#SQUARE SQUARE} | ** The style of the end caps applied to the beginnings and ends of each * dash and/or subpath in a stroke operation. * |
{@link #setLineJoin(javafx.scene.shape.StrokeLineJoin) Line Join} | *Yes | *{@link StrokeLineJoin#MITER MITER} | ** The style of the joins applied between individual segments in the boundary * paths of shapes in a stroke operation. * |
{@link #setMiterLimit(double) Miter Limit} | *Yes | *{@code 10.0} | ** The ratio limit of how far a {@link StrokeLineJoin#MITER MITER} line join * may extend in the direction of a sharp corner between segments in the * boundary path of a shape, relative to the line width, before it is truncated * to a {@link StrokeLineJoin#BEVEL BEVEL} join in a stroke operation. * |
{@link #setLineDashes(double...) Dashes} | *Yes | *{@code null} | ** The array of dash lengths to be applied to the segments in the boundary * of shapes in a stroke operation. * |
{@link #setLineDashOffset(double) Dash Offset} | *Yes | *{@code 0.0} | ** The distance offset into the array of dash lengths at which to start the * dashing of the segments in the boundary of shapes in a stroke operation. * |
Text Attributes | |||
{@link #setFont(javafx.scene.text.Font) Font} | *Yes | *{@link Font#getDefault() Default Font} | ** The font used for all fill and stroke text operations. * |
{@link #setTextAlign(javafx.scene.text.TextAlignment) Text Align} | *Yes | *{@link TextAlignment#LEFT LEFT} | ** The horizontal alignment of text with respect to the {@code X} coordinate * specified in the text operation. * |
{@link #setTextBaseline(javafx.geometry.VPos) Text Baseline} | *Yes | *{@link VPos#BASELINE BASELINE} | ** The vertical position of the text relative to the {@code Y} coordinate * specified in the text operation. * |
{@link #setFontSmoothingType(javafx.scene.text.FontSmoothingType) Font Smoothing} | *Yes | *{@link FontSmoothingType#GRAY GRAY} | ** The type of smoothing (antialiasing) applied to the glyphs in the font * for all fill text operations. * |
Path Attributes | |||
{@link #beginPath() Current Path} | *No | *Empty path | ** The path constructed using various path construction methods to be used * in various path filling, stroking, or clipping operations. * |
{@link #setFillRule(javafx.scene.shape.FillRule) Fill Rule} | *Yes | *{@link FillRule#NON_ZERO NON_ZERO} | ** The method used to determine the interior of paths for a path fill or * clip operation. * |
Method | *Common Rendering Attributes | *Fill Attributes | *Stroke Attributes | *Text Attributes | *Path Attributes | *
---|---|---|---|---|---|
Basic Shape Rendering | |||||
* * {@link #fillRect(double, double, double, double) fillRect()}, * {@link #fillRoundRect(double, double, double, double, double, double) fillRoundRect()}, * {@link #fillOval(double, double, double, double) fillOval()}, * {@link #fillArc(double, double, double, double, double, double, javafx.scene.shape.ArcType) fillArc()} * * | *Yes | *Yes | *No | *No | *No | *
* * {@link #strokeLine(double, double, double, double) strokeLine()}, * {@link #strokeRect(double, double, double, double) strokeRect()}, * {@link #strokeRoundRect(double, double, double, double, double, double) strokeRoundRect()}, * {@link #strokeOval(double, double, double, double) strokeOval()}, * {@link #strokeArc(double, double, double, double, double, double, javafx.scene.shape.ArcType) strokeArc()} * * | *Yes | *No | *Yes | *No | *No | *
* * {@link #clearRect(double, double, double, double) clearRect()} * * | *Yes [1] | *No | *No | *No | *No | *
* * {@link #fillPolygon(double[], double[], int) fillPolygon()} * * | *Yes | *Yes | *No | *No | *Yes [2] | *
* * {@link #strokePolygon(double[], double[], int) strokePolygon()}, * {@link #strokePolyline(double[], double[], int) strokePolyline()} * * | *Yes | *No | *Yes | *No | *No | *
* [1] Only the Transform, Clip, and Effect apply to clearRect() | |||||
Text Rendering | |||||
* * {@link #fillText(java.lang.String, double, double) fillText()}, * {@link #fillText(java.lang.String, double, double, double) fillText(with maxWidth)} * * | *Yes | *Yes | *No | *Yes [3] | *No | *
* * {@link #strokeText(java.lang.String, double, double) strokeText()}, * {@link #strokeText(java.lang.String, double, double, double) strokeText(with maxWidth)} * * | *Yes | *No | *Yes | *Yes [3] | *No | *
* [3] The Font Smoothing attribute only applies to filled text * | |||||
Path Rendering | |||||
* {@link #beginPath() beginPath()}, * {@link #moveTo(double, double) moveTo()}, * {@link #lineTo(double, double) lineTo()}, * {@link #quadraticCurveTo(double, double, double, double) quadraticCurveTo()}, * {@link #bezierCurveTo(double, double, double, double, double, double) bezierCurveTo()}, * {@link #arc(double, double, double, double, double, double) arc()}, * {@link #arcTo(double, double, double, double, double) arcTo()}, * {@link #appendSVGPath(java.lang.String) appendSVGPath()}, * {@link #closePath() closePath()}, * {@link #rect(double, double, double, double) rect()} * | *Yes [4] | *No | *No | *No | *No | *
* * {@link #fill() fill()} * * | *Yes [4] | *Yes | *No | *No | *Yes | *
* * {@link #stroke() stroke()} * * | *Yes [4] | *No | *Yes | *No | *Yes [5] | *
* * {@link #clip() clip()} * * | *No | *No | *No | *No | *Yes | *
* [4] Transform applied only during path construction | |||||
Image Rendering | |||||
* * {@link #drawImage(javafx.scene.image.Image, double, double) drawImage(all forms)} * * | *Yes | *No | *No | *No | *No | *
Miscellaneous | |||||
* {@link #applyEffect(javafx.scene.effect.Effect) applyEffect()}, * {@link #getPixelWriter() PixelWriter methods} * | *No | *No | *No | *No | *No | *
Example:
* **
import javafx.scene.*; import javafx.scene.paint.*; import javafx.scene.canvas.*; Group root = new Group(); Scene s = new Scene(root, 300, 300, Color.BLACK); final Canvas canvas = new Canvas(250,250); GraphicsContext gc = canvas.getGraphicsContext2D(); gc.setFill(Color.BLUE); gc.fillRect(75,75,100,100); root.getChildren().add(canvas); ** * * @since JavaFX 2.2 */ public final class GraphicsContext { Canvas theCanvas; Path2D path; boolean pathDirty; State curState; LinkedList
* Note that the {@code FontSmoothingType} value of * {@link FontSmoothingType#LCD LCD} is only supported over an opaque * background. {@code LCD} text will generally appear as {@code GRAY} * text over transparent or partially transparent pixels, and in some * implementations it may not be supported at all on a {@link Canvas} * because the required support does not exist for surfaces which contain * an alpha channel as all {@code Canvas} objects do. * * @param fontsmoothing the {@link FontSmoothingType} or null * @since JavaFX 8u40 */ public void setFontSmoothingType(FontSmoothingType fontsmoothing) { if (fontsmoothing != null && fontsmoothing != curState.fontsmoothing) { curState.fontsmoothing = fontsmoothing; writeParam((byte) fontsmoothing.ordinal(), NGCanvas.FONT_SMOOTH); } } /** * Gets the current Font Smoothing Type. * The default value is {@link FontSmoothingType#GRAY GRAY}. * The font smoothing type is a text attribute * used for any of the text methods as specified in the * Rendering Attributes Table. * * @return the {@link FontSmoothingType} * @since JavaFX 8u40 */ public FontSmoothingType getFontSmoothingType() { return curState.fontsmoothing; } /** * Defines horizontal text alignment, relative to the text {@code x} origin. * The default value is {@link TextAlignment#LEFT LEFT}. * The text alignment is a text attribute * used for any of the text methods as specified in the * Rendering Attributes Table. *
* Let horizontal bounds represent the logical width of a single line of * text. Where each line of text has a separate horizontal bounds. *
* Then TextAlignment is specified as: *
* * Note: Canvas does not support line wrapping, therefore the text * alignment Justify is identical to left aligned text. *
* A {@code null} value will be ignored and the current value will remain unchanged. * * @param align {@code TextAlignment} with values of Left, Center, Right or null. */ public void setTextAlign(TextAlignment align) { if (align != null && curState.textalign != align) { byte a; switch (align) { case LEFT: a = NGCanvas.ALIGN_LEFT; break; case CENTER: a = NGCanvas.ALIGN_CENTER; break; case RIGHT: a = NGCanvas.ALIGN_RIGHT; break; case JUSTIFY: a = NGCanvas.ALIGN_JUSTIFY; break; default: return; } curState.textalign = align; writeParam(a, NGCanvas.TEXT_ALIGN); } } /** * Gets the current {@code TextAlignment}. * The default value is {@link TextAlignment#LEFT LEFT}. * The text alignment is a text attribute * used for any of the text methods as specified in the * Rendering Attributes Table. * * @return {@code TextAlignment} with values of Left, Center, Right, or * Justify. */ public TextAlignment getTextAlign() { return curState.textalign; } /** * Sets the current Text Baseline. * The default value is {@link VPos#BASELINE BASELINE}. * The text baseline is a text attribute * used for any of the text methods as specified in the * Rendering Attributes Table. * A {@code null} value will be ignored and the current value will remain unchanged. * * @param baseline {@code VPos} with values of Top, Center, Baseline, or Bottom or null. */ public void setTextBaseline(VPos baseline) { if (baseline != null && curState.textbaseline != baseline) { byte b; switch (baseline) { case TOP: b = NGCanvas.BASE_TOP; break; case CENTER: b = NGCanvas.BASE_MIDDLE; break; case BASELINE: b = NGCanvas.BASE_ALPHABETIC; break; case BOTTOM: b = NGCanvas.BASE_BOTTOM; break; default: return; } curState.textbaseline = baseline; writeParam(b, NGCanvas.TEXT_BASELINE); } } /** * Gets the current Text Baseline. * The default value is {@link VPos#BASELINE BASELINE}. * The text baseline is a text attribute * used for any of the text methods as specified in the * Rendering Attributes Table. * * @return {@code VPos} with values of Top, Center, Baseline, or Bottom */ public VPos getTextBaseline() { return curState.textbaseline; } /** * Fills the given string of text at position x, y * with the current fill paint attribute. * A {@code null} text value will be ignored. *
* This method will be affected by any of the * global common, * fill, * or text * attributes as specified in the * Rendering Attributes Table. *
* * @param text the string of text or null. * @param x position on the x axis. * @param y position on the y axis. */ public void fillText(String text, double x, double y) { writeText(text, x, y, 0, NGCanvas.FILL_TEXT); } /** * Draws the given string of text at position x, y * with the current stroke paint attribute. * A {@code null} text value will be ignored. ** This method will be affected by any of the * global common, * stroke, * or text * attributes as specified in the * Rendering Attributes Table. *
* * @param text the string of text or null. * @param x position on the x axis. * @param y position on the y axis. */ public void strokeText(String text, double x, double y) { writeText(text, x, y, 0, NGCanvas.STROKE_TEXT); } /** * Fills text and includes a maximum width of the string. * If the width of the text extends past max width, then it will be sized * to fit. * A {@code null} text value will be ignored. ** This method will be affected by any of the * global common, * fill, * or text * attributes as specified in the * Rendering Attributes Table. *
* * @param text the string of text or null. * @param x position on the x axis. * @param y position on the y axis. * @param maxWidth maximum width the text string can have. */ public void fillText(String text, double x, double y, double maxWidth) { if (maxWidth <= 0) return; writeText(text, x, y, maxWidth, NGCanvas.FILL_TEXT); } /** * Draws text with stroke paint and includes a maximum width of the string. * If the width of the text extends past max width, then it will be sized * to fit. * A {@code null} text value will be ignored. ** This method will be affected by any of the * global common, * stroke, * or text * attributes as specified in the * Rendering Attributes Table. *
* * @param text the string of text or null. * @param x position on the x axis. * @param y position on the y axis. * @param maxWidth maximum width the text string can have. */ public void strokeText(String text, double x, double y, double maxWidth) { if (maxWidth <= 0) return; writeText(text, x, y, maxWidth, NGCanvas.STROKE_TEXT); } /** * Set the filling rule attribute for determining the interior of paths * in fill or clip operations. * The default value is {@code FillRule.NON_ZERO}. * A {@code null} value will be ignored and the current value will remain unchanged. * The fill rule is a path attribute * used for any of the fill or clip path methods as specified in the * Rendering Attributes Table. * * @param fillRule {@code FillRule} with a value of Even_odd or Non_zero or null. */ public void setFillRule(FillRule fillRule) { if (fillRule != null && curState.fillRule != fillRule) { byte b; if (fillRule == FillRule.EVEN_ODD) { b = NGCanvas.FILL_RULE_EVEN_ODD; } else { b = NGCanvas.FILL_RULE_NON_ZERO; } curState.fillRule = fillRule; writeParam(b, NGCanvas.FILL_RULE); } } /** * Get the filling rule attribute for determining the interior of paths * in fill and clip operations. * The default value is {@code FillRule.NON_ZERO}. * The fill rule is a path attribute * used for any of the fill or clip path methods as specified in the * Rendering Attributes Table. * * @return current fill rule. */ public FillRule getFillRule() { return curState.fillRule; } /** * Resets the current path to empty. * The default path is empty. * The current path is a path attribute * used for any of the path methods as specified in the * Rendering Attributes Table * and is not affected by the {@link #save()} and * {@link #restore()} operations. */ public void beginPath() { path.reset(); markPathDirty(); } /** * Issues a move command for the current path to the given x,y coordinate. * The coordinates are transformed by the current transform as they are * added to the path and unaffected by subsequent changes to the transform. * The current path is a path attribute * used for any of the path methods as specified in the * Rendering Attributes Table * and is not affected by the {@link #save()} and * {@link #restore()} operations. * * @param x0 the X position for the move to command. * @param y0 the Y position for the move to command. */ public void moveTo(double x0, double y0) { coords[0] = (float) x0; coords[1] = (float) y0; curState.transform.transform(coords, 0, coords, 0, 1); path.moveTo(coords[0], coords[1]); markPathDirty(); } /** * Adds segments to the current path to make a line to the given x,y * coordinate. * The coordinates are transformed by the current transform as they are * added to the path and unaffected by subsequent changes to the transform. * The current path is a path attribute * used for any of the path methods as specified in the * Rendering Attributes Table * and is not affected by the {@link #save()} and * {@link #restore()} operations. * * @param x1 the X coordinate of the ending point of the line. * @param y1 the Y coordinate of the ending point of the line. */ public void lineTo(double x1, double y1) { coords[0] = (float) x1; coords[1] = (float) y1; curState.transform.transform(coords, 0, coords, 0, 1); if (path.getNumCommands() == 0) { path.moveTo(coords[0], coords[1]); } path.lineTo(coords[0], coords[1]); markPathDirty(); } /** * Adds segments to the current path to make a quadratic Bezier curve. * The coordinates are transformed by the current transform as they are * added to the path and unaffected by subsequent changes to the transform. * The current path is a path attribute * used for any of the path methods as specified in the * Rendering Attributes Table * and is not affected by the {@link #save()} and * {@link #restore()} operations. * * @param xc the X coordinate of the control point * @param yc the Y coordinate of the control point * @param x1 the X coordinate of the end point * @param y1 the Y coordinate of the end point */ public void quadraticCurveTo(double xc, double yc, double x1, double y1) { coords[0] = (float) xc; coords[1] = (float) yc; coords[2] = (float) x1; coords[3] = (float) y1; curState.transform.transform(coords, 0, coords, 0, 2); if (path.getNumCommands() == 0) { path.moveTo(coords[0], coords[1]); } path.quadTo(coords[0], coords[1], coords[2], coords[3]); markPathDirty(); } /** * Adds segments to the current path to make a cubic Bezier curve. * The coordinates are transformed by the current transform as they are * added to the path and unaffected by subsequent changes to the transform. * The current path is a path attribute * used for any of the path methods as specified in the * Rendering Attributes Table * and is not affected by the {@link #save()} and * {@link #restore()} operations. * * @param xc1 the X coordinate of first Bezier control point. * @param yc1 the Y coordinate of the first Bezier control point. * @param xc2 the X coordinate of the second Bezier control point. * @param yc2 the Y coordinate of the second Bezier control point. * @param x1 the X coordinate of the end point. * @param y1 the Y coordinate of the end point. */ public void bezierCurveTo(double xc1, double yc1, double xc2, double yc2, double x1, double y1) { coords[0] = (float) xc1; coords[1] = (float) yc1; coords[2] = (float) xc2; coords[3] = (float) yc2; coords[4] = (float) x1; coords[5] = (float) y1; curState.transform.transform(coords, 0, coords, 0, 3); if (path.getNumCommands() == 0) { path.moveTo(coords[0], coords[1]); } path.curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]); markPathDirty(); } /** * Adds segments to the current path to make an arc. * The coordinates are transformed by the current transform as they are * added to the path and unaffected by subsequent changes to the transform. * The current path is a path attribute * used for any of the path methods as specified in the * Rendering Attributes Table * and is not affected by the {@link #save()} and * {@link #restore()} operations. ** If {@code p0} is the current point in the path and {@code p1} is the * point specified by {@code (x1, y1)} and {@code p2} is the point * specified by {@code (x2, y2)}, then the arc segments appended will * be segments along the circumference of a circle of the specified * radius touching and inscribed into the convex (interior) side of * {@code p0->p1->p2}. The path will contain a line segment (if * needed) to the tangent point between that circle and {@code p0->p1} * followed by circular arc segments to reach the tangent point between * the circle and {@code p1->p2} and will end with the current point at * that tangent point (not at {@code p2}). * Note that the radius and circularity of the arc segments will be * measured or considered relative to the current transform, but the * resulting segments that are computed from those untransformed * points will then be transformed when they are added to the path. * Since all computation is done in untransformed space, but the * pre-existing path segments are all transformed, the ability to * correctly perform the computation may implicitly depend on being * able to inverse transform the current end of the current path back * into untransformed coordinates. *
** If there is no way to compute and inscribe the indicated circle * for any reason then the entire operation will simply append segments * to force a line to point {@code p1}. Possible reasons that the * computation may fail include: *
* This method will be affected by any of the * global common, * fill, * or path * attributes as specified in the * Rendering Attributes Table. * Note that the path segments were transformed as they were originally * added to the current path so the current transform will not affect * those path segments again, but it may affect other attributes in * affect at the time of the {@code fill()} operation. *
*/ public void fill() { writePath(NGCanvas.FILL_PATH); } /** * Strokes the path with the current stroke paint. ** This method will be affected by any of the * global common, * stroke, * or path * attributes as specified in the * Rendering Attributes Table. * Note that the path segments were transformed as they were originally * added to the current path so the current transform will not affect * those path segments again, but it may affect other attributes in * affect at the time of the {@code stroke()} operation. *
*/ public void stroke() { writePath(NGCanvas.STROKE_PATH); } /** * Intersects the current clip with the current path and applies it to * subsequent rendering operation as an anti-aliased mask. * The current clip is a common attribute * used for nearly all rendering operations as specified in the * Rendering Attributes Table. ** This method will itself be affected only by the * path * attributes as specified in the * Rendering Attributes Table. * Note that the path segments were transformed as they were originally * added to the current path so the current transform will not affect * those path segments again, but it may affect other attributes in * affect at the time of the {@code stroke()} operation. *
*/ public void clip() { Path2D clip = new Path2D(path); clipStack.addLast(clip); curState.numClipPaths++; GrowableDataBuffer buf = getBuffer(); buf.putByte(NGCanvas.PUSH_CLIP); buf.putObject(clip); } /** * Returns true if the the given x,y point is inside the path. * * @param x the X coordinate to use for the check. * @param y the Y coordinate to use for the check. * @return true if the point given is inside the path, false * otherwise. */ public boolean isPointInPath(double x, double y) { // TODO: HTML5 considers points on the path to be inside, but we // implement a halfin-halfout approach... return path.contains((float) x, (float) y); } /** * Clears a portion of the canvas with a transparent color value. ** This method will be affected only by the current transform, clip, * and effect. *
* * @param x X position of the upper left corner of the rectangle. * @param y Y position of the upper left corner of the rectangle. * @param w width of the rectangle. * @param h height of the rectangle. */ public void clearRect(double x, double y, double w, double h) { if (w != 0 && h != 0) { resetIfCovers(null, x, y, w, h); writeOp4(x, y, w, h, NGCanvas.CLEAR_RECT); } } /** * Fills a rectangle using the current fill paint. ** This method will be affected by any of the * global common * or fill * attributes as specified in the * Rendering Attributes Table. *
* * @param x the X position of the upper left corner of the rectangle. * @param y the Y position of the upper left corner of the rectangle. * @param w the width of the rectangle. * @param h the height of the rectangle. */ public void fillRect(double x, double y, double w, double h) { if (w != 0 && h != 0) { resetIfCovers(this.curState.fill, x, y, w, h); writeOp4(x, y, w, h, NGCanvas.FILL_RECT); } } /** * Strokes a rectangle using the current stroke paint. ** This method will be affected by any of the * global common * or stroke * attributes as specified in the * Rendering Attributes Table. *
* * @param x the X position of the upper left corner of the rectangle. * @param y the Y position of the upper left corner of the rectangle. * @param w the width of the rectangle. * @param h the height of the rectangle. */ public void strokeRect(double x, double y, double w, double h) { if (w != 0 || h != 0) { writeOp4(x, y, w, h, NGCanvas.STROKE_RECT); } } /** * Fills an oval using the current fill paint. ** This method will be affected by any of the * global common * or fill * attributes as specified in the * Rendering Attributes Table. *
* * @param x the X coordinate of the upper left bound of the oval. * @param y the Y coordinate of the upper left bound of the oval. * @param w the width at the center of the oval. * @param h the height at the center of the oval. */ public void fillOval(double x, double y, double w, double h) { if (w != 0 && h != 0) { writeOp4(x, y, w, h, NGCanvas.FILL_OVAL); } } /** * Strokes an oval using the current stroke paint. ** This method will be affected by any of the * global common * or stroke * attributes as specified in the * Rendering Attributes Table. *
* * @param x the X coordinate of the upper left bound of the oval. * @param y the Y coordinate of the upper left bound of the oval. * @param w the width at the center of the oval. * @param h the height at the center of the oval. */ public void strokeOval(double x, double y, double w, double h) { if (w != 0 || h != 0) { writeOp4(x, y, w, h, NGCanvas.STROKE_OVAL); } } /** * Fills an arc using the current fill paint. A {@code null} ArcType or * non positive width or height will cause the render command to be ignored. ** This method will be affected by any of the * global common * or fill * attributes as specified in the * Rendering Attributes Table. *
* * @param x the X coordinate of the arc. * @param y the Y coordinate of the arc. * @param w the width of the arc. * @param h the height of the arc. * @param startAngle the starting angle of the arc in degrees. * @param arcExtent the angular extent of the arc in degrees. * @param closure closure type (Round, Chord, Open) or null. */ public void fillArc(double x, double y, double w, double h, double startAngle, double arcExtent, ArcType closure) { if (w != 0 && h != 0 && closure != null) { writeArcType(closure); writeOp6(x, y, w, h, startAngle, arcExtent, NGCanvas.FILL_ARC); } } /** * Strokes an Arc using the current stroke paint. A {@code null} ArcType or * non positive width or height will cause the render command to be ignored. ** This method will be affected by any of the * global common * or stroke * attributes as specified in the * Rendering Attributes Table. *
* * @param x the X coordinate of the arc. * @param y the Y coordinate of the arc. * @param w the width of the arc. * @param h the height of the arc. * @param startAngle the starting angle of the arc in degrees. * @param arcExtent arcExtent the angular extent of the arc in degrees. * @param closure closure type (Round, Chord, Open) or null */ public void strokeArc(double x, double y, double w, double h, double startAngle, double arcExtent, ArcType closure) { if (w != 0 && h != 0 && closure != null) { writeArcType(closure); writeOp6(x, y, w, h, startAngle, arcExtent, NGCanvas.STROKE_ARC); } } /** * Fills a rounded rectangle using the current fill paint. ** This method will be affected by any of the * global common * or fill * attributes as specified in the * Rendering Attributes Table. *
* * @param x the X coordinate of the upper left bound of the oval. * @param y the Y coordinate of the upper left bound of the oval. * @param w the width at the center of the oval. * @param h the height at the center of the oval. * @param arcWidth the arc width of the rectangle corners. * @param arcHeight the arc height of the rectangle corners. */ public void fillRoundRect(double x, double y, double w, double h, double arcWidth, double arcHeight) { if (w != 0 && h != 0) { writeOp6(x, y, w, h, arcWidth, arcHeight, NGCanvas.FILL_ROUND_RECT); } } /** * Strokes a rounded rectangle using the current stroke paint. ** This method will be affected by any of the * global common * or stroke * attributes as specified in the * Rendering Attributes Table. *
* * @param x the X coordinate of the upper left bound of the oval. * @param y the Y coordinate of the upper left bound of the oval. * @param w the width at the center of the oval. * @param h the height at the center of the oval. * @param arcWidth the arc width of the rectangle corners. * @param arcHeight the arc height of the rectangle corners. */ public void strokeRoundRect(double x, double y, double w, double h, double arcWidth, double arcHeight) { if (w != 0 && h != 0) { writeOp6(x, y, w, h, arcWidth, arcHeight, NGCanvas.STROKE_ROUND_RECT); } } /** * Strokes a line using the current stroke paint. ** This method will be affected by any of the * global common * or stroke * attributes as specified in the * Rendering Attributes Table. *
* * @param x1 the X coordinate of the starting point of the line. * @param y1 the Y coordinate of the starting point of the line. * @param x2 the X coordinate of the ending point of the line. * @param y2 the Y coordinate of the ending point of the line. */ public void strokeLine(double x1, double y1, double x2, double y2) { writeOp4(x1, y1, x2, y2, NGCanvas.STROKE_LINE); } /** * Fills a polygon with the given points using the currently set fill paint. * A {@code null} value for any of the arrays will be ignored and nothing will be drawn. ** This method will be affected by any of the * global common, * fill, * or Fill Rule * attributes as specified in the * Rendering Attributes Table. *
* * @param xPoints array containing the x coordinates of the polygon's points or null. * @param yPoints array containing the y coordinates of the polygon's points or null. * @param nPoints the number of points that make the polygon. */ public void fillPolygon(double xPoints[], double yPoints[], int nPoints) { if (nPoints >= 3) { writePoly(xPoints, yPoints, nPoints, true, NGCanvas.FILL_PATH); } } /** * Strokes a polygon with the given points using the currently set stroke paint. * A {@code null} value for any of the arrays will be ignored and nothing will be drawn. ** This method will be affected by any of the * global common * or stroke * attributes as specified in the * Rendering Attributes Table. *
* * @param xPoints array containing the x coordinates of the polygon's points or null. * @param yPoints array containing the y coordinates of the polygon's points or null. * @param nPoints the number of points that make the polygon. */ public void strokePolygon(double xPoints[], double yPoints[], int nPoints) { if (nPoints >= 2) { writePoly(xPoints, yPoints, nPoints, true, NGCanvas.STROKE_PATH); } } /** * Strokes a polyline with the given points using the currently set stroke * paint attribute. * A {@code null} value for any of the arrays will be ignored and nothing will be drawn. ** This method will be affected by any of the * global common * or stroke * attributes as specified in the * Rendering Attributes Table. *
* * @param xPoints array containing the x coordinates of the polyline's points or null. * @param yPoints array containing the y coordinates of the polyline's points or null. * @param nPoints the number of points that make the polyline. */ public void strokePolyline(double xPoints[], double yPoints[], int nPoints) { if (nPoints >= 2) { writePoly(xPoints, yPoints, nPoints, false, NGCanvas.STROKE_PATH); } } /** * Draws an image at the given x, y position using the width * and height of the given image. * A {@code null} image value or an image still in progress will be ignored. ** This method will be affected by any of the * global common * attributes as specified in the * Rendering Attributes Table. *
* * @param img the image to be drawn or null. * @param x the X coordinate on the destination for the upper left of the image. * @param y the Y coordinate on the destination for the upper left of the image. */ public void drawImage(Image img, double x, double y) { if (img == null) return; double sw = img.getWidth(); double sh = img.getHeight(); writeImage(img, x, y, sw, sh); } /** * Draws an image into the given destination rectangle of the canvas. The * Image is scaled to fit into the destination rectagnle. * A {@code null} image value or an image still in progress will be ignored. ** This method will be affected by any of the * global common * attributes as specified in the * Rendering Attributes Table. *
* * @param img the image to be drawn or null. * @param x the X coordinate on the destination for the upper left of the image. * @param y the Y coordinate on the destination for the upper left of the image. * @param w the width of the destination rectangle. * @param h the height of the destination rectangle. */ public void drawImage(Image img, double x, double y, double w, double h) { writeImage(img, x, y, w, h); } /** * Draws the specified source rectangle of the given image to the given * destination rectangle of the Canvas. * A {@code null} image value or an image still in progress will be ignored. ** This method will be affected by any of the * global common * attributes as specified in the * Rendering Attributes Table. *
* * @param img the image to be drawn or null. * @param sx the source rectangle's X coordinate position. * @param sy the source rectangle's Y coordinate position. * @param sw the source rectangle's width. * @param sh the source rectangle's height. * @param dx the destination rectangle's X coordinate position. * @param dy the destination rectangle's Y coordinate position. * @param dw the destination rectangle's width. * @param dh the destination rectangle's height. */ public void drawImage(Image img, double sx, double sy, double sw, double sh, double dx, double dy, double dw, double dh) { writeImage(img, dx, dy, dw, dh, sx, sy, sw, sh); } private PixelWriter writer; /** * Returns a {@link PixelWriter} object that can be used to modify * the pixels of the {@link Canvas} associated with this * {@code GraphicsContext}. * All coordinates in the {@code PixelWriter} methods on the returned * object will be in device space since they refer directly to pixels * and no other rendering attributes will be applied when modifying * pixels using this object. * * @return the {@code PixelWriter} for modifying the pixels of this * {@code Canvas} */ public PixelWriter getPixelWriter() { if (writer == null) { writer = new PixelWriter() { @Override public PixelFormat