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 { return mBounds; } 43 transformedBounds()44 Rect transformedBounds() const { 45 Rect transformedBounds(transformAndCalculateBounds(mBounds, mTransform)); 46 return transformedBounds; 47 } 48 getTransform()49 const Matrix4& getTransform() const { return mTransform; } 50 transform(const Matrix4 & transform)51 void transform(const Matrix4& transform) { 52 Matrix4 t; 53 t.loadMultiply(transform, mTransform); 54 mTransform = t; 55 } 56 57 private: 58 Rect mBounds; 59 Matrix4 mTransform; 60 }; 61 62 class RectangleList { 63 public: 64 RectangleList(); 65 66 bool isEmpty() const; 67 int getTransformedRectanglesCount() const; 68 const TransformedRectangle& getTransformedRectangle(int i) const; 69 70 void setEmpty(); 71 void set(const Rect& bounds, const Matrix4& transform); 72 bool intersectWith(const Rect& bounds, const Matrix4& transform); 73 void transform(const Matrix4& transform); 74 75 SkRegion convertToRegion(const SkRegion& clip) const; 76 Rect calculateBounds() const; 77 78 enum { kMaxTransformedRectangles = 5 }; 79 80 private: 81 int mTransformedRectanglesCount; 82 TransformedRectangle mTransformedRectangles[kMaxTransformedRectangles]; 83 }; 84 85 enum class ClipMode { 86 Rectangle, 87 RectangleList, 88 89 // region and path - intersected. if either is empty, don't use 90 Region 91 }; 92 93 struct ClipBase { ClipBaseClipBase94 explicit ClipBase(ClipMode mode) : mode(mode) {} ClipBaseClipBase95 explicit ClipBase(const Rect& rect) : mode(ClipMode::Rectangle), rect(rect) {} 96 const ClipMode mode; 97 bool intersectWithRoot = false; 98 // Bounds of the clipping area, used to define the scissor, and define which 99 // portion of the stencil is updated/used 100 Rect rect; 101 102 void dump() const; 103 }; 104 105 struct ClipRect : ClipBase { ClipRectClipRect106 explicit ClipRect(const Rect& rect) : ClipBase(rect) {} 107 }; 108 109 struct ClipRectList : ClipBase { ClipRectListClipRectList110 explicit ClipRectList(const RectangleList& rectList) 111 : ClipBase(ClipMode::RectangleList), rectList(rectList) {} 112 RectangleList rectList; 113 }; 114 115 struct ClipRegion : ClipBase { ClipRegionClipRegion116 explicit ClipRegion(const SkRegion& region) : ClipBase(ClipMode::Region), region(region) {} ClipRegionClipRegion117 ClipRegion() : ClipBase(ClipMode::Region) {} 118 SkRegion region; 119 }; 120 121 class ClipArea { 122 public: 123 ClipArea(); 124 125 void setViewportDimensions(int width, int height); 126 isEmpty()127 bool isEmpty() const { return mClipRect.isEmpty(); } 128 129 void setEmpty(); 130 void setClip(float left, float top, float right, float bottom); 131 void clipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op); 132 void clipPathWithTransform(const SkPath& path, const mat4* transform, SkRegion::Op op); 133 getClipRect()134 const Rect& getClipRect() const { return mClipRect; } 135 getClipRegion()136 const SkRegion& getClipRegion() const { return mClipRegion; } 137 getRectangleList()138 const RectangleList& getRectangleList() const { return mRectangleList; } 139 isRegion()140 bool isRegion() const { return ClipMode::Region == mMode; } 141 isSimple()142 bool isSimple() const { return mMode == ClipMode::Rectangle; } 143 isRectangleList()144 bool isRectangleList() const { return mMode == ClipMode::RectangleList; } 145 146 WARN_UNUSED_RESULT const ClipBase* serializeClip(LinearAllocator& allocator); 147 WARN_UNUSED_RESULT const ClipBase* serializeIntersectedClip( 148 LinearAllocator& allocator, const ClipBase* recordedClip, 149 const Matrix4& recordedClipTransform); 150 void applyClip(const ClipBase* recordedClip, const Matrix4& recordedClipTransform); 151 152 static void applyTransformToRegion(const Matrix4& transform, SkRegion* region); 153 154 private: 155 void enterRectangleMode(); 156 void rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op); 157 158 void enterRectangleListMode(); 159 void rectangleListModeClipRectWithTransform(const Rect& r, const mat4* transform, 160 SkRegion::Op op); 161 162 void enterRegionModeFromRectangleMode(); 163 void enterRegionModeFromRectangleListMode(); 164 void enterRegionMode(); 165 void regionModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op); 166 167 void clipRegion(const SkRegion& region, SkRegion::Op op); 168 void ensureClipRegion(); 169 void onClipRegionUpdated(); 170 171 // Called by every state modifying public method. onClipUpdated()172 void onClipUpdated() { 173 mPostViewportClipObserved = true; 174 mLastSerialization = nullptr; 175 mLastResolutionResult = nullptr; 176 } 177 createViewportRegion()178 SkRegion createViewportRegion() { return SkRegion(mViewportBounds.toSkIRect()); } 179 regionFromPath(const SkPath & path,SkRegion & pathAsRegion)180 void regionFromPath(const SkPath& path, SkRegion& pathAsRegion) { 181 // TODO: this should not mask every path to the viewport - this makes it impossible to use 182 // paths to clip to larger areas (which is valid e.g. with SkRegion::kReplace_Op) 183 pathAsRegion.setPath(path, createViewportRegion()); 184 } 185 186 ClipMode mMode; 187 bool mPostViewportClipObserved = false; 188 bool mReplaceOpObserved = false; 189 190 /** 191 * If mLastSerialization is non-null, it represents an already serialized copy 192 * of the current clip state. If null, it has not been computed. 193 */ 194 const ClipBase* mLastSerialization = nullptr; 195 196 /** 197 * This pair of pointers is a single entry cache of most recently seen 198 */ 199 const ClipBase* mLastResolutionResult = nullptr; 200 const ClipBase* mLastResolutionClip = nullptr; 201 Matrix4 mLastResolutionTransform; 202 203 Rect mViewportBounds; 204 Rect mClipRect; 205 SkRegion mClipRegion; 206 RectangleList mRectangleList; 207 }; 208 209 } /* namespace uirenderer */ 210 } /* namespace android */ 211 212 #endif /* CLIPAREA_H_ */ 213