| 1 | /* | 
|---|
| 2 | * Copyright 2006 The Android Open Source Project | 
|---|
| 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 SkPathEffect_DEFINED | 
|---|
| 9 | #define SkPathEffect_DEFINED | 
|---|
| 10 |  | 
|---|
| 11 | #include "include/core/SkFlattenable.h" | 
|---|
| 12 | #include "include/core/SkPath.h" | 
|---|
| 13 | #include "include/core/SkPoint.h" | 
|---|
| 14 | #include "include/core/SkRect.h" | 
|---|
| 15 |  | 
|---|
| 16 | class SkPath; | 
|---|
| 17 | class SkStrokeRec; | 
|---|
| 18 |  | 
|---|
| 19 | /** \class SkPathEffect | 
|---|
| 20 |  | 
|---|
| 21 | SkPathEffect is the base class for objects in the SkPaint that affect | 
|---|
| 22 | the geometry of a drawing primitive before it is transformed by the | 
|---|
| 23 | canvas' matrix and drawn. | 
|---|
| 24 |  | 
|---|
| 25 | Dashing is implemented as a subclass of SkPathEffect. | 
|---|
| 26 | */ | 
|---|
| 27 | class SK_API SkPathEffect : public SkFlattenable { | 
|---|
| 28 | public: | 
|---|
| 29 | /** | 
|---|
| 30 | *  Returns a patheffect that apples each effect (first and second) to the original path, | 
|---|
| 31 | *  and returns a path with the sum of these. | 
|---|
| 32 | * | 
|---|
| 33 | *  result = first(path) + second(path) | 
|---|
| 34 | * | 
|---|
| 35 | */ | 
|---|
| 36 | static sk_sp<SkPathEffect> MakeSum(sk_sp<SkPathEffect> first, sk_sp<SkPathEffect> second); | 
|---|
| 37 |  | 
|---|
| 38 | /** | 
|---|
| 39 | *  Returns a patheffect that applies the inner effect to the path, and then applies the | 
|---|
| 40 | *  outer effect to the result of the inner's. | 
|---|
| 41 | * | 
|---|
| 42 | *  result = outer(inner(path)) | 
|---|
| 43 | */ | 
|---|
| 44 | static sk_sp<SkPathEffect> MakeCompose(sk_sp<SkPathEffect> outer, sk_sp<SkPathEffect> inner); | 
|---|
| 45 |  | 
|---|
| 46 | /** | 
|---|
| 47 | *  Given a src path (input) and a stroke-rec (input and output), apply | 
|---|
| 48 | *  this effect to the src path, returning the new path in dst, and return | 
|---|
| 49 | *  true. If this effect cannot be applied, return false and ignore dst | 
|---|
| 50 | *  and stroke-rec. | 
|---|
| 51 | * | 
|---|
| 52 | *  The stroke-rec specifies the initial request for stroking (if any). | 
|---|
| 53 | *  The effect can treat this as input only, or it can choose to change | 
|---|
| 54 | *  the rec as well. For example, the effect can decide to change the | 
|---|
| 55 | *  stroke's width or join, or the effect can change the rec from stroke | 
|---|
| 56 | *  to fill (or fill to stroke) in addition to returning a new (dst) path. | 
|---|
| 57 | * | 
|---|
| 58 | *  If this method returns true, the caller will apply (as needed) the | 
|---|
| 59 | *  resulting stroke-rec to dst and then draw. | 
|---|
| 60 | */ | 
|---|
| 61 | bool filterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect* cullR) const; | 
|---|
| 62 |  | 
|---|
| 63 | /** | 
|---|
| 64 | *  Compute a conservative bounds for its effect, given the src bounds. | 
|---|
| 65 | *  The baseline implementation just assigns src to dst. | 
|---|
| 66 | */ | 
|---|
| 67 | void computeFastBounds(SkRect* dst, const SkRect& src) const; | 
|---|
| 68 |  | 
|---|
| 69 | /** \class PointData | 
|---|
| 70 |  | 
|---|
| 71 | PointData aggregates all the information needed to draw the point | 
|---|
| 72 | primitives returned by an 'asPoints' call. | 
|---|
| 73 | */ | 
|---|
| 74 | class PointData { | 
|---|
| 75 | public: | 
|---|
| 76 | PointData() | 
|---|
| 77 | : fFlags(0) | 
|---|
| 78 | , fPoints(nullptr) | 
|---|
| 79 | , fNumPoints(0) { | 
|---|
| 80 | fSize.set(SK_Scalar1, SK_Scalar1); | 
|---|
| 81 | // 'asPoints' needs to initialize/fill-in 'fClipRect' if it sets | 
|---|
| 82 | // the kUseClip flag | 
|---|
| 83 | } | 
|---|
| 84 | ~PointData() { | 
|---|
| 85 | delete [] fPoints; | 
|---|
| 86 | } | 
|---|
| 87 |  | 
|---|
| 88 | // TODO: consider using passed-in flags to limit the work asPoints does. | 
|---|
| 89 | // For example, a kNoPath flag could indicate don't bother generating | 
|---|
| 90 | // stamped solutions. | 
|---|
| 91 |  | 
|---|
| 92 | // Currently none of these flags are supported. | 
|---|
| 93 | enum PointFlags { | 
|---|
| 94 | kCircles_PointFlag            = 0x01,   // draw points as circles (instead of rects) | 
|---|
| 95 | kUsePath_PointFlag            = 0x02,   // draw points as stamps of the returned path | 
|---|
| 96 | kUseClip_PointFlag            = 0x04,   // apply 'fClipRect' before drawing the points | 
|---|
| 97 | }; | 
|---|
| 98 |  | 
|---|
| 99 | uint32_t           fFlags;      // flags that impact the drawing of the points | 
|---|
| 100 | SkPoint*           fPoints;     // the center point of each generated point | 
|---|
| 101 | int                fNumPoints;  // number of points in fPoints | 
|---|
| 102 | SkVector           fSize;       // the size to draw the points | 
|---|
| 103 | SkRect             fClipRect;   // clip required to draw the points (if kUseClip is set) | 
|---|
| 104 | SkPath             fPath;       // 'stamp' to be used at each point (if kUsePath is set) | 
|---|
| 105 |  | 
|---|
| 106 | SkPath             fFirst;      // If not empty, contains geometry for first point | 
|---|
| 107 | SkPath             fLast;       // If not empty, contains geometry for last point | 
|---|
| 108 | }; | 
|---|
| 109 |  | 
|---|
| 110 | /** | 
|---|
| 111 | *  Does applying this path effect to 'src' yield a set of points? If so, | 
|---|
| 112 | *  optionally return the points in 'results'. | 
|---|
| 113 | */ | 
|---|
| 114 | bool asPoints(PointData* results, const SkPath& src, | 
|---|
| 115 | const SkStrokeRec&, const SkMatrix&, | 
|---|
| 116 | const SkRect* cullR) const; | 
|---|
| 117 |  | 
|---|
| 118 | /** | 
|---|
| 119 | *  If the PathEffect can be represented as a dash pattern, asADash will return kDash_DashType | 
|---|
| 120 | *  and None otherwise. If a non NULL info is passed in, the various DashInfo will be filled | 
|---|
| 121 | *  in if the PathEffect can be a dash pattern. If passed in info has an fCount equal or | 
|---|
| 122 | *  greater to that of the effect, it will memcpy the values of the dash intervals into the | 
|---|
| 123 | *  info. Thus the general approach will be call asADash once with default info to get DashType | 
|---|
| 124 | *  and fCount. If effect can be represented as a dash pattern, allocate space for the intervals | 
|---|
| 125 | *  in info, then call asADash again with the same info and the intervals will get copied in. | 
|---|
| 126 | */ | 
|---|
| 127 |  | 
|---|
| 128 | enum DashType { | 
|---|
| 129 | kNone_DashType, //!< ignores the info parameter | 
|---|
| 130 | kDash_DashType, //!< fills in all of the info parameter | 
|---|
| 131 | }; | 
|---|
| 132 |  | 
|---|
| 133 | struct DashInfo { | 
|---|
| 134 | DashInfo() : fIntervals(nullptr), fCount(0), fPhase(0) {} | 
|---|
| 135 | DashInfo(SkScalar* intervals, int32_t count, SkScalar phase) | 
|---|
| 136 | : fIntervals(intervals), fCount(count), fPhase(phase) {} | 
|---|
| 137 |  | 
|---|
| 138 | SkScalar*   fIntervals;         //!< Length of on/off intervals for dashed lines | 
|---|
| 139 | //   Even values represent ons, and odds offs | 
|---|
| 140 | int32_t     fCount;             //!< Number of intervals in the dash. Should be even number | 
|---|
| 141 | SkScalar    fPhase;             //!< Offset into the dashed interval pattern | 
|---|
| 142 | //   mod the sum of all intervals | 
|---|
| 143 | }; | 
|---|
| 144 |  | 
|---|
| 145 | DashType asADash(DashInfo* info) const; | 
|---|
| 146 |  | 
|---|
| 147 | static void RegisterFlattenables(); | 
|---|
| 148 |  | 
|---|
| 149 | static SkFlattenable::Type GetFlattenableType() { | 
|---|
| 150 | return kSkPathEffect_Type; | 
|---|
| 151 | } | 
|---|
| 152 |  | 
|---|
| 153 | SkFlattenable::Type getFlattenableType() const override { | 
|---|
| 154 | return kSkPathEffect_Type; | 
|---|
| 155 | } | 
|---|
| 156 |  | 
|---|
| 157 | static sk_sp<SkPathEffect> Deserialize(const void* data, size_t size, | 
|---|
| 158 | const SkDeserialProcs* procs = nullptr) { | 
|---|
| 159 | return sk_sp<SkPathEffect>(static_cast<SkPathEffect*>( | 
|---|
| 160 | SkFlattenable::Deserialize( | 
|---|
| 161 | kSkPathEffect_Type, data, size, procs).release())); | 
|---|
| 162 | } | 
|---|
| 163 |  | 
|---|
| 164 | protected: | 
|---|
| 165 | SkPathEffect() {} | 
|---|
| 166 |  | 
|---|
| 167 | virtual bool onFilterPath(SkPath*, const SkPath&, SkStrokeRec*, const SkRect*) const = 0; | 
|---|
| 168 | virtual SkRect onComputeFastBounds(const SkRect& src) const { | 
|---|
| 169 | return src; | 
|---|
| 170 | } | 
|---|
| 171 | virtual bool onAsPoints(PointData*, const SkPath&, const SkStrokeRec&, const SkMatrix&, | 
|---|
| 172 | const SkRect*) const { | 
|---|
| 173 | return false; | 
|---|
| 174 | } | 
|---|
| 175 | virtual DashType onAsADash(DashInfo*) const { | 
|---|
| 176 | return kNone_DashType; | 
|---|
| 177 | } | 
|---|
| 178 |  | 
|---|
| 179 | private: | 
|---|
| 180 | // illegal | 
|---|
| 181 | SkPathEffect(const SkPathEffect&); | 
|---|
| 182 | SkPathEffect& operator=(const SkPathEffect&); | 
|---|
| 183 |  | 
|---|
| 184 | typedef SkFlattenable INHERITED; | 
|---|
| 185 | }; | 
|---|
| 186 |  | 
|---|
| 187 | #endif | 
|---|
| 188 |  | 
|---|