ClipArea.h revision e4db79de127cfe961195f52907af8451026eaa20
1ce0537b80087a6225273040a987414b1dd081aa0Romain Guy/* 2ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * Copyright (C) 2015 The Android Open Source Project 3ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * 4ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * Licensed under the Apache License, Version 2.0 (the "License"); 5ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * you may not use this file except in compliance with the License. 6ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * You may obtain a copy of the License at 7ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * 8ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * http://www.apache.org/licenses/LICENSE-2.0 9ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * 10ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * Unless required by applicable law or agreed to in writing, software 11ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * distributed under the License is distributed on an "AS IS" BASIS, 12ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * See the License for the specific language governing permissions and 14ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * limitations under the License. 15ce0537b80087a6225273040a987414b1dd081aa0Romain Guy */ 16ce0537b80087a6225273040a987414b1dd081aa0Romain Guy#ifndef CLIPAREA_H 175b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy#define CLIPAREA_H 185b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy 19ce0537b80087a6225273040a987414b1dd081aa0Romain Guy#include "Matrix.h" 20ce0537b80087a6225273040a987414b1dd081aa0Romain Guy#include "Rect.h" 21ce0537b80087a6225273040a987414b1dd081aa0Romain Guy#include "utils/Pair.h" 22ce0537b80087a6225273040a987414b1dd081aa0Romain Guy 2321b028a44f3e0bd9b0f0432b8b92c45f661d22a4Romain Guy#include <SkRegion.h> 24ce0537b80087a6225273040a987414b1dd081aa0Romain Guy 25ce0537b80087a6225273040a987414b1dd081aa0Romain Guynamespace android { 26ce0537b80087a6225273040a987414b1dd081aa0Romain Guynamespace uirenderer { 27ce0537b80087a6225273040a987414b1dd081aa0Romain Guy 28d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet Haaseclass LinearAllocator; 29d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet Haase 30d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet HaaseRect transformAndCalculateBounds(const Rect& r, const Matrix4& transform); 31d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet Haase 32d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet Haaseclass TransformedRectangle { 33d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet Haasepublic: 34d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet Haase TransformedRectangle(); 35d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet Haase TransformedRectangle(const Rect& bounds, const Matrix4& transform); 36d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet Haase 37d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet Haase bool canSimplyIntersectWith(const TransformedRectangle& other) const; 38d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet Haase void intersectWith(const TransformedRectangle& other); 39d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet Haase 40d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet Haase bool isEmpty() const; 41d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet Haase 429e10841c27d973b930e1b49a099c69d866659505Romain Guy const Rect& getBounds() const { 439e10841c27d973b930e1b49a099c69d866659505Romain Guy return mBounds; 449e10841c27d973b930e1b49a099c69d866659505Romain Guy } 459e10841c27d973b930e1b49a099c69d866659505Romain Guy 46121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy Rect transformedBounds() const { 47121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy Rect transformedBounds(transformAndCalculateBounds(mBounds, mTransform)); 48121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy return transformedBounds; 49121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy } 50121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy 51ce0537b80087a6225273040a987414b1dd081aa0Romain Guy const Matrix4& getTransform() const { 52ce0537b80087a6225273040a987414b1dd081aa0Romain Guy return mTransform; 53fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy } 547d139ba2c331f11e9b485753cc727a0ff202f2a4Romain Guy 55ce0537b80087a6225273040a987414b1dd081aa0Romain Guy void transform(const Matrix4& transform) { 56ce0537b80087a6225273040a987414b1dd081aa0Romain Guy Matrix4 t; 57121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy t.loadMultiply(transform, mTransform); 58121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy mTransform = t; 59121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy } 60121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy 61dda570201ac851dd85af3861f7e575721d3345daRomain Guyprivate: 62ce0537b80087a6225273040a987414b1dd081aa0Romain Guy Rect mBounds; 63121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy Matrix4 mTransform; 64121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy}; 65121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy 66121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guyclass RectangleList { 67ce0537b80087a6225273040a987414b1dd081aa0Romain Guypublic: 68121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy RectangleList(); 69121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy 70121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy bool isEmpty() const; 71121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy int getTransformedRectanglesCount() const; 72121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy const TransformedRectangle& getTransformedRectangle(int i) const; 73121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy 74121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy void setEmpty(); 75121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy void set(const Rect& bounds, const Matrix4& transform); 76ce0537b80087a6225273040a987414b1dd081aa0Romain Guy bool intersectWith(const Rect& bounds, const Matrix4& transform); 77ce0537b80087a6225273040a987414b1dd081aa0Romain Guy void transform(const Matrix4& transform); 78121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy 79121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy SkRegion convertToRegion(const SkRegion& clip) const; 80121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy Rect calculateBounds() const; 817d139ba2c331f11e9b485753cc727a0ff202f2a4Romain Guy 82121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy enum { 83121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy kMaxTransformedRectangles = 5 84121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy }; 857d139ba2c331f11e9b485753cc727a0ff202f2a4Romain Guy 86121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guyprivate: 87121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy int mTransformedRectanglesCount; 88121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy TransformedRectangle mTransformedRectangles[kMaxTransformedRectangles]; 897d139ba2c331f11e9b485753cc727a0ff202f2a4Romain Guy}; 90121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy 91ce0537b80087a6225273040a987414b1dd081aa0Romain Guyenum class ClipMode { 92121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy Rectangle, 93121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy RectangleList, 94121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy 95121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy // region and path - intersected. if either is empty, don't use 96121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy Region 97121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy}; 98fe8809471a40cac8acc984adfa51c39e13e83947Romain Guy 99ce0537b80087a6225273040a987414b1dd081aa0Romain Guystruct ClipBase { 1005b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy ClipBase(ClipMode mode) 1018c749f87d29e1a363ddf9027c3a51753c612d510Romain Guy : mode(mode) {} 1028c749f87d29e1a363ddf9027c3a51753c612d510Romain Guy ClipBase(const Rect& rect) 1038c749f87d29e1a363ddf9027c3a51753c612d510Romain Guy : mode(ClipMode::Rectangle) 104fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy , rect(rect) {} 105fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy const ClipMode mode; 1066c81893c626499e58c8eeb20d6c35ec4e1ce808bRomain Guy // Bounds of the clipping area, used to define the scissor, and define which 107121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy // portion of the stencil is updated/used 1087d139ba2c331f11e9b485753cc727a0ff202f2a4Romain Guy Rect rect; 1097d139ba2c331f11e9b485753cc727a0ff202f2a4Romain Guy}; 110163935113919a184122b8b3bd672ef08c8df65dcRomain Guy 1119aaa8269a3e7291aab84d01c3fc9c744d8f2d2f4Romain Guystruct ClipRect : ClipBase { 112a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65Romain Guy ClipRect(const Rect& rect) 113a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65Romain Guy : ClipBase(rect) {} 114a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65Romain Guy}; 115a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65Romain Guy 1169aaa8269a3e7291aab84d01c3fc9c744d8f2d2f4Romain Guystruct ClipRectList : ClipBase { 117ce0537b80087a6225273040a987414b1dd081aa0Romain Guy ClipRectList(const RectangleList& rectList) 118ce0537b80087a6225273040a987414b1dd081aa0Romain Guy : ClipBase(ClipMode::RectangleList) 119ce0537b80087a6225273040a987414b1dd081aa0Romain Guy , rectList(rectList) {} 120ce0537b80087a6225273040a987414b1dd081aa0Romain Guy RectangleList rectList; 121ce0537b80087a6225273040a987414b1dd081aa0Romain Guy}; 1225b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy 123struct ClipRegion : ClipBase { 124 ClipRegion(const SkRegion& region) 125 : ClipBase(ClipMode::Region) 126 , region(region) {} 127 ClipRegion() 128 : ClipBase(ClipMode::Region) {} 129 SkRegion region; 130}; 131 132class ClipArea { 133public: 134 ClipArea(); 135 136 void setViewportDimensions(int width, int height); 137 138 bool isEmpty() const { 139 return mClipRect.isEmpty(); 140 } 141 142 void setEmpty(); 143 void setClip(float left, float top, float right, float bottom); 144 void clipRectWithTransform(const Rect& r, const mat4* transform, 145 SkRegion::Op op); 146 void clipRegion(const SkRegion& region, SkRegion::Op op); 147 void clipPathWithTransform(const SkPath& path, const mat4* transform, 148 SkRegion::Op op); 149 150 const Rect& getClipRect() const { 151 return mClipRect; 152 } 153 154 const SkRegion& getClipRegion() const { 155 return mClipRegion; 156 } 157 158 const RectangleList& getRectangleList() const { 159 return mRectangleList; 160 } 161 162 bool isRegion() const { 163 return ClipMode::Region == mMode; 164 } 165 166 bool isSimple() const { 167 return mMode == ClipMode::Rectangle; 168 } 169 170 bool isRectangleList() const { 171 return mMode == ClipMode::RectangleList; 172 } 173 174 const ClipBase* serializeClip(LinearAllocator& allocator); 175 const ClipBase* serializeIntersectedClip(LinearAllocator& allocator, 176 const ClipBase* recordedClip, const Matrix4& recordedClipTransform); 177 void applyClip(const ClipBase* recordedClip, const Matrix4& recordedClipTransform); 178 179private: 180 void enterRectangleMode(); 181 void rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op); 182 183 void enterRectangleListMode(); 184 void rectangleListModeClipRectWithTransform(const Rect& r, 185 const mat4* transform, SkRegion::Op op); 186 187 void enterRegionModeFromRectangleMode(); 188 void enterRegionModeFromRectangleListMode(); 189 void enterRegionMode(); 190 void regionModeClipRectWithTransform(const Rect& r, const mat4* transform, 191 SkRegion::Op op); 192 193 void ensureClipRegion(); 194 void onClipRegionUpdated(); 195 196 // Called by every state modifying public method. 197 void onClipUpdated() { 198 mPostViewportClipObserved = true; 199 mLastSerialization = nullptr; 200 mLastResolutionResult = nullptr; 201 } 202 203 SkRegion createViewportRegion() { 204 return SkRegion(mViewportBounds.toSkIRect()); 205 } 206 207 void regionFromPath(const SkPath& path, SkRegion& pathAsRegion) { 208 // TODO: this should not mask every path to the viewport - this makes it impossible to use 209 // paths to clip to larger areas (which is valid e.g. with SkRegion::kReplace_Op) 210 pathAsRegion.setPath(path, createViewportRegion()); 211 } 212 213 ClipMode mMode; 214 bool mPostViewportClipObserved = false; 215 216 /** 217 * If mLastSerialization is non-null, it represents an already serialized copy 218 * of the current clip state. If null, it has not been computed. 219 */ 220 const ClipBase* mLastSerialization = nullptr; 221 222 /** 223 * This pair of pointers is a single entry cache of most recently seen 224 */ 225 const ClipBase* mLastResolutionResult = nullptr; 226 const ClipBase* mLastResolutionClip = nullptr; 227 Matrix4 mLastResolutionTransform; 228 229 Rect mViewportBounds; 230 Rect mClipRect; 231 SkRegion mClipRegion; 232 RectangleList mRectangleList; 233}; 234 235} /* namespace uirenderer */ 236} /* namespace android */ 237 238#endif /* CLIPAREA_H_ */ 239