• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 // TODO: Can we get the dependencies scoped down more?
20 #include "CanvasOps.h"
21 #include "CanvasOpBuffer.h"
22 #include <SaveFlags.h>
23 
24 #include <SkRasterClip.h>
25 #include <ui/FatVector.h>
26 
27 #include <optional>
28 
29 namespace android::uirenderer {
30 
31 // Exists to avoid forcing all this common logic into the templated class
32 class CanvasStateHelper {
33 protected:
34     CanvasStateHelper(int width, int height);
35     ~CanvasStateHelper() = default;
36 
37     struct SaveEntry {
38         bool clip : 1 = false;
39         bool matrix : 1 = false;
40         bool layer : 1 = false;
41     };
42 
saveEntryForLayer()43     constexpr SaveEntry saveEntryForLayer() {
44         return {
45             .clip = true,
46             .matrix = true,
47             .layer = true,
48         };
49     }
50 
flagsToSaveEntry(SaveFlags::Flags flags)51     constexpr SaveEntry flagsToSaveEntry(SaveFlags::Flags flags) {
52         return SaveEntry {
53             .clip = static_cast<bool>(flags & SaveFlags::Clip),
54             .matrix = static_cast<bool>(flags & SaveFlags::Matrix),
55             .layer = false
56         };
57     }
58 
59     bool internalSave(SaveEntry saveEntry);
60 
internalSaveLayer(const SkCanvas::SaveLayerRec & layerRec)61     void internalSaveLayer(const SkCanvas::SaveLayerRec& layerRec) {
62         internalSave({
63             .clip = true,
64             .matrix = true,
65             .layer = true
66         });
67         internalClipRect(*layerRec.fBounds, SkClipOp::kIntersect);
68     }
69 
70     bool internalRestore();
71 
72     void internalClipRect(const SkRect& rect, SkClipOp op);
73     void internalClipPath(const SkPath& path, SkClipOp op);
74 
75     SkIRect mInitialBounds;
76     FatVector<SaveEntry, 6> mSaveStack;
77     FatVector<SkMatrix, 6> mTransformStack;
78     FatVector<SkConservativeClip, 6> mClipStack;
79 
80     size_t mCurrentTransformIndex;
81     size_t mCurrentClipIndex;
82 
clip()83     const SkConservativeClip& clip() const {
84         return mClipStack[mCurrentClipIndex];
85     }
86 
clip()87     SkConservativeClip& clip() {
88         return mClipStack[mCurrentClipIndex];
89     }
90 
91     void resetState(int width, int height);
92 
93 public:
saveCount()94     int saveCount() const { return mSaveStack.size(); }
95 
96     SkRect getClipBounds() const;
97     bool quickRejectRect(float left, float top, float right, float bottom) const;
98     bool quickRejectPath(const SkPath& path) const;
99 
transform()100     const SkMatrix& transform() const {
101         return mTransformStack[mCurrentTransformIndex];
102     }
103 
transform()104     SkMatrix& transform() {
105         return mTransformStack[mCurrentTransformIndex];
106     }
107 
108     // For compat with existing HWUI Canvas interface
getMatrix(SkMatrix * outMatrix)109     void getMatrix(SkMatrix* outMatrix) const {
110         *outMatrix = transform();
111     }
112 
setMatrix(const SkMatrix & matrix)113     void setMatrix(const SkMatrix& matrix) {
114         transform() = matrix;
115     }
116 
concat(const SkMatrix & matrix)117     void concat(const SkMatrix& matrix) {
118         transform().preConcat(matrix);
119     }
120 
rotate(float degrees)121     void rotate(float degrees) {
122         SkMatrix m;
123         m.setRotate(degrees);
124         concat(m);
125     }
126 
scale(float sx,float sy)127     void scale(float sx, float sy) {
128         SkMatrix m;
129         m.setScale(sx, sy);
130         concat(m);
131     }
132 
skew(float sx,float sy)133     void skew(float sx, float sy) {
134         SkMatrix m;
135         m.setSkew(sx, sy);
136         concat(m);
137     }
138 
translate(float dx,float dy)139     void translate(float dx, float dy) {
140         transform().preTranslate(dx, dy);
141     }
142 };
143 
144 // Front-end canvas that handles queries, up-front state, and produces CanvasOp<> output downstream
145 template <typename CanvasOpReceiver>
146 class CanvasFrontend final : public CanvasStateHelper {
147 public:
148     template<class... Args>
CanvasFrontend(int width,int height,Args &&...args)149     CanvasFrontend(int width, int height, Args&&... args) : CanvasStateHelper(width, height),
150             mReceiver(std::in_place, std::forward<Args>(args)...) { }
151 
152     void save(SaveFlags::Flags flags = SaveFlags::MatrixClip) {
153         if (internalSave(flagsToSaveEntry(flags))) {
154             submit<CanvasOpType::Save>({});
155         }
156     }
157 
restore()158     void restore() {
159         if (internalRestore()) {
160             submit<CanvasOpType::Restore>({});
161         }
162     }
163 
164     template <CanvasOpType T>
draw(CanvasOp<T> && op)165     void draw(CanvasOp<T>&& op) {
166         // The front-end requires going through certain front-doors, which these aren't.
167         static_assert(T != CanvasOpType::Save, "Must use CanvasFrontend::save() call instead");
168         static_assert(T != CanvasOpType::Restore, "Must use CanvasFrontend::restore() call instead");
169 
170         if constexpr (T == CanvasOpType::SaveLayer) {
171             internalSaveLayer(op.saveLayerRec);
172         }
173         if constexpr (T == CanvasOpType::SaveBehind) {
174             // Don't use internalSaveLayer as this doesn't apply clipping, it's a "regular" save
175             // But we do want to flag it as a layer, such that restore is Definitely Required
176             internalSave(saveEntryForLayer());
177         }
178         if constexpr (T == CanvasOpType::ClipRect) {
179             internalClipRect(op.rect, op.op);
180         }
181         if constexpr (T == CanvasOpType::ClipPath) {
182             internalClipPath(op.path, op.op);
183         }
184 
185         submit(std::move(op));
186     }
187 
receiver()188     const CanvasOpReceiver& receiver() const {
189         LOG_ALWAYS_FATAL_IF(!mReceiver.has_value());
190         return *mReceiver;
191     }
192 
finish()193     CanvasOpReceiver finish() {
194         auto ret = std::move(mReceiver.value());
195         mReceiver.reset();
196         return std::move(ret);
197     }
198 
199     template<class... Args>
reset(int newWidth,int newHeight,Args &&...args)200     void reset(int newWidth, int newHeight, Args&&... args) {
201         resetState(newWidth, newHeight);
202         mReceiver.emplace(std::forward<Args>(args)...);
203     }
204 
205 private:
206     std::optional<CanvasOpReceiver> mReceiver;
207 
208     template <CanvasOpType T>
submit(CanvasOp<T> && op)209     void submit(CanvasOp<T>&& op) {
210         LOG_ALWAYS_FATAL_IF(!mReceiver.has_value());
211         mReceiver->push_container(CanvasOpContainer(std::move(op), transform()));
212     }
213 };
214 
215 } // namespace android::uirenderer
216