javaquery/canvas/src/main/java/net/java/html/canvas/GraphicsContext.java
author Anton Epple <toni.epple@eppleton.de>
Tue, 11 Feb 2014 15:42:12 +0100
branchcanvas
changeset 1442 0660e56b5b33
parent 1303 3d62ad46d744
child 1443 6e51eb226f44
permissions -rw-r--r--
fixed null pointer exception (somewhat hacky solution)
     1 /**
     2  * Back 2 Browser Bytecode Translator
     3  * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     4  *
     5  * This program is free software: you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation, version 2 of the License.
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program. Look for COPYING file in the top folder.
    16  * If not, see http://opensource.org/licenses/GPL-2.0.
    17  */
    18 package net.java.html.canvas;
    19 
    20 import net.java.html.canvas.Style.Color;
    21 import net.java.html.canvas.Style.LinearGradient;
    22 import net.java.html.canvas.Style.Pattern;
    23 import net.java.html.canvas.Style.RadialGradient;
    24 import net.java.html.canvas.spi.GraphicsEnvironment;
    25 import org.apidesign.html.canvas.impl.CnvsAccssr;
    26 
    27 /**
    28  * A 2D Graphics Context similar to HTML5 or JavaFX GraphicsContext. Use this to
    29  * paint on your Canvas.s
    30  *
    31  * @author antonepple
    32  */
    33 public final class GraphicsContext {
    34 
    35     public static void getAccssr() {
    36         // do nothing
    37     }
    38 
    39     GraphicsEnvironment graphicsEnvironmentImpl;
    40 
    41     static {
    42         CnvsAccssr cnvsAccssr = new CnvsAccssr() {
    43             @Override
    44             public GraphicsContext create(GraphicsEnvironment environment) {
    45                 return new GraphicsContext(environment);
    46             }
    47         };
    48     }
    49 
    50     GraphicsContext(GraphicsEnvironment graphicsEnvironment) {
    51         this.graphicsEnvironmentImpl = graphicsEnvironment;
    52     }
    53 
    54     /**
    55      * Adds path elements to the current path to make an arc.
    56      *
    57      * @param centerX the center x position of the arc.
    58      * @param centerY the center y position of the arc.
    59      * @param radius the radius of the arc.
    60      * @param endAngle teh endAngle of the arc
    61      * @param ccw the direction of the arc (counterclockwise)
    62      */
    63     public void arc(double centerX,
    64             double centerY,
    65             double startAngle,
    66             double radius,
    67             double endAngle,
    68             boolean ccw) {
    69         graphicsEnvironmentImpl.arc(centerX, centerY, startAngle, radius, endAngle, ccw);
    70     }
    71 
    72     /**
    73      * Adds segments to the current path to make an arc.
    74      *
    75      * @param x1 the X coordinate of the first point of the arc.
    76      * @param y1 the Y coordinate of the first point of the arc.
    77      * @param x2 the X coordinate of the second point of the arc.
    78      * @param y2 the Y coordinate of the second point of the arc.
    79      * @param radius the radius of the arc in the range {0.0-positive infinity}.
    80      */
    81     public void arcTo(double x1,
    82             double y1,
    83             double x2,
    84             double y2,
    85             double radius) {
    86         graphicsEnvironmentImpl.arcTo(x1, y1, x2, y2, radius);
    87     }
    88 
    89     /**
    90      * Returns true if the the given x,y point is inside the path.
    91      *
    92      * @param x the X coordinate to use for the check.
    93      * @param y the Y coordinate to use for the check.
    94      * @return true if the point given is inside the path, false otherwise.
    95      */
    96     public boolean isPointInPath(double x, double y) {
    97         return graphicsEnvironmentImpl.isPointInPath(x, y);
    98     }
    99 
   100     /**
   101      * Fills the path with the current fill paint.
   102      */
   103     public void fill() {
   104         graphicsEnvironmentImpl.fill();
   105     }
   106 
   107     /**
   108      * Strokes the path with the current stroke paint.
   109      */
   110     public void stroke() {
   111         graphicsEnvironmentImpl.stroke();
   112     }
   113 
   114     /**
   115      * Starts a Path
   116      */
   117     public void beginPath() {
   118         graphicsEnvironmentImpl.beginPath();
   119     }
   120 
   121     /**
   122      * Closes the path.
   123      */
   124     public void closePath() {
   125         graphicsEnvironmentImpl.closePath();
   126     }
   127 
   128     /**
   129      * Clips using the current path
   130      */
   131     public void clip() {
   132         graphicsEnvironmentImpl.clip();
   133     }
   134 
   135     /**
   136      * Issues a move command for the current path to the given x,y coordinate.
   137      *
   138      * @param x0 the X position for the move to command.
   139      * @param y0 the Y position for the move to command.
   140      */
   141     public void moveTo(double x, double y) {
   142         graphicsEnvironmentImpl.moveTo(x, y);
   143     }
   144 
   145     /**
   146      * Adds segments to the current path to make a line at the given x,y
   147      * coordinate.
   148      *
   149      * @param x1 the X coordinate of the ending point of the line.
   150      * @param y1 the Y coordinate of the ending point of the line.
   151      */
   152     public void lineTo(double x, double y) {
   153         graphicsEnvironmentImpl.lineTo(x, y);
   154     }
   155 
   156     /**
   157      * Adds segments to the current path to make a quadratic curve.
   158      *
   159      * @param cpx the X coordinate of the control point
   160      * @param cpy the Y coordinate of the control point
   161      * @param x the X coordinate of the end point
   162      * @param y the Y coordinate of the end point
   163      */
   164     public void quadraticCurveTo(double cpx, double cpy, double x, double y) {
   165         graphicsEnvironmentImpl.quadraticCurveTo(cpx, cpy, x, y);
   166     }
   167 
   168     /**
   169      * Adds segments to the current path to make a cubic bezier curve.
   170      *
   171      * @param cp1x the X coordinate of first bezier control point.
   172      * @param cp1y the Y coordinate of the first bezier control point.
   173      * @param cp2x the X coordinate of the second bezier control point.
   174      * @param cp2y the Y coordinate of the second bezier control point.
   175      * @param x the X coordinate of the end point.
   176      * @param y the Y coordinate of the end point.
   177      */
   178     public void bezierCurveTo(double cp1x, double cp1y, double cp2x, double cp2y, double x, double y) {
   179         graphicsEnvironmentImpl.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
   180     }
   181 
   182     /**
   183      * Fills a rectangle using the current fill paint.
   184      *
   185      * @param x the X position of the upper left corner of the rectangle.
   186      * @param y the Y position of the upper left corner of the rectangle.
   187      * @param w the width of the rectangle.
   188      * @param h the height of the rectangle.
   189      */
   190     public void fillRect(double x, double y, double width, double height) {
   191         graphicsEnvironmentImpl.fillRect(x, y, width, height);
   192     }
   193 
   194     /**
   195      * Strokes a rectangle using the current stroke paint.
   196      *
   197      * @param x the X position of the upper left corner of the rectangle.
   198      * @param y the Y position of the upper left corner of the rectangle.
   199      * @param width the width of the rectangle.
   200      * @param height the height of the rectangle.
   201      */
   202     public void strokeRect(double x, double y, double width, double height) {
   203         graphicsEnvironmentImpl.strokeRect(x, y, width, height);
   204     }
   205 
   206     /**
   207      * Clears a portion of the canvas with a transparent color value.
   208      *
   209      * @param x X position of the upper left corner of the rectangle.
   210      * @param y Y position of the upper left corner of the rectangle.
   211      * @param width width of the rectangle.
   212      * @param height height of the rectangle.
   213      */
   214     public void clearRect(double x, double y, double width, double height) {
   215         graphicsEnvironmentImpl.clearRect(x, y, width, height);
   216     }
   217 
   218     /**
   219      * Clears a portion of the canvas with a transparent color value.
   220      *
   221      * @param x X position of the upper left corner of the rectangle.
   222      * @param y Y position of the upper left corner of the rectangle.
   223      * @param width width of the rectangle.
   224      * @param height height of the rectangle.
   225      */
   226     public void rect(double x, double y, double width, double height) {
   227         graphicsEnvironmentImpl.rect(x, y, width, height);
   228     }
   229 
   230     /**
   231      * Saves the following attributes onto a stack.
   232      * <ul>
   233      * <li>Global Alpha</li>
   234      * <li>Global Blend Operation</li>
   235      * <li>Transform</li>
   236      * <li>Fill Paint</li>
   237      * <li>Stroke Paint</li>
   238      * <li>Line Width</li>
   239      * <li>Line Cap</li>
   240      * <li>Line Join</li>
   241      * <li>Miter Limit</li>
   242      * <li>Number of Clip Paths</li>
   243      * <li>Font</li>
   244      * <li>Text Align</li>
   245      * <li>Text Baseline</li>
   246      * <li>Effect</li>
   247      * <li>Fill Rule</li>
   248      * </ul>
   249      * This method does NOT alter the current state in any way. Also, not that
   250      * the current path is not saved.
   251      */
   252     public void save() {
   253         graphicsEnvironmentImpl.save();
   254     }
   255 
   256     /**
   257      * Pops the state off of the stack, setting the following attributes to
   258      * their value at the time when that state was pushed onto the stack. If the
   259      * stack is empty then nothing is changed.
   260      *
   261      * <ul>
   262      * <li>Global Alpha</li>
   263      * <li>Global Blend Operation</li>
   264      * <li>Transform</li>
   265      * <li>Fill Paint</li>
   266      * <li>Stroke Paint</li>
   267      * <li>Line Width</li>
   268      * <li>Line Cap</li>
   269      * <li>Line Join</li>
   270      * <li>Miter Limit</li>
   271      * <li>Number of Clip Paths</li>
   272      * <li>Font</li>
   273      * <li>Text Align</li>
   274      * <li>Text Baseline</li>
   275      * <li>Effect</li>
   276      * <li>Fill Rule</li>
   277      * </ul>
   278      */
   279     public void restore() {
   280         graphicsEnvironmentImpl.restore();
   281     }
   282 
   283     /**
   284      * Rotates the current transform in degrees.
   285      *
   286      * @param angle value in degrees to rotate the current transform.
   287      */
   288     public void rotate(double angle) {
   289         graphicsEnvironmentImpl.rotate(angle);
   290     }
   291 
   292     /**
   293      * Concatenates the input with the current transform.
   294      *
   295      * @param mxx - the X coordinate scaling element of the 3x4 matrix
   296      * @param myx - the Y coordinate shearing element of the 3x4 matrix
   297      * @param mxy - the X coordinate shearing element of the 3x4 matrix
   298      * @param myy - the Y coordinate scaling element of the 3x4 matrix
   299      * @param mxt - the X coordinate translation element of the 3x4 matrix
   300      * @param myt - the Y coordinate translation element of the 3x4 matrix
   301      */
   302     public void transform(double mxx, double myx, double mxy, double myy, double mxt, double myt) {
   303         graphicsEnvironmentImpl.transform(mxx, myx, mxy, myy, mxt, myt);
   304     }
   305 
   306     /**
   307      * Concatenates the input with the current transform.
   308      *
   309      * @param mxx - the X coordinate scaling element of the 3x4 matrix
   310      * @param myx - the Y coordinate shearing element of the 3x4 matrix
   311      * @param mxy - the X coordinate shearing element of the 3x4 matrix
   312      * @param myy - the Y coordinate scaling element of the 3x4 matrix
   313      * @param mxt - the X coordinate translation element of the 3x4 matrix
   314      * @param myt - the Y coordinate translation element of the 3x4 matrix
   315      */
   316     public void setTransform(double mxx, double myx, double mxy, double myy, double mxt, double myt) {
   317         graphicsEnvironmentImpl.setTransform(mxx, myx, mxy, myy, mxt, myt);
   318     }
   319 
   320     /**
   321      * Translates the current transform by x, y.
   322      *
   323      * @param x value to translate along the x axis.
   324      * @param y value to translate along the y axis.
   325      */
   326     public void translate(double x, double y) {
   327         graphicsEnvironmentImpl.translate(x, y);
   328     }
   329 
   330     /**
   331      * Scales the current transform by x, y.
   332      *
   333      * @param x value to scale in the x axis.
   334      * @param y value to scale in the y axis.
   335      */
   336     public void scale(double x, double y) {
   337         graphicsEnvironmentImpl.scale(x, y);
   338     }
   339 
   340     /**
   341      * Draws an image at the given x, y position using the width and height of
   342      * the given image.
   343      *
   344      * @param img the image to be drawn.
   345      * @param x the X coordinate on the destination for the upper left of the
   346      * image.
   347      * @param y the Y coordinate on the destination for the upper left of the
   348      * image.
   349      */
   350     public void drawImage(Image image, double x, double y) {
   351         Object nativeImage = graphicsEnvironmentImpl.drawImage(image, x, y, image.getCached());
   352         image.cache(nativeImage);
   353     }
   354 
   355     /**
   356      * Draws an image into the given destination rectangle of the canvas. The
   357      * Image is scaled to fit into the destination rectagnle.
   358      *
   359      * @param img the image to be drawn.
   360      * @param x the X coordinate on the destination for the upper left of the
   361      * image.
   362      * @param y the Y coordinate on the destination for the upper left of the
   363      * image.
   364      * @param width the width of the destination rectangle.
   365      * @param height the height of the destination rectangle.
   366      */
   367     public void drawImage(Image image, double x, double y, double width, double height) {
   368         Object nativeImage = graphicsEnvironmentImpl.drawImage(image, x, y, width, height, image.getCached());
   369         image.cache(nativeImage);
   370     }
   371 
   372     /**
   373      * Draws the current source rectangle of the given image to the given
   374      * destination rectangle of the Canvas.
   375      *
   376      * @param img the image to be drawn.
   377      * @param sx the source rectangle's X coordinate position.
   378      * @param sy the source rectangle's Y coordinate position.
   379      * @param sw the source rectangle's width.
   380      * @param sh the source rectangle's height.
   381      * @param dx the destination rectangle's X coordinate position.
   382      * @param dy the destination rectangle's Y coordinate position.
   383      * @param dw the destination rectangle's width.
   384      * @param dh the destination rectangle's height.
   385      */
   386     public void drawImage(Image image, double sx, double sy, double sw, double sh, double dx, double dy, double dw, double dh) {
   387         Object nativeImage = graphicsEnvironmentImpl.drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh, image.getCached());
   388         image.cache(nativeImage);
   389     }
   390 
   391     /**
   392      * Merges two images drawing one on top of the other and returning the
   393      * result.
   394      *
   395      * @param a the lower Image
   396      * @param b the upper Image
   397      * @return
   398      */
   399     public Image merge(Image a, Image b) {
   400         if (a.getCached() == null) {
   401             drawImage(a, 0, 0);
   402         }
   403         if (b.getCached() == null) {
   404             drawImage(b, 0, 0);
   405         }
   406         Object nativeImage = graphicsEnvironmentImpl.mergeImages(a, b, a.getCached(), b.getCached());
   407         Image merged = Image.create("should add real path here");
   408         merged.cache(nativeImage);
   409         return merged;
   410     }
   411 
   412 //    public void setShadowColor(String color) {
   413 //        graphicsEnvironmentImpl.setShadowColor(color);
   414 //    }
   415 //
   416 //    public void setShadowBlur(double blur) {
   417 //        graphicsEnvironmentImpl.setShadowBlur(blur);
   418 //    }
   419 //
   420 //    public void setShadowOffsetX(double x) {
   421 //        graphicsEnvironmentImpl.setShadowOffsetX(x);
   422 //    }
   423 //
   424 //    public void setShadowOffsetY(double y) {
   425 //        graphicsEnvironmentImpl.setShadowOffsetY(y);
   426 //    }
   427 //
   428 //    public String getShadowColor() {
   429 //        return graphicsEnvironmentImpl.getShadowColor();
   430 //    }
   431 //
   432 //    public double getShadowBlur() {
   433 //        return graphicsEnvironmentImpl.getShadowBlur();
   434 //    }
   435 //
   436 //    public double getShadowOffsetX() {
   437 //        return graphicsEnvironmentImpl.getShadowOffsetX();
   438 //    }
   439 //
   440 //    public double getShadowOffsetY() {
   441 //        return graphicsEnvironmentImpl.getShadowOffsetY();
   442 //    }
   443     public String getLineCap() {
   444         return graphicsEnvironmentImpl.getLineCap();
   445     }
   446 
   447     public void setLineCap(String style) {
   448         graphicsEnvironmentImpl.setLineCap(style);
   449     }
   450 
   451     public String getLineJoin() {
   452         return graphicsEnvironmentImpl.getLineJoin();
   453     }
   454 
   455     public void setLineJoin(String style) {
   456         graphicsEnvironmentImpl.setLineJoin(style);
   457     }
   458 
   459     public double getLineWidth() {
   460         return graphicsEnvironmentImpl.getLineWidth();
   461     }
   462 
   463     public void setLineWidth(double width) {
   464         graphicsEnvironmentImpl.setLineWidth(width);
   465     }
   466 
   467     public double getMiterLimit() {
   468         return graphicsEnvironmentImpl.getMiterLimit();
   469     }
   470 
   471     public void setMiterLimit(double limit) {
   472         graphicsEnvironmentImpl.setMiterLimit(limit);
   473     }
   474 
   475     public void setFillStyle(Style style) {
   476         Object nativeFillStyle = graphicsEnvironmentImpl.setFillStyle(style, style.getCached());
   477         style.cache(nativeFillStyle);
   478     }
   479 
   480     public String getFont() {
   481         return graphicsEnvironmentImpl.getFont();
   482     }
   483 
   484     public void setFont(String font) {
   485         graphicsEnvironmentImpl.setFont(font);
   486     }
   487 
   488     public void setStrokeStyle(Style style) {
   489         Object nativeStrokeStyle = graphicsEnvironmentImpl.setStrokeStyle(style, style.getCached());
   490         style.cache(nativeStrokeStyle);
   491     }
   492 
   493     public String getTextAlign() {
   494         return graphicsEnvironmentImpl.getTextAlign();
   495     }
   496 
   497     public void setTextAlign(String textAlign) {
   498         graphicsEnvironmentImpl.setTextAlign(textAlign);
   499     }
   500 
   501     public String getTextBaseline() {
   502         return graphicsEnvironmentImpl.getTextBaseline();
   503     }
   504 
   505     public void setTextBaseline(String textbaseline) {
   506         graphicsEnvironmentImpl.setTextBaseline(textbaseline);
   507     }
   508 
   509     public void fillText(String text, double x, double y) {
   510         graphicsEnvironmentImpl.fillText(text, x, y);
   511     }
   512 
   513     public void fillText(String text, double x, double y, double maxWidth) {
   514         graphicsEnvironmentImpl.fillText(text, x, y, maxWidth);
   515     }
   516 
   517     public Dimension measureText(String text) {
   518         return graphicsEnvironmentImpl.measureText(text);
   519     }
   520 
   521     public void strokeText(String text, double x, double y) {
   522         graphicsEnvironmentImpl.strokeText(text, x, y);
   523     }
   524 
   525     public void strokeText(String text, double x, double y, double maxWidth) {
   526         graphicsEnvironmentImpl.strokeText(text, x, y, maxWidth);
   527     }
   528 
   529 //    public ImageData createPixelMap(double x, double y) {
   530 //        return graphicsEnvironmentImpl.createPixelMap(x, y);
   531 //    }
   532 //
   533 //    public ImageData createPixelMap(ImageData pixelMap) {
   534 //        return graphicsEnvironmentImpl.createPixelMap(pixelMap);
   535 //    }
   536 //
   537 //    public ImageData getSnapshot(double x, double y, double width, double height) {
   538 //        return graphicsEnvironmentImpl.getPixelMap(x, y, width, height);
   539 //    }
   540 //
   541 //    public void drawPixelMap(ImageData pixelMap, double x, double y) {
   542 //        graphicsEnvironmentImpl.putPixelMap(pixelMap, x, y);
   543 //    }
   544 //
   545 //    public void drawPixelMap(ImageData pixelMap, double x, double y, double dirtyx, double dirtyy, double dirtywidth, double dirtyheight) {
   546 //        graphicsEnvironmentImpl.putPixelMap(pixelMap, x, y, dirtyx, dirtyy, dirtywidth, dirtyheight);
   547 //    }
   548     /**
   549      * Sets the global alpha of the current state.
   550      *
   551      * @param alpha value in the range {@code 0.0-1.0}. The value is clamped if
   552      * it is out of range.
   553      */
   554     public void setGlobalAlpha(double alpha) {
   555         graphicsEnvironmentImpl.setGlobalAlpha(alpha);
   556     }
   557 
   558     /**
   559      * Gets the current global alpha.
   560      *
   561      * @return the current global alpha.
   562      */
   563     public double getGlobalAlpha() {
   564         return graphicsEnvironmentImpl.getGlobalAlpha();
   565     }
   566 
   567     /**
   568      * Sets the global blend mode.
   569      *
   570      * @param op the BlendMode that will be set.
   571      */
   572     public void setGlobalCompositeOperation(String operation) {
   573         graphicsEnvironmentImpl.setGlobalCompositeOperation(operation);
   574     }
   575 
   576     /**
   577      * Gets the global blend mode.
   578      *
   579      * @return the global BlendMode of the current state.
   580      */
   581     public String getGlobalCompositeOperation() {
   582         return graphicsEnvironmentImpl.getGlobalCompositeOperation();
   583     }
   584 
   585     public LinearGradient createLinearGradient(double x0, double y0, double x1, double y1) {
   586         return new Style.LinearGradient(x0, y0, x1, y1);
   587     }
   588 
   589     public Pattern createPattern(Image image, String repeat) {
   590         return new Pattern(image, repeat);
   591     }
   592 
   593     public RadialGradient createRadialGradient(double x0, double y0, double r0, double x1, double y1, double r1) {
   594         return new RadialGradient(x0, y0, r0, x1, y1, r1);
   595     }
   596 
   597     public Color getWebColor(String webColor) {
   598         return new Style.Color(webColor);
   599     }
   600 
   601     /**
   602      * Get the height of this GraphicsContext (which should be the same as the
   603      * enclosing canvas height)
   604      *
   605      * @return the height of this GraphicsContext
   606      */
   607     public int getHeight() {
   608         return graphicsEnvironmentImpl.getHeight();
   609     }
   610 
   611     /**
   612      * Get the width of this GraphicsContext (which should be the same as the
   613      * enclosing canvas height)
   614      *
   615      * @return the width of this GraphicsContext
   616      */
   617     public int getWidth() {
   618         return graphicsEnvironmentImpl.getWidth();
   619     }
   620 
   621 //    public void setHeight(int height) {
   622 //        graphicsEnvironmentImpl.setHeight(height);
   623 //    }
   624 //
   625 //    public void setWidth(int width) {
   626 //        graphicsEnvironmentImpl.setWidth(width);
   627 //    }
   628     /**
   629      * Fill a circle with a center position of centerX, centerY and the
   630      * specified radius.
   631      *
   632      * @param centerX
   633      * @param centerY
   634      * @param radius
   635      */
   636     public void fillCircle(float centerX, float centerY, float radius) {
   637         graphicsEnvironmentImpl.arc(centerX, centerY, radius, 0, Math.PI * 2, false);
   638     }
   639 
   640     /**
   641      * Fills a polygon with the given points using the currently set fill paint.
   642      *
   643      * @param x_coord array containing the x coordinates of the polygon's
   644      * points.
   645      * @param y_coord array containing the y coordinates of the polygon's
   646      * points.
   647      * @param vertexCount the number of points that make the polygon.
   648      */
   649     public void fillPolygon(double[] x_coord, double[] y_coord, int vertexCount) {
   650         if (vertexCount >= 1 && x_coord != null && x_coord.length >= vertexCount && y_coord != null && y_coord.length >= vertexCount) {
   651             graphicsEnvironmentImpl.beginPath();
   652         }
   653         graphicsEnvironmentImpl.moveTo(x_coord[0], y_coord[0]);
   654         for (int i = 1; i < vertexCount; i++) {
   655             graphicsEnvironmentImpl.lineTo(x_coord[i], y_coord[i]);
   656 
   657         }
   658         graphicsEnvironmentImpl.closePath();
   659         graphicsEnvironmentImpl.fill();
   660         graphicsEnvironmentImpl.stroke();
   661     }
   662 }