1 /* 2 * Copyright (C) 2015 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 #ifndef CLIPAREA_H 17 #define CLIPAREA_H 18 19 #include "Matrix.h" 20 #include "Rect.h" 21 #include "utils/Pair.h" 22 23 #include <SkRegion.h> 24 25 namespace android { 26 namespace uirenderer { 27 28 class LinearAllocator; 29 30 Rect transformAndCalculateBounds(const Rect& r, const Matrix4& transform); 31 32 class TransformedRectangle { 33 public: 34 TransformedRectangle(); 35 TransformedRectangle(const Rect& bounds, const Matrix4& transform); 36 37 bool canSimplyIntersectWith(const TransformedRectangle& other) const; 38 void intersectWith(const TransformedRectangle& other); 39 40 bool isEmpty() const; 41 getBounds()42 const Rect& getBounds() const { 43 return mBounds; 44 } 45 transformedBounds()46 Rect transformedBounds() const { 47 Rect transformedBounds(transformAndCalculateBounds(mBounds, mTransform)); 48 return transformedBounds; 49 } 50 getTransform()51 const Matrix4& getTransform() const { 52 return mTransform; 53 } 54 transform(const Matrix4 & transform)55 void transform(const Matrix4& transform) { 56 Matrix4 t; 57 t.loadMultiply(transform, mTransform); 58 mTransform = t; 59 } 60 61 private: 62 Rect mBounds; 63 Matrix4 mTransform; 64 }; 65 66 class RectangleList { 67 public: 68 RectangleList(); 69 70 bool isEmpty() const; 71 int getTransformedRectanglesCount() const; 72 const TransformedRectangle& getTransformedRectangle(int i) const; 73 74 void setEmpty(); 75 void set(const Rect& bounds, const Matrix4& transform); 76 bool intersectWith(const Rect& bounds, const Matrix4& transform); 77 void transform(const Matrix4& transform); 78 79 SkRegion convertToRegion(const SkRegion& clip) const; 80 Rect calculateBounds() const; 81 82 enum { 83 kMaxTransformedRectangles = 5 84 }; 85 86 private: 87 int mTransformedRectanglesCount; 88 TransformedRectangle mTransformedRectangles[kMaxTransformedRectangles]; 89 }; 90 91 enum class ClipMode { 92 Rectangle, 93 RectangleList, 94 95 // region and path - intersected. if either is empty, don't use 96 Region 97 }; 98 99 struct ClipBase { ClipBaseClipBase100 explicit ClipBase(ClipMode mode) 101 : mode(mode) {} ClipBaseClipBase102 explicit ClipBase(const Rect& rect) 103 : mode(ClipMode::Rectangle) 104 , rect(rect) {} 105 const ClipMode mode; 106 bool intersectWithRoot = false; 107 // Bounds of the clipping area, used to define the scissor, and define which 108 // portion of the stencil is updated/used 109 Rect rect; 110 111 void dump() const; 112 }; 113 114 struct ClipRect : ClipBase { ClipRectClipRect115 explicit ClipRect(const Rect& rect) 116 : ClipBase(rect) {} 117 }; 118 119 struct ClipRectList : ClipBase { ClipRectListClipRectList120 explicit ClipRectList(const RectangleList& rectList) 121 : ClipBase(ClipMode::RectangleList) 122 , rectList(rectList) {} 123 RectangleList rectList; 124 }; 125 126 struct ClipRegion : ClipBase { ClipRegionClipRegion127 explicit ClipRegion(const SkRegion& region) 128 : ClipBase(ClipMode::Region) 129 , region(region) {} ClipRegionClipRegion130 ClipRegion() 131 : ClipBase(ClipMode::Region) {} 132 SkRegion region; 133 }; 134 135 class ClipArea { 136 public: 137 ClipArea(); 138 139 void setViewportDimensions(int width, int height); 140 isEmpty()141 bool isEmpty() const { 142 return mClipRect.isEmpty(); 143 } 144 145 void setEmpty(); 146 void setClip(float left, float top, float right, float bottom); 147 void clipRectWithTransform(const Rect& r, const mat4* transform, 148 SkRegion::Op op); 149 void clipPathWithTransform(const SkPath& path, const mat4* transform, 150 SkRegion::Op op); 151 getClipRect()152 const Rect& getClipRect() const { 153 return mClipRect; 154 } 155 getClipRegion()156 const SkRegion& getClipRegion() const { 157 return mClipRegion; 158 } 159 getRectangleList()160 const RectangleList& getRectangleList() const { 161 return mRectangleList; 162 } 163 isRegion()164 bool isRegion() const { 165 return ClipMode::Region == mMode; 166 } 167 isSimple()168 bool isSimple() const { 169 return mMode == ClipMode::Rectangle; 170 } 171 isRectangleList()172 bool isRectangleList() const { 173 return mMode == ClipMode::RectangleList; 174 } 175 176 WARN_UNUSED_RESULT const ClipBase* serializeClip(LinearAllocator& allocator); 177 WARN_UNUSED_RESULT const ClipBase* serializeIntersectedClip(LinearAllocator& allocator, 178 const ClipBase* recordedClip, const Matrix4& recordedClipTransform); 179 void applyClip(const ClipBase* recordedClip, const Matrix4& recordedClipTransform); 180 181 static void applyTransformToRegion(const Matrix4& transform, SkRegion* region); 182 183 private: 184 void enterRectangleMode(); 185 void rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op); 186 187 void enterRectangleListMode(); 188 void rectangleListModeClipRectWithTransform(const Rect& r, 189 const mat4* transform, SkRegion::Op op); 190 191 void enterRegionModeFromRectangleMode(); 192 void enterRegionModeFromRectangleListMode(); 193 void enterRegionMode(); 194 void regionModeClipRectWithTransform(const Rect& r, const mat4* transform, 195 SkRegion::Op op); 196 197 void clipRegion(const SkRegion& region, SkRegion::Op op); 198 void ensureClipRegion(); 199 void onClipRegionUpdated(); 200 201 // Called by every state modifying public method. onClipUpdated()202 void onClipUpdated() { 203 mPostViewportClipObserved = true; 204 mLastSerialization = nullptr; 205 mLastResolutionResult = nullptr; 206 } 207 createViewportRegion()208 SkRegion createViewportRegion() { 209 return SkRegion(mViewportBounds.toSkIRect()); 210 } 211 regionFromPath(const SkPath & path,SkRegion & pathAsRegion)212 void regionFromPath(const SkPath& path, SkRegion& pathAsRegion) { 213 // TODO: this should not mask every path to the viewport - this makes it impossible to use 214 // paths to clip to larger areas (which is valid e.g. with SkRegion::kReplace_Op) 215 pathAsRegion.setPath(path, createViewportRegion()); 216 } 217 218 ClipMode mMode; 219 bool mPostViewportClipObserved = false; 220 bool mReplaceOpObserved = false; 221 222 /** 223 * If mLastSerialization is non-null, it represents an already serialized copy 224 * of the current clip state. If null, it has not been computed. 225 */ 226 const ClipBase* mLastSerialization = nullptr; 227 228 /** 229 * This pair of pointers is a single entry cache of most recently seen 230 */ 231 const ClipBase* mLastResolutionResult = nullptr; 232 const ClipBase* mLastResolutionClip = nullptr; 233 Matrix4 mLastResolutionTransform; 234 235 Rect mViewportBounds; 236 Rect mClipRect; 237 SkRegion mClipRegion; 238 RectangleList mRectangleList; 239 }; 240 241 } /* namespace uirenderer */ 242 } /* namespace android */ 243 244 #endif /* CLIPAREA_H_ */ 245