Home | History | Annotate | Download | only in gpu
      1 /*
      2  * Copyright 2014 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 GrStrokeInfo_DEFINED
      9 #define GrStrokeInfo_DEFINED
     10 
     11 #include "SkPathEffect.h"
     12 #include "SkStrokeRec.h"
     13 #include "SkTemplates.h"
     14 
     15 class GrUniqueKey;
     16 
     17 /*
     18  * GrStrokeInfo encapsulates all the pertinent infomation regarding the stroke. The SkStrokeRec
     19  * which holds information on fill style, width, miter, cap, and join. It also holds information
     20  * about the dash like intervals, count, and phase.
     21  */
     22 class GrStrokeInfo : public SkStrokeRec {
     23 public:
     24     static const GrStrokeInfo& FillInfo() {
     25         static const GrStrokeInfo gFill(kFill_InitStyle);
     26         return gFill;
     27     }
     28 
     29     GrStrokeInfo(SkStrokeRec::InitStyle style)
     30         : INHERITED(style)
     31         , fDashType(SkPathEffect::kNone_DashType) {
     32     }
     33 
     34     GrStrokeInfo(const GrStrokeInfo& src, bool includeDash = true)
     35         : INHERITED(src) {
     36         if (includeDash && src.isDashed()) {
     37             fDashType = src.fDashType;
     38             fDashPhase = src.fDashPhase;
     39             fIntervals.reset(src.getDashCount());
     40             memcpy(fIntervals.get(), src.fIntervals.get(), fIntervals.count() * sizeof(SkScalar));
     41         } else {
     42             fDashType = SkPathEffect::kNone_DashType;
     43         }
     44     }
     45 
     46     GrStrokeInfo(const SkPaint& paint, SkPaint::Style styleOverride)
     47         : INHERITED(paint, styleOverride)
     48         , fDashType(SkPathEffect::kNone_DashType) {
     49         this->init(paint);
     50     }
     51 
     52     explicit GrStrokeInfo(const SkPaint& paint)
     53         : INHERITED(paint)
     54         , fDashType(SkPathEffect::kNone_DashType) {
     55         this->init(paint);
     56     }
     57 
     58     GrStrokeInfo& operator=(const GrStrokeInfo& other) {
     59         if (other.isDashed()) {
     60             fDashType = other.fDashType;
     61             fDashPhase = other.fDashPhase;
     62             fIntervals.reset(other.getDashCount());
     63             memcpy(fIntervals.get(), other.fIntervals.get(), fIntervals.count() * sizeof(SkScalar));
     64         } else {
     65             this->removeDash();
     66         }
     67         this->INHERITED::operator=(other);
     68         return *this;
     69     }
     70 
     71     bool hasEqualEffect(const GrStrokeInfo& other) const {
     72         if (this->isDashed() != other.isDashed()) {
     73             return false;
     74         }
     75         if (this->isDashed()) {
     76             if (fDashPhase != other.fDashPhase ||
     77                 fIntervals.count() != other.fIntervals.count() ||
     78                 memcmp(fIntervals.get(), other.fIntervals.get(),
     79                        fIntervals.count() * sizeof(SkScalar)) != 0) {
     80                 return false;
     81             }
     82         }
     83         return this->INHERITED::hasEqualEffect(other);
     84     }
     85 
     86     /*
     87      * This functions takes in a patheffect and updates the dashing information if the path effect
     88      * is a Dash type. Returns true if the path effect is a dashed effect and we are stroking,
     89      * otherwise it returns false.
     90      */
     91     bool setDashInfo(const SkPathEffect* pe) {
     92         if (pe && !this->isFillStyle()) {
     93             SkPathEffect::DashInfo dashInfo;
     94             fDashType = pe->asADash(&dashInfo);
     95             if (SkPathEffect::kDash_DashType == fDashType) {
     96                 fIntervals.reset(dashInfo.fCount);
     97                 dashInfo.fIntervals = fIntervals.get();
     98                 pe->asADash(&dashInfo);
     99                 fDashPhase = dashInfo.fPhase;
    100                 return true;
    101             }
    102         }
    103         return false;
    104     }
    105 
    106     /*
    107      * Like the above, but sets with an explicit SkPathEffect::DashInfo
    108      */
    109     bool setDashInfo(const SkPathEffect::DashInfo& info) {
    110         if (!this->isFillStyle()) {
    111             fDashType = SkPathEffect::kDash_DashType;
    112             fDashPhase = info.fPhase;
    113             fIntervals.reset(info.fCount);
    114             for (int i = 0; i < fIntervals.count(); i++) {
    115                 fIntervals[i] = info.fIntervals[i];
    116             }
    117             return true;
    118         }
    119         return false;
    120     }
    121 
    122     bool isDashed() const {
    123         return (!this->isFillStyle() && SkPathEffect::kDash_DashType == fDashType);
    124     }
    125 
    126     int32_t getDashCount() const {
    127         SkASSERT(this->isDashed());
    128         return fIntervals.count();
    129     }
    130 
    131     SkScalar getDashPhase() const {
    132         SkASSERT(this->isDashed());
    133         return fDashPhase;
    134     }
    135 
    136     const SkScalar* getDashIntervals() const {
    137         SkASSERT(this->isDashed());
    138         return fIntervals.get();
    139     }
    140 
    141     void removeDash() {
    142         fDashType = SkPathEffect::kNone_DashType;
    143     }
    144 
    145     /** Applies the dash to a path, if the stroke info has dashing.
    146      * @return true if the dashing was applied (dst and dstStrokeInfo will be modified).
    147      *         false if the stroke info did not have dashing. The dst and dstStrokeInfo
    148      *               will be unmodified. The stroking in the SkStrokeRec might still
    149      *               be applicable.
    150      */
    151     bool applyDashToPath(SkPath* dst, GrStrokeInfo* dstStrokeInfo, const SkPath& src) const;
    152 
    153     /**
    154      * Computes the length of the data that will be written by asUniqueKeyFragment() function.
    155      */
    156     int computeUniqueKeyFragmentData32Cnt() const {
    157         const int kSkScalarData32Cnt = sizeof(SkScalar) / sizeof(uint32_t);
    158         // SkStrokeRec data: 32 bits for style+join+cap and 2 scalars for miter and width.
    159         int strokeKeyData32Cnt = 1 + 2 * kSkScalarData32Cnt;
    160 
    161         if (this->isDashed()) {
    162             // One scalar for dash phase and one for each dash value.
    163             strokeKeyData32Cnt += (1 + this->getDashCount()) * kSkScalarData32Cnt;
    164         }
    165         return strokeKeyData32Cnt;
    166     }
    167 
    168     /**
    169      * Writes the object contents as uint32_t data, to be used with GrUniqueKey.
    170      * Note: the data written does not encode the length, so care must be taken to ensure
    171      * that the full unique key data is encoded properly. For example, GrStrokeInfo
    172      * fragment can be placed last in the sequence, at fixed index.
    173      */
    174     void asUniqueKeyFragment(uint32_t*) const;
    175 
    176 private:
    177     // Prevent accidental usage, should use GrStrokeInfo::hasEqualEffect.
    178     bool hasEqualEffect(const SkStrokeRec& other) const;
    179 
    180     void init(const SkPaint& paint) {
    181         const SkPathEffect* pe = paint.getPathEffect();
    182         this->setDashInfo(pe);
    183     }
    184 
    185     SkPathEffect::DashType fDashType;
    186     SkScalar               fDashPhase;
    187     SkAutoSTArray<2, SkScalar> fIntervals;
    188     typedef SkStrokeRec INHERITED;
    189 };
    190 
    191 #endif
    192