Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2012 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #ifndef SkStrokeRec_DEFINED
      9 #define SkStrokeRec_DEFINED
     10 
     11 #include "../private/SkMacros.h"
     12 #include "SkPaint.h"
     13 
     14 class SkPath;
     15 
     16 SK_BEGIN_REQUIRE_DENSE
     17 class SkStrokeRec {
     18 public:
     19     enum InitStyle {
     20         kHairline_InitStyle,
     21         kFill_InitStyle
     22     };
     23     SkStrokeRec(InitStyle style);
     24     SkStrokeRec(const SkPaint&, SkPaint::Style, SkScalar resScale = 1);
     25     explicit SkStrokeRec(const SkPaint&, SkScalar resScale = 1);
     26 
     27     enum Style {
     28         kHairline_Style,
     29         kFill_Style,
     30         kStroke_Style,
     31         kStrokeAndFill_Style
     32     };
     33 
     34     static constexpr int kStyleCount = kStrokeAndFill_Style + 1;
     35 
     36     Style getStyle() const;
     37     SkScalar getWidth() const { return fWidth; }
     38     SkScalar getMiter() const { return fMiterLimit; }
     39     SkPaint::Cap getCap() const { return (SkPaint::Cap)fCap; }
     40     SkPaint::Join getJoin() const { return (SkPaint::Join)fJoin; }
     41 
     42     bool isHairlineStyle() const {
     43         return kHairline_Style == this->getStyle();
     44     }
     45 
     46     bool isFillStyle() const {
     47         return kFill_Style == this->getStyle();
     48     }
     49 
     50     void setFillStyle();
     51     void setHairlineStyle();
     52     /**
     53      *  Specify the strokewidth, and optionally if you want stroke + fill.
     54      *  Note, if width==0, then this request is taken to mean:
     55      *      strokeAndFill==true -> new style will be Fill
     56      *      strokeAndFill==false -> new style will be Hairline
     57      */
     58     void setStrokeStyle(SkScalar width, bool strokeAndFill = false);
     59 
     60     void setStrokeParams(SkPaint::Cap cap, SkPaint::Join join, SkScalar miterLimit) {
     61         fCap = cap;
     62         fJoin = join;
     63         fMiterLimit = miterLimit;
     64     }
     65 
     66     SkScalar getResScale() const {
     67         return fResScale;
     68     }
     69 
     70     void setResScale(SkScalar rs) {
     71         SkASSERT(rs > 0 && SkScalarIsFinite(rs));
     72         fResScale = rs;
     73     }
     74 
     75     /**
     76      *  Returns true if this specifes any thick stroking, i.e. applyToPath()
     77      *  will return true.
     78      */
     79     bool needToApply() const {
     80         Style style = this->getStyle();
     81         return (kStroke_Style == style) || (kStrokeAndFill_Style == style);
     82     }
     83 
     84     /**
     85      *  Apply these stroke parameters to the src path, returning the result
     86      *  in dst.
     87      *
     88      *  If there was no change (i.e. style == hairline or fill) this returns
     89      *  false and dst is unchanged. Otherwise returns true and the result is
     90      *  stored in dst.
     91      *
     92      *  src and dst may be the same path.
     93      */
     94     bool applyToPath(SkPath* dst, const SkPath& src) const;
     95 
     96     /**
     97      *  Apply these stroke parameters to a paint.
     98      */
     99     void applyToPaint(SkPaint* paint) const;
    100 
    101     /**
    102      * Gives a conservative value for the outset that should applied to a
    103      * geometries bounds to account for any inflation due to applying this
    104      * strokeRec to the geometry.
    105      */
    106     SkScalar getInflationRadius() const;
    107 
    108     /**
    109      * Equivalent to:
    110      *   SkStrokeRec rec(paint, style);
    111      *   rec.getInflationRadius();
    112      * This does not account for other effects on the paint (i.e. path
    113      * effect).
    114      */
    115     static SkScalar GetInflationRadius(const SkPaint&, SkPaint::Style);
    116 
    117     static SkScalar GetInflationRadius(SkPaint::Join, SkScalar miterLimit, SkPaint::Cap,
    118                                        SkScalar strokeWidth);
    119 
    120     /**
    121      * Compare if two SkStrokeRecs have an equal effect on a path.
    122      * Equal SkStrokeRecs produce equal paths. Equality of produced
    123      * paths does not take the ResScale parameter into account.
    124      */
    125     bool hasEqualEffect(const SkStrokeRec& other) const {
    126         if (!this->needToApply()) {
    127             return this->getStyle() == other.getStyle();
    128         }
    129         return fWidth == other.fWidth &&
    130                fMiterLimit == other.fMiterLimit &&
    131                fCap == other.fCap &&
    132                fJoin == other.fJoin &&
    133                fStrokeAndFill == other.fStrokeAndFill;
    134     }
    135 
    136 private:
    137     void init(const SkPaint&, SkPaint::Style, SkScalar resScale);
    138 
    139     SkScalar        fResScale;
    140     SkScalar        fWidth;
    141     SkScalar        fMiterLimit;
    142     // The following three members are packed together into a single u32.
    143     // This is to avoid unnecessary padding and ensure binary equality for
    144     // hashing (because the padded areas might contain garbage values).
    145     //
    146     // fCap and fJoin are larger than needed to avoid having to initialize
    147     // any pad values
    148     uint32_t        fCap : 16;             // SkPaint::Cap
    149     uint32_t        fJoin : 15;            // SkPaint::Join
    150     uint32_t        fStrokeAndFill : 1;    // bool
    151 };
    152 SK_END_REQUIRE_DENSE
    153 
    154 #endif
    155