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