Home | History | Annotate | Download | only in hwui
      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 
     42     const Rect& getBounds() const {
     43         return mBounds;
     44     }
     45 
     46     Rect transformedBounds() const {
     47         Rect transformedBounds(transformAndCalculateBounds(mBounds, mTransform));
     48         return transformedBounds;
     49     }
     50 
     51     const Matrix4& getTransform() const {
     52         return mTransform;
     53     }
     54 
     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 {
    100     explicit ClipBase(ClipMode mode)
    101             : mode(mode) {}
    102     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 {
    115     explicit ClipRect(const Rect& rect)
    116             : ClipBase(rect) {}
    117 };
    118 
    119 struct ClipRectList : ClipBase {
    120     explicit ClipRectList(const RectangleList& rectList)
    121             : ClipBase(ClipMode::RectangleList)
    122             , rectList(rectList) {}
    123     RectangleList rectList;
    124 };
    125 
    126 struct ClipRegion : ClipBase {
    127     explicit ClipRegion(const SkRegion& region)
    128             : ClipBase(ClipMode::Region)
    129             , region(region) {}
    130     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 
    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 
    152     const Rect& getClipRect() const {
    153         return mClipRect;
    154     }
    155 
    156     const SkRegion& getClipRegion() const {
    157         return mClipRegion;
    158     }
    159 
    160     const RectangleList& getRectangleList() const {
    161         return mRectangleList;
    162     }
    163 
    164     bool isRegion() const {
    165         return ClipMode::Region == mMode;
    166     }
    167 
    168     bool isSimple() const {
    169         return mMode == ClipMode::Rectangle;
    170     }
    171 
    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.
    202     void onClipUpdated() {
    203         mPostViewportClipObserved = true;
    204         mLastSerialization = nullptr;
    205         mLastResolutionResult = nullptr;
    206     }
    207 
    208     SkRegion createViewportRegion() {
    209         return SkRegion(mViewportBounds.toSkIRect());
    210     }
    211 
    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