1
2/*
3 * Copyright 2011 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#ifndef SkDrawLooper_DEFINED
11#define SkDrawLooper_DEFINED
12
13#include "include/core/SkBlurTypes.h"
14#include "include/core/SkColor.h"
15#include "include/core/SkFlattenable.h"
16#include "include/core/SkPoint.h"
17#include <functional> // std::function
18
19class SkArenaAlloc;
20class SkCanvas;
21class SkMatrix;
22class SkPaint;
23struct SkRect;
24
25/** \class SkDrawLooper
26 Subclasses of SkDrawLooper can be attached to a SkPaint. Where they are,
27 and something is drawn to a canvas with that paint, the looper subclass will
28 be called, allowing it to modify the canvas and/or paint for that draw call.
29 More than that, via the next() method, the looper can modify the draw to be
30 invoked multiple times (hence the name loop-er), allow it to perform effects
31 like shadows or frame/fills, that require more than one pass.
32*/
33class SK_API SkDrawLooper : public SkFlattenable {
34public:
35 /**
36 * Holds state during a draw. Users call next() until it returns false.
37 *
38 * Subclasses of SkDrawLooper should create a subclass of this object to
39 * hold state specific to their subclass.
40 */
41 class SK_API Context {
42 public:
43 Context() {}
44 virtual ~Context() {}
45
46 struct Info {
47 SkVector fTranslate;
48 bool fApplyPostCTM;
49
50 void applyToCTM(SkMatrix* ctm) const;
51 void applyToCanvas(SkCanvas*) const;
52 };
53
54 /**
55 * Called in a loop on objects returned by SkDrawLooper::createContext().
56 * Each time true is returned, the object is drawn (possibly with a modified
57 * canvas and/or paint). When false is finally returned, drawing for the object
58 * stops.
59 *
60 * On each call, the paint will be in its original state, but the
61 * canvas will be as it was following the previous call to next() or
62 * createContext().
63 *
64 * The implementation must ensure that, when next() finally returns
65 * false, the canvas has been restored to the state it was
66 * initially, before createContext() was first called.
67 */
68 virtual bool next(Info*, SkPaint*) = 0;
69
70 private:
71 Context(const Context&) = delete;
72 Context& operator=(const Context&) = delete;
73 };
74
75 /**
76 * Called right before something is being drawn. Returns a Context
77 * whose next() method should be called until it returns false.
78 */
79 virtual Context* makeContext(SkArenaAlloc*) const = 0;
80
81 /**
82 * The fast bounds functions are used to enable the paint to be culled early
83 * in the drawing pipeline. If a subclass can support this feature it must
84 * return true for the canComputeFastBounds() function. If that function
85 * returns false then computeFastBounds behavior is undefined otherwise it
86 * is expected to have the following behavior. Given the parent paint and
87 * the parent's bounding rect the subclass must fill in and return the
88 * storage rect, where the storage rect is with the union of the src rect
89 * and the looper's bounding rect.
90 */
91 bool canComputeFastBounds(const SkPaint& paint) const;
92 void computeFastBounds(const SkPaint& paint, const SkRect& src, SkRect* dst) const;
93
94 struct BlurShadowRec {
95 SkScalar fSigma;
96 SkVector fOffset;
97 SkColor fColor;
98 SkBlurStyle fStyle;
99 };
100 /**
101 * If this looper can be interpreted as having two layers, such that
102 * 1. The first layer (bottom most) just has a blur and translate
103 * 2. The second layer has no modifications to either paint or canvas
104 * 3. No other layers.
105 * then return true, and if not null, fill out the BlurShadowRec).
106 *
107 * If any of the above are not met, return false and ignore the BlurShadowRec parameter.
108 */
109 virtual bool asABlurShadow(BlurShadowRec*) const;
110
111 static SkFlattenable::Type GetFlattenableType() {
112 return kSkDrawLooper_Type;
113 }
114
115 SkFlattenable::Type getFlattenableType() const override {
116 return kSkDrawLooper_Type;
117 }
118
119 static sk_sp<SkDrawLooper> Deserialize(const void* data, size_t size,
120 const SkDeserialProcs* procs = nullptr) {
121 return sk_sp<SkDrawLooper>(static_cast<SkDrawLooper*>(
122 SkFlattenable::Deserialize(
123 kSkDrawLooper_Type, data, size, procs).release()));
124 }
125
126 void apply(SkCanvas* canvas, const SkPaint& paint,
127 std::function<void(SkCanvas*, const SkPaint&)>);
128
129protected:
130 SkDrawLooper() {}
131
132private:
133 typedef SkFlattenable INHERITED;
134};
135
136#endif
137