1 /*
   2  * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javafx.scene.shape;
  27 
  28 import com.sun.javafx.util.Logging;
  29 import com.sun.javafx.geom.Path2D;
  30 import com.sun.javafx.scene.DirtyBits;
  31 import com.sun.javafx.sg.prism.NGNode;
  32 import com.sun.javafx.sg.prism.NGSVGPath;
  33 import com.sun.javafx.tk.Toolkit;
  34 import javafx.beans.property.ObjectProperty;
  35 import javafx.beans.property.ObjectPropertyBase;
  36 import javafx.beans.property.StringProperty;
  37 import javafx.beans.property.StringPropertyBase;
  38 import javafx.scene.paint.Paint;
  39 
  40 /**
  41  * The {@code SVGPath} class represents a simple shape that is constructed by
  42  * parsing SVG path data from a String.
  43  *
  44 <PRE>
  45 import javafx.scene.shape.*;
  46 
  47 SVGPath svg = new SVGPath();
  48 svg.setContent("M40,60 C42,48 44,30 25,32");
  49 </PRE>
  50  * @since JavaFX 2.0
  51  */
  52 public  class SVGPath extends Shape {
  53     /**
  54      * Defines the filling rule constant for determining the interior of the path.
  55      * The value must be one of the following constants:
  56      * {@code FillRile.EVEN_ODD} or {@code FillRule.NON_ZERO}.
  57      * The default value is {@code FillRule.NON_ZERO}.
  58      *
  59      * @defaultValue FillRule.NON_ZERO
  60      */
  61     private ObjectProperty<FillRule> fillRule;
  62 
  63     private Path2D path2d;
  64 
  65     public final void setFillRule(FillRule value) {
  66         if (fillRule != null || value != FillRule.NON_ZERO) {
  67             fillRuleProperty().set(value);
  68         }
  69     }
  70 
  71     public final FillRule getFillRule() {
  72         return fillRule == null ? FillRule.NON_ZERO : fillRule.get();
  73     }
  74 
  75     public final ObjectProperty<FillRule> fillRuleProperty() {
  76         if (fillRule == null) {
  77             fillRule = new ObjectPropertyBase<FillRule>(FillRule.NON_ZERO) {
  78 
  79                 @Override
  80                 public void invalidated() {
  81                     impl_markDirty(DirtyBits.SHAPE_FILLRULE);
  82                     impl_geomChanged();
  83                 }
  84 
  85                 @Override
  86                 public Object getBean() {
  87                     return SVGPath.this;
  88                 }
  89 
  90                 @Override
  91                 public String getName() {
  92                     return "fillRule";
  93                 }
  94             };
  95         }
  96         return fillRule;
  97     }
  98 
  99     /**
 100      * Defines the SVG Path encoded string as specified at:
 101      * <a href="http://www.w3.org/TR/SVG/paths.html">http://www.w3.org/TR/SVG/paths.html</a>.
 102      *
 103      * @defaultValue empty string
 104      */
 105     private StringProperty content;
 106 
 107 
 108     public final void setContent(String value) {
 109         contentProperty().set(value);
 110     }
 111 
 112     public final String getContent() {
 113         return content == null ? "" : content.get();
 114     }
 115 
 116     public final StringProperty contentProperty() {
 117         if (content == null) {
 118             content = new StringPropertyBase("") {
 119 
 120                 @Override
 121                 public void invalidated() {
 122                     impl_markDirty(DirtyBits.NODE_CONTENTS);
 123                     impl_geomChanged();
 124                     path2d = null;
 125                 }
 126 
 127                 @Override
 128                 public Object getBean() {
 129                     return SVGPath.this;
 130                 }
 131 
 132                 @Override
 133                 public String getName() {
 134                     return "content";
 135                 }
 136             };
 137         }
 138         return content;
 139     }
 140 
 141     private Object svgPathObject;
 142 
 143     /**
 144      * @treatAsPrivate implementation detail
 145      * @deprecated This is an internal API that is not intended for use and will be removed in the next version
 146      */
 147     @Deprecated
 148     @Override
 149     protected NGNode impl_createPeer() {
 150         return new NGSVGPath();
 151     }
 152 
 153     /**
 154      * @treatAsPrivate implementation detail
 155      * @deprecated This is an internal API that is not intended for use and will be removed in the next version
 156      */
 157     @Deprecated
 158     @Override
 159     public Path2D impl_configShape() {
 160         if (path2d == null) {
 161             path2d = createSVGPath2D();
 162         } else {
 163             path2d.setWindingRule(getFillRule() == FillRule.NON_ZERO ?
 164                                   Path2D.WIND_NON_ZERO : Path2D.WIND_EVEN_ODD);
 165         }
 166 
 167         return path2d;
 168     }
 169 
 170     /**
 171      * @treatAsPrivate implementation detail
 172      * @deprecated This is an internal API that is not intended for use and will be removed in the next version
 173      */
 174     @Deprecated
 175     @Override
 176     public void impl_updatePeer() {
 177         super.impl_updatePeer();
 178 
 179         if (impl_isDirty(DirtyBits.SHAPE_FILLRULE) ||
 180             impl_isDirty(DirtyBits.NODE_CONTENTS))
 181         {
 182             final NGSVGPath peer = impl_getPeer();
 183             if (peer.acceptsPath2dOnUpdate()) {
 184                 if (svgPathObject == null) {
 185                     svgPathObject = new Path2D();
 186                 }
 187                 Path2D tempPathObject = (Path2D) svgPathObject;
 188                 tempPathObject.setTo(impl_configShape());
 189             } else {
 190                 svgPathObject = createSVGPathObject();
 191             }
 192             peer.setContent(svgPathObject);
 193         }
 194     }
 195 
 196     /**
 197      * Returns a string representation of this {@code SVGPath} object.
 198      * @return a string representation of this {@code SVGPath} object.
 199      */
 200     @Override
 201     public String toString() {
 202         final StringBuilder sb = new StringBuilder("SVGPath[");
 203 
 204         String id = getId();
 205         if (id != null) {
 206             sb.append("id=").append(id).append(", ");
 207         }
 208 
 209         sb.append("content=\"").append(getContent()).append("\"");
 210 
 211         sb.append(", fill=").append(getFill());
 212         sb.append(", fillRule=").append(getFillRule());
 213 
 214         Paint stroke = getStroke();
 215         if (stroke != null) {
 216             sb.append(", stroke=").append(stroke);
 217             sb.append(", strokeWidth=").append(getStrokeWidth());
 218         }
 219 
 220         return sb.append("]").toString();
 221     }
 222 
 223     private Path2D createSVGPath2D() {
 224         try {
 225             return Toolkit.getToolkit().createSVGPath2D(this);
 226         } catch (final RuntimeException e) {
 227             Logging.getJavaFXLogger().warning(
 228                     "Failed to configure svg path \"{0}\": {1}",
 229                     getContent(), e.getMessage());
 230 
 231             return Toolkit.getToolkit().createSVGPath2D(new SVGPath());
 232         }
 233     }
 234 
 235     private Object createSVGPathObject() {
 236         try {
 237             return Toolkit.getToolkit().createSVGPathObject(this);
 238         } catch (final RuntimeException e) {
 239             Logging.getJavaFXLogger().warning(
 240                     "Failed to configure svg path \"{0}\": {1}",
 241                     getContent(), e.getMessage());
 242 
 243             return Toolkit.getToolkit().createSVGPathObject(new SVGPath());
 244         }
 245     }
 246 }