ClipArea.cpp revision 4f4c60820995bad73d87c2fff4b5c5b1c6b5e027
1487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk/*
2487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk * Copyright (C) 2015 The Android Open Source Project
3487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk *
4487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk * Licensed under the Apache License, Version 2.0 (the "License");
5487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk * you may not use this file except in compliance with the License.
6487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk * You may obtain a copy of the License at
7487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk *
8487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk *      http://www.apache.org/licenses/LICENSE-2.0
9487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk *
10487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk * Unless required by applicable law or agreed to in writing, software
11487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk * distributed under the License is distributed on an "AS IS" BASIS,
12487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk * See the License for the specific language governing permissions and
14487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk * limitations under the License.
15487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk */
16487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk#include "ClipArea.h"
17487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
18e4db79de127cfe961195f52907af8451026eaa20Chris Craik#include "utils/LinearAllocator.h"
19e4db79de127cfe961195f52907af8451026eaa20Chris Craik
20487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk#include <SkPath.h>
21487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk#include <limits>
22e4db79de127cfe961195f52907af8451026eaa20Chris Craik#include <type_traits>
23487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
24487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuknamespace android {
25487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuknamespace uirenderer {
26487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
27487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukstatic void handlePoint(Rect& transformedBounds, const Matrix4& transform, float x, float y) {
284d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik    Vertex v = {x, y};
29487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    transform.mapPoint(v.x, v.y);
3015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    transformedBounds.expandToCover(v.x, v.y);
31487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
32487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
33487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob TsukRect transformAndCalculateBounds(const Rect& r, const Matrix4& transform) {
34487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    const float kMinFloat = std::numeric_limits<float>::lowest();
35487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    const float kMaxFloat = std::numeric_limits<float>::max();
36487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    Rect transformedBounds = { kMaxFloat, kMaxFloat, kMinFloat, kMinFloat };
37487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    handlePoint(transformedBounds, transform, r.left, r.top);
38487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    handlePoint(transformedBounds, transform, r.right, r.top);
39487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    handlePoint(transformedBounds, transform, r.left, r.bottom);
40487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    handlePoint(transformedBounds, transform, r.right, r.bottom);
41487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    return transformedBounds;
42487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
43487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
44487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk/*
45487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk * TransformedRectangle
46487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk */
47487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
48487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob TsukTransformedRectangle::TransformedRectangle() {
49487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
50487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
51487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob TsukTransformedRectangle::TransformedRectangle(const Rect& bounds,
52487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        const Matrix4& transform)
53487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        : mBounds(bounds)
54487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        , mTransform(transform) {
55487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
56487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
57487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukbool TransformedRectangle::canSimplyIntersectWith(
58487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        const TransformedRectangle& other) const {
59487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
60487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    return mTransform == other.mTransform;
61487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
62487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
63ac02eb9035a13a3d09c2def9ed63d04225eb2509Chris Craikvoid TransformedRectangle::intersectWith(const TransformedRectangle& other) {
64ac02eb9035a13a3d09c2def9ed63d04225eb2509Chris Craik    mBounds.doIntersect(other.mBounds);
65487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
66487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
67487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukbool TransformedRectangle::isEmpty() const {
68487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    return mBounds.isEmpty();
69487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
70487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
71487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk/*
72487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk * RectangleList
73487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk */
74487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
75487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob TsukRectangleList::RectangleList()
76487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        : mTransformedRectanglesCount(0) {
77487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
78487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
79487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukbool RectangleList::isEmpty() const {
80487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    if (mTransformedRectanglesCount < 1) {
81487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        return true;
82487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
83487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
84487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    for (int i = 0; i < mTransformedRectanglesCount; i++) {
85487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        if (mTransformedRectangles[i].isEmpty()) {
86487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            return true;
87487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        }
88487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
89487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    return false;
90487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
91487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
92487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukint RectangleList::getTransformedRectanglesCount() const {
93487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    return mTransformedRectanglesCount;
94487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
95487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
96487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukconst TransformedRectangle& RectangleList::getTransformedRectangle(int i) const {
97487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    return mTransformedRectangles[i];
98487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
99487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
100487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukvoid RectangleList::setEmpty() {
101487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mTransformedRectanglesCount = 0;
102487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
103487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
104487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukvoid RectangleList::set(const Rect& bounds, const Matrix4& transform) {
105487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mTransformedRectanglesCount = 1;
106487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mTransformedRectangles[0] = TransformedRectangle(bounds, transform);
107487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
108487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
109487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukbool RectangleList::intersectWith(const Rect& bounds,
110487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        const Matrix4& transform) {
111487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    TransformedRectangle newRectangle(bounds, transform);
112487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
113487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    // Try to find a rectangle with a compatible transformation
114487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    int index = 0;
115487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    for (; index < mTransformedRectanglesCount; index++) {
116487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        TransformedRectangle& tr(mTransformedRectangles[index]);
117487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        if (tr.canSimplyIntersectWith(newRectangle)) {
118487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            tr.intersectWith(newRectangle);
119487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            return true;
120487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        }
121487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
122487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
123487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    // Add it to the list if there is room
124487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    if (index < kMaxTransformedRectangles) {
125487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        mTransformedRectangles[index] = newRectangle;
126487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        mTransformedRectanglesCount += 1;
127487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        return true;
128487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
129487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
130487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    // This rectangle list is full
131487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    return false;
132487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
133487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
134487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob TsukRect RectangleList::calculateBounds() const {
135487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    Rect bounds;
136487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    for (int index = 0; index < mTransformedRectanglesCount; index++) {
137487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        const TransformedRectangle& tr(mTransformedRectangles[index]);
138487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        if (index == 0) {
139487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            bounds = tr.transformedBounds();
140487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        } else {
141ac02eb9035a13a3d09c2def9ed63d04225eb2509Chris Craik            bounds.doIntersect(tr.transformedBounds());
142487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        }
143487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
144487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    return bounds;
145487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
146487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
147487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukstatic SkPath pathFromTransformedRectangle(const Rect& bounds,
148487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        const Matrix4& transform) {
149487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    SkPath rectPath;
150487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    SkPath rectPathTransformed;
151487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    rectPath.addRect(bounds.left, bounds.top, bounds.right, bounds.bottom);
152487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    SkMatrix skTransform;
153487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    transform.copyTo(skTransform);
154487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    rectPath.transform(skTransform, &rectPathTransformed);
155487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    return rectPathTransformed;
156487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
157487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
158487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob TsukSkRegion RectangleList::convertToRegion(const SkRegion& clip) const {
159487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    SkRegion rectangleListAsRegion;
160487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    for (int index = 0; index < mTransformedRectanglesCount; index++) {
161487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        const TransformedRectangle& tr(mTransformedRectangles[index]);
162487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        SkPath rectPathTransformed = pathFromTransformedRectangle(
163487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk                tr.getBounds(), tr.getTransform());
164487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        if (index == 0) {
165487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            rectangleListAsRegion.setPath(rectPathTransformed, clip);
166487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        } else {
167487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            SkRegion rectRegion;
168487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            rectRegion.setPath(rectPathTransformed, clip);
169487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            rectangleListAsRegion.op(rectRegion, SkRegion::kIntersect_Op);
170487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        }
171487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
172487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    return rectangleListAsRegion;
173487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
174487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
175e4db79de127cfe961195f52907af8451026eaa20Chris Craikvoid RectangleList::transform(const Matrix4& transform) {
176e4db79de127cfe961195f52907af8451026eaa20Chris Craik    for (int index = 0; index < mTransformedRectanglesCount; index++) {
177e4db79de127cfe961195f52907af8451026eaa20Chris Craik        mTransformedRectangles[index].transform(transform);
178e4db79de127cfe961195f52907af8451026eaa20Chris Craik    }
179e4db79de127cfe961195f52907af8451026eaa20Chris Craik}
180e4db79de127cfe961195f52907af8451026eaa20Chris Craik
181487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk/*
182487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk * ClipArea
183487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk */
184487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
185487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob TsukClipArea::ClipArea()
186e4db79de127cfe961195f52907af8451026eaa20Chris Craik        : mMode(ClipMode::Rectangle) {
187487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
188487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
189487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk/*
190487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk * Interface
191487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk */
192487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
193487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukvoid ClipArea::setViewportDimensions(int width, int height) {
194e4db79de127cfe961195f52907af8451026eaa20Chris Craik    mPostViewportClipObserved = false;
195487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mViewportBounds.set(0, 0, width, height);
196487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mClipRect = mViewportBounds;
197487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
198487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
199487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukvoid ClipArea::setEmpty() {
200e4db79de127cfe961195f52907af8451026eaa20Chris Craik    onClipUpdated();
201e4db79de127cfe961195f52907af8451026eaa20Chris Craik    mMode = ClipMode::Rectangle;
202487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mClipRect.setEmpty();
203487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mClipRegion.setEmpty();
204487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mRectangleList.setEmpty();
205487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
206487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
207487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukvoid ClipArea::setClip(float left, float top, float right, float bottom) {
208e4db79de127cfe961195f52907af8451026eaa20Chris Craik    onClipUpdated();
209e4db79de127cfe961195f52907af8451026eaa20Chris Craik    mMode = ClipMode::Rectangle;
210487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mClipRect.set(left, top, right, bottom);
211487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mClipRegion.setEmpty();
212487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
213487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
2144d3e704b04c6abd7995df640d12662b0271f6c7bChris Craikvoid ClipArea::clipRectWithTransform(const Rect& r, const mat4* transform,
215487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        SkRegion::Op op) {
2167fc1b0349bc2ac8c880120dc5611f703faa7f06fChris Craik    if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op;
217e4db79de127cfe961195f52907af8451026eaa20Chris Craik    onClipUpdated();
218487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    switch (mMode) {
219e4db79de127cfe961195f52907af8451026eaa20Chris Craik    case ClipMode::Rectangle:
2204d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        rectangleModeClipRectWithTransform(r, transform, op);
2214d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        break;
222e4db79de127cfe961195f52907af8451026eaa20Chris Craik    case ClipMode::RectangleList:
2234d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        rectangleListModeClipRectWithTransform(r, transform, op);
2244d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        break;
225e4db79de127cfe961195f52907af8451026eaa20Chris Craik    case ClipMode::Region:
2264d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        regionModeClipRectWithTransform(r, transform, op);
2274d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        break;
228487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
229487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
230487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
2314d3e704b04c6abd7995df640d12662b0271f6c7bChris Craikvoid ClipArea::clipRegion(const SkRegion& region, SkRegion::Op op) {
2327fc1b0349bc2ac8c880120dc5611f703faa7f06fChris Craik    if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op;
233e4db79de127cfe961195f52907af8451026eaa20Chris Craik    onClipUpdated();
234487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    enterRegionMode();
235487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mClipRegion.op(region, op);
236e30b53cec5eb6eaa5d24231feb3207b917c1baabTom Hudson    onClipRegionUpdated();
237487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
238487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
2394d3e704b04c6abd7995df640d12662b0271f6c7bChris Craikvoid ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform,
240487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        SkRegion::Op op) {
2417fc1b0349bc2ac8c880120dc5611f703faa7f06fChris Craik    if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op;
242e4db79de127cfe961195f52907af8451026eaa20Chris Craik    onClipUpdated();
243487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    SkMatrix skTransform;
244487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    transform->copyTo(skTransform);
245487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    SkPath transformed;
246487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    path.transform(skTransform, &transformed);
247487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    SkRegion region;
248487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    regionFromPath(transformed, region);
2494d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik    clipRegion(region, op);
250487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
251487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
252487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk/*
253487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk * Rectangle mode
254487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk */
255487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
256487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukvoid ClipArea::enterRectangleMode() {
257487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    // Entering rectangle mode discards any
258487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    // existing clipping information from the other modes.
259487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    // The only way this occurs is by a clip setting operation.
260e4db79de127cfe961195f52907af8451026eaa20Chris Craik    mMode = ClipMode::Rectangle;
261487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
262487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
2634d3e704b04c6abd7995df640d12662b0271f6c7bChris Craikvoid ClipArea::rectangleModeClipRectWithTransform(const Rect& r,
264487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        const mat4* transform, SkRegion::Op op) {
265487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
2668ce8f3f4d68a7750bc02b5254ebbd8658281e675Chris Craik    if (op == SkRegion::kReplace_Op && transform->rectToRect()) {
2678ce8f3f4d68a7750bc02b5254ebbd8658281e675Chris Craik        mClipRect = r;
2688ce8f3f4d68a7750bc02b5254ebbd8658281e675Chris Craik        transform->mapRect(mClipRect);
2694d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        return;
2708ce8f3f4d68a7750bc02b5254ebbd8658281e675Chris Craik    } else if (op != SkRegion::kIntersect_Op) {
271487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        enterRegionMode();
2724d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        regionModeClipRectWithTransform(r, transform, op);
2734d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        return;
274487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
275487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
276487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    if (transform->rectToRect()) {
277487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        Rect transformed(r);
278487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        transform->mapRect(transformed);
279ac02eb9035a13a3d09c2def9ed63d04225eb2509Chris Craik        mClipRect.doIntersect(transformed);
2804d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        return;
281487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
282487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
283487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    enterRectangleListMode();
2844d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik    rectangleListModeClipRectWithTransform(r, transform, op);
285487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
286487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
287487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk/*
288487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk * RectangleList mode implementation
289487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk */
290487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
291487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukvoid ClipArea::enterRectangleListMode() {
292487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    // Is is only legal to enter rectangle list mode from
293487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    // rectangle mode, since rectangle list mode cannot represent
294487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    // all clip areas that can be represented by a region.
295e4db79de127cfe961195f52907af8451026eaa20Chris Craik    ALOG_ASSERT(mMode == ClipMode::Rectangle);
296e4db79de127cfe961195f52907af8451026eaa20Chris Craik    mMode = ClipMode::RectangleList;
297487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mRectangleList.set(mClipRect, Matrix4::identity());
298487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
299487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
3004d3e704b04c6abd7995df640d12662b0271f6c7bChris Craikvoid ClipArea::rectangleListModeClipRectWithTransform(const Rect& r,
301487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        const mat4* transform, SkRegion::Op op) {
302487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    if (op != SkRegion::kIntersect_Op
303487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            || !mRectangleList.intersectWith(r, *transform)) {
304487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        enterRegionMode();
3054d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        regionModeClipRectWithTransform(r, transform, op);
306487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
307487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
308487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
309487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk/*
310487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk * Region mode implementation
311487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk */
312487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
313487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukvoid ClipArea::enterRegionMode() {
314e4db79de127cfe961195f52907af8451026eaa20Chris Craik    ClipMode oldMode = mMode;
315e4db79de127cfe961195f52907af8451026eaa20Chris Craik    mMode = ClipMode::Region;
316e4db79de127cfe961195f52907af8451026eaa20Chris Craik    if (oldMode != ClipMode::Region) {
317e4db79de127cfe961195f52907af8451026eaa20Chris Craik        if (oldMode == ClipMode::Rectangle) {
318e4db79de127cfe961195f52907af8451026eaa20Chris Craik            mClipRegion.setRect(mClipRect.toSkIRect());
319487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        } else {
320487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            mClipRegion = mRectangleList.convertToRegion(createViewportRegion());
321e30b53cec5eb6eaa5d24231feb3207b917c1baabTom Hudson            onClipRegionUpdated();
322487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        }
323487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
324487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
325487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
3264d3e704b04c6abd7995df640d12662b0271f6c7bChris Craikvoid ClipArea::regionModeClipRectWithTransform(const Rect& r,
327487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        const mat4* transform, SkRegion::Op op) {
328487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    SkPath transformedRect = pathFromTransformedRectangle(r, *transform);
329487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    SkRegion transformedRectRegion;
330487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    regionFromPath(transformedRect, transformedRectRegion);
331487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mClipRegion.op(transformedRectRegion, op);
332e30b53cec5eb6eaa5d24231feb3207b917c1baabTom Hudson    onClipRegionUpdated();
333487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
334487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
335e30b53cec5eb6eaa5d24231feb3207b917c1baabTom Hudsonvoid ClipArea::onClipRegionUpdated() {
336487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    if (!mClipRegion.isEmpty()) {
337487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        mClipRect.set(mClipRegion.getBounds());
338487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
339487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        if (mClipRegion.isRect()) {
340487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            mClipRegion.setEmpty();
341e30b53cec5eb6eaa5d24231feb3207b917c1baabTom Hudson            enterRectangleMode();
342487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        }
343487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    } else {
344487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        mClipRect.setEmpty();
345487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
346487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
347487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
348e4db79de127cfe961195f52907af8451026eaa20Chris Craik/**
349e4db79de127cfe961195f52907af8451026eaa20Chris Craik * Clip serialization
350e4db79de127cfe961195f52907af8451026eaa20Chris Craik */
351e4db79de127cfe961195f52907af8451026eaa20Chris Craik
352e4db79de127cfe961195f52907af8451026eaa20Chris Craikconst ClipBase* ClipArea::serializeClip(LinearAllocator& allocator) {
353e4db79de127cfe961195f52907af8451026eaa20Chris Craik    if (!mPostViewportClipObserved) {
354e4db79de127cfe961195f52907af8451026eaa20Chris Craik        // Only initial clip-to-viewport observed, so no serialization of clip necessary
355e4db79de127cfe961195f52907af8451026eaa20Chris Craik        return nullptr;
356e4db79de127cfe961195f52907af8451026eaa20Chris Craik    }
357e4db79de127cfe961195f52907af8451026eaa20Chris Craik
358e4db79de127cfe961195f52907af8451026eaa20Chris Craik    static_assert(std::is_trivially_destructible<Rect>::value,
359e4db79de127cfe961195f52907af8451026eaa20Chris Craik            "expect Rect to be trivially destructible");
360e4db79de127cfe961195f52907af8451026eaa20Chris Craik    static_assert(std::is_trivially_destructible<RectangleList>::value,
361e4db79de127cfe961195f52907af8451026eaa20Chris Craik            "expect RectangleList to be trivially destructible");
362e4db79de127cfe961195f52907af8451026eaa20Chris Craik
363e4db79de127cfe961195f52907af8451026eaa20Chris Craik    if (mLastSerialization == nullptr) {
3644f4c60820995bad73d87c2fff4b5c5b1c6b5e027Chris Craik        ClipBase* serialization = nullptr;
365e4db79de127cfe961195f52907af8451026eaa20Chris Craik        switch (mMode) {
366e4db79de127cfe961195f52907af8451026eaa20Chris Craik        case ClipMode::Rectangle:
367b4f4f3e16d8fbb2905dfc168383213161e988f83Chris Craik            serialization = allocator.create<ClipRect>(mClipRect);
368e4db79de127cfe961195f52907af8451026eaa20Chris Craik            break;
369e4db79de127cfe961195f52907af8451026eaa20Chris Craik        case ClipMode::RectangleList:
370b4f4f3e16d8fbb2905dfc168383213161e988f83Chris Craik            serialization = allocator.create<ClipRectList>(mRectangleList);
371b4f4f3e16d8fbb2905dfc168383213161e988f83Chris Craik            serialization->rect = mRectangleList.calculateBounds();
372e4db79de127cfe961195f52907af8451026eaa20Chris Craik            break;
373e4db79de127cfe961195f52907af8451026eaa20Chris Craik        case ClipMode::Region:
374b4f4f3e16d8fbb2905dfc168383213161e988f83Chris Craik            serialization = allocator.create<ClipRegion>(mClipRegion);
375b4f4f3e16d8fbb2905dfc168383213161e988f83Chris Craik            serialization->rect.set(mClipRegion.getBounds());
376e4db79de127cfe961195f52907af8451026eaa20Chris Craik            break;
377e4db79de127cfe961195f52907af8451026eaa20Chris Craik        }
378b4f4f3e16d8fbb2905dfc168383213161e988f83Chris Craik        mLastSerialization = serialization;
379e4db79de127cfe961195f52907af8451026eaa20Chris Craik    }
380e4db79de127cfe961195f52907af8451026eaa20Chris Craik    return mLastSerialization;
381e4db79de127cfe961195f52907af8451026eaa20Chris Craik}
382e4db79de127cfe961195f52907af8451026eaa20Chris Craik
383e4db79de127cfe961195f52907af8451026eaa20Chris Craikinline static const Rect& getRect(const ClipBase* scb) {
384e4db79de127cfe961195f52907af8451026eaa20Chris Craik    return reinterpret_cast<const ClipRect*>(scb)->rect;
385e4db79de127cfe961195f52907af8451026eaa20Chris Craik}
386e4db79de127cfe961195f52907af8451026eaa20Chris Craik
387e4db79de127cfe961195f52907af8451026eaa20Chris Craikinline static const RectangleList& getRectList(const ClipBase* scb) {
388e4db79de127cfe961195f52907af8451026eaa20Chris Craik    return reinterpret_cast<const ClipRectList*>(scb)->rectList;
389e4db79de127cfe961195f52907af8451026eaa20Chris Craik}
390e4db79de127cfe961195f52907af8451026eaa20Chris Craik
391e4db79de127cfe961195f52907af8451026eaa20Chris Craikinline static const SkRegion& getRegion(const ClipBase* scb) {
392e4db79de127cfe961195f52907af8451026eaa20Chris Craik    return reinterpret_cast<const ClipRegion*>(scb)->region;
393e4db79de127cfe961195f52907af8451026eaa20Chris Craik}
394e4db79de127cfe961195f52907af8451026eaa20Chris Craik
395e4db79de127cfe961195f52907af8451026eaa20Chris Craik// Conservative check for too many rectangles to fit in rectangle list.
396e4db79de127cfe961195f52907af8451026eaa20Chris Craik// For simplicity, doesn't account for rect merging
397e4db79de127cfe961195f52907af8451026eaa20Chris Craikstatic bool cannotFitInRectangleList(const ClipArea& clipArea, const ClipBase* scb) {
398e4db79de127cfe961195f52907af8451026eaa20Chris Craik    int currentRectCount = clipArea.isRectangleList()
399e4db79de127cfe961195f52907af8451026eaa20Chris Craik            ? clipArea.getRectangleList().getTransformedRectanglesCount()
400e4db79de127cfe961195f52907af8451026eaa20Chris Craik            : 1;
401e4db79de127cfe961195f52907af8451026eaa20Chris Craik    int recordedRectCount = (scb->mode == ClipMode::RectangleList)
402e4db79de127cfe961195f52907af8451026eaa20Chris Craik            ? getRectList(scb).getTransformedRectanglesCount()
403e4db79de127cfe961195f52907af8451026eaa20Chris Craik            : 1;
404e4db79de127cfe961195f52907af8451026eaa20Chris Craik    return currentRectCount + recordedRectCount > RectangleList::kMaxTransformedRectangles;
405e4db79de127cfe961195f52907af8451026eaa20Chris Craik}
406e4db79de127cfe961195f52907af8451026eaa20Chris Craik
407e4db79de127cfe961195f52907af8451026eaa20Chris Craikconst ClipBase* ClipArea::serializeIntersectedClip(LinearAllocator& allocator,
408e4db79de127cfe961195f52907af8451026eaa20Chris Craik        const ClipBase* recordedClip, const Matrix4& recordedClipTransform) {
409e4db79de127cfe961195f52907af8451026eaa20Chris Craik    // if no recordedClip passed, just serialize current state
410e4db79de127cfe961195f52907af8451026eaa20Chris Craik    if (!recordedClip) return serializeClip(allocator);
411e4db79de127cfe961195f52907af8451026eaa20Chris Craik
412e4db79de127cfe961195f52907af8451026eaa20Chris Craik    if (!mLastResolutionResult
413e4db79de127cfe961195f52907af8451026eaa20Chris Craik            || recordedClip != mLastResolutionClip
414e4db79de127cfe961195f52907af8451026eaa20Chris Craik            || recordedClipTransform != mLastResolutionTransform) {
415e4db79de127cfe961195f52907af8451026eaa20Chris Craik        mLastResolutionClip = recordedClip;
416e4db79de127cfe961195f52907af8451026eaa20Chris Craik        mLastResolutionTransform = recordedClipTransform;
417e4db79de127cfe961195f52907af8451026eaa20Chris Craik
418e4db79de127cfe961195f52907af8451026eaa20Chris Craik        if (CC_LIKELY(mMode == ClipMode::Rectangle
419e4db79de127cfe961195f52907af8451026eaa20Chris Craik                && recordedClip->mode == ClipMode::Rectangle
420e4db79de127cfe961195f52907af8451026eaa20Chris Craik                && recordedClipTransform.rectToRect())) {
421e4db79de127cfe961195f52907af8451026eaa20Chris Craik            // common case - result is a single rectangle
422e4db79de127cfe961195f52907af8451026eaa20Chris Craik            auto rectClip = allocator.create<ClipRect>(getRect(recordedClip));
423e4db79de127cfe961195f52907af8451026eaa20Chris Craik            recordedClipTransform.mapRect(rectClip->rect);
424e4db79de127cfe961195f52907af8451026eaa20Chris Craik            rectClip->rect.doIntersect(mClipRect);
425e4db79de127cfe961195f52907af8451026eaa20Chris Craik            mLastResolutionResult = rectClip;
426e4db79de127cfe961195f52907af8451026eaa20Chris Craik        } else if (CC_UNLIKELY(mMode == ClipMode::Region
427e4db79de127cfe961195f52907af8451026eaa20Chris Craik                || recordedClip->mode == ClipMode::Region
428e4db79de127cfe961195f52907af8451026eaa20Chris Craik                || cannotFitInRectangleList(*this, recordedClip))) {
429e4db79de127cfe961195f52907af8451026eaa20Chris Craik            // region case
430e4db79de127cfe961195f52907af8451026eaa20Chris Craik            SkRegion other;
431e4db79de127cfe961195f52907af8451026eaa20Chris Craik            switch (recordedClip->mode) {
432e4db79de127cfe961195f52907af8451026eaa20Chris Craik            case ClipMode::Rectangle:
433e4db79de127cfe961195f52907af8451026eaa20Chris Craik                if (CC_LIKELY(recordedClipTransform.rectToRect())) {
434e4db79de127cfe961195f52907af8451026eaa20Chris Craik                    // simple transform, skip creating SkPath
435e4db79de127cfe961195f52907af8451026eaa20Chris Craik                    Rect resultClip(getRect(recordedClip));
436e4db79de127cfe961195f52907af8451026eaa20Chris Craik                    recordedClipTransform.mapRect(resultClip);
437e4db79de127cfe961195f52907af8451026eaa20Chris Craik                    other.setRect(resultClip.toSkIRect());
438e4db79de127cfe961195f52907af8451026eaa20Chris Craik                } else {
439e4db79de127cfe961195f52907af8451026eaa20Chris Craik                    SkPath transformedRect = pathFromTransformedRectangle(getRect(recordedClip),
440e4db79de127cfe961195f52907af8451026eaa20Chris Craik                            recordedClipTransform);
441e4db79de127cfe961195f52907af8451026eaa20Chris Craik                    other.setPath(transformedRect, createViewportRegion());
442e4db79de127cfe961195f52907af8451026eaa20Chris Craik                }
443e4db79de127cfe961195f52907af8451026eaa20Chris Craik                break;
444e4db79de127cfe961195f52907af8451026eaa20Chris Craik            case ClipMode::RectangleList: {
445e4db79de127cfe961195f52907af8451026eaa20Chris Craik                RectangleList transformedList(getRectList(recordedClip));
446e4db79de127cfe961195f52907af8451026eaa20Chris Craik                transformedList.transform(recordedClipTransform);
447e4db79de127cfe961195f52907af8451026eaa20Chris Craik                other = transformedList.convertToRegion(createViewportRegion());
448e4db79de127cfe961195f52907af8451026eaa20Chris Craik                break;
449e4db79de127cfe961195f52907af8451026eaa20Chris Craik            }
450e4db79de127cfe961195f52907af8451026eaa20Chris Craik            case ClipMode::Region:
451e4db79de127cfe961195f52907af8451026eaa20Chris Craik                other = getRegion(recordedClip);
452e4db79de127cfe961195f52907af8451026eaa20Chris Craik
453e4db79de127cfe961195f52907af8451026eaa20Chris Craik                // TODO: handle non-translate transforms properly!
454e4db79de127cfe961195f52907af8451026eaa20Chris Craik                other.translate(recordedClipTransform.getTranslateX(),
455e4db79de127cfe961195f52907af8451026eaa20Chris Craik                        recordedClipTransform.getTranslateY());
456e4db79de127cfe961195f52907af8451026eaa20Chris Craik            }
457e4db79de127cfe961195f52907af8451026eaa20Chris Craik
458e4db79de127cfe961195f52907af8451026eaa20Chris Craik            ClipRegion* regionClip = allocator.create<ClipRegion>();
459e4db79de127cfe961195f52907af8451026eaa20Chris Craik            switch (mMode) {
460e4db79de127cfe961195f52907af8451026eaa20Chris Craik            case ClipMode::Rectangle:
461e4db79de127cfe961195f52907af8451026eaa20Chris Craik                regionClip->region.op(mClipRect.toSkIRect(), other, SkRegion::kIntersect_Op);
462e4db79de127cfe961195f52907af8451026eaa20Chris Craik                break;
463e4db79de127cfe961195f52907af8451026eaa20Chris Craik            case ClipMode::RectangleList:
464e4db79de127cfe961195f52907af8451026eaa20Chris Craik                regionClip->region.op(mRectangleList.convertToRegion(createViewportRegion()),
465e4db79de127cfe961195f52907af8451026eaa20Chris Craik                        other, SkRegion::kIntersect_Op);
466e4db79de127cfe961195f52907af8451026eaa20Chris Craik                break;
467e4db79de127cfe961195f52907af8451026eaa20Chris Craik            case ClipMode::Region:
468e4db79de127cfe961195f52907af8451026eaa20Chris Craik                regionClip->region.op(mClipRegion, other, SkRegion::kIntersect_Op);
469e4db79de127cfe961195f52907af8451026eaa20Chris Craik                break;
470e4db79de127cfe961195f52907af8451026eaa20Chris Craik            }
471e4db79de127cfe961195f52907af8451026eaa20Chris Craik            regionClip->rect.set(regionClip->region.getBounds());
472e4db79de127cfe961195f52907af8451026eaa20Chris Craik            mLastResolutionResult = regionClip;
473e4db79de127cfe961195f52907af8451026eaa20Chris Craik        } else {
474e4db79de127cfe961195f52907af8451026eaa20Chris Craik            auto rectListClip = allocator.create<ClipRectList>(mRectangleList);
475e4db79de127cfe961195f52907af8451026eaa20Chris Craik            auto&& rectList = rectListClip->rectList;
476e4db79de127cfe961195f52907af8451026eaa20Chris Craik            if (mMode == ClipMode::Rectangle) {
477e4db79de127cfe961195f52907af8451026eaa20Chris Craik                rectList.set(mClipRect, Matrix4::identity());
478e4db79de127cfe961195f52907af8451026eaa20Chris Craik            }
479e4db79de127cfe961195f52907af8451026eaa20Chris Craik
480e4db79de127cfe961195f52907af8451026eaa20Chris Craik            if (recordedClip->mode == ClipMode::Rectangle) {
481e4db79de127cfe961195f52907af8451026eaa20Chris Craik                rectList.intersectWith(getRect(recordedClip), recordedClipTransform);
482e4db79de127cfe961195f52907af8451026eaa20Chris Craik            } else {
483e4db79de127cfe961195f52907af8451026eaa20Chris Craik                const RectangleList& other = getRectList(recordedClip);
484e4db79de127cfe961195f52907af8451026eaa20Chris Craik                for (int i = 0; i < other.getTransformedRectanglesCount(); i++) {
485e4db79de127cfe961195f52907af8451026eaa20Chris Craik                    auto&& tr = other.getTransformedRectangle(i);
486e4db79de127cfe961195f52907af8451026eaa20Chris Craik                    Matrix4 totalTransform(recordedClipTransform);
487e4db79de127cfe961195f52907af8451026eaa20Chris Craik                    totalTransform.multiply(tr.getTransform());
488e4db79de127cfe961195f52907af8451026eaa20Chris Craik                    rectList.intersectWith(tr.getBounds(), totalTransform);
489e4db79de127cfe961195f52907af8451026eaa20Chris Craik                }
490e4db79de127cfe961195f52907af8451026eaa20Chris Craik            }
491e4db79de127cfe961195f52907af8451026eaa20Chris Craik            rectListClip->rect = rectList.calculateBounds();
492e4db79de127cfe961195f52907af8451026eaa20Chris Craik            mLastResolutionResult = rectListClip;
493e4db79de127cfe961195f52907af8451026eaa20Chris Craik        }
494e4db79de127cfe961195f52907af8451026eaa20Chris Craik    }
495e4db79de127cfe961195f52907af8451026eaa20Chris Craik    return mLastResolutionResult;
496e4db79de127cfe961195f52907af8451026eaa20Chris Craik}
497e4db79de127cfe961195f52907af8451026eaa20Chris Craik
498e4db79de127cfe961195f52907af8451026eaa20Chris Craikvoid ClipArea::applyClip(const ClipBase* clip, const Matrix4& transform) {
499e4db79de127cfe961195f52907af8451026eaa20Chris Craik    if (!clip) return; // nothing to do
500e4db79de127cfe961195f52907af8451026eaa20Chris Craik
501e4db79de127cfe961195f52907af8451026eaa20Chris Craik    if (CC_LIKELY(clip->mode == ClipMode::Rectangle)) {
502e4db79de127cfe961195f52907af8451026eaa20Chris Craik        clipRectWithTransform(getRect(clip), &transform, SkRegion::kIntersect_Op);
503e4db79de127cfe961195f52907af8451026eaa20Chris Craik    } else if (CC_LIKELY(clip->mode == ClipMode::RectangleList)) {
504e4db79de127cfe961195f52907af8451026eaa20Chris Craik        auto&& rectList = getRectList(clip);
505e4db79de127cfe961195f52907af8451026eaa20Chris Craik        for (int i = 0; i < rectList.getTransformedRectanglesCount(); i++) {
506e4db79de127cfe961195f52907af8451026eaa20Chris Craik            auto&& tr = rectList.getTransformedRectangle(i);
507e4db79de127cfe961195f52907af8451026eaa20Chris Craik            Matrix4 totalTransform(transform);
508e4db79de127cfe961195f52907af8451026eaa20Chris Craik            totalTransform.multiply(tr.getTransform());
509e4db79de127cfe961195f52907af8451026eaa20Chris Craik            clipRectWithTransform(tr.getBounds(), &totalTransform, SkRegion::kIntersect_Op);
510e4db79de127cfe961195f52907af8451026eaa20Chris Craik        }
511e4db79de127cfe961195f52907af8451026eaa20Chris Craik    } else {
512e4db79de127cfe961195f52907af8451026eaa20Chris Craik        SkRegion region(getRegion(clip));
513e4db79de127cfe961195f52907af8451026eaa20Chris Craik        // TODO: handle non-translate transforms properly!
514e4db79de127cfe961195f52907af8451026eaa20Chris Craik        region.translate(transform.getTranslateX(), transform.getTranslateY());
515e4db79de127cfe961195f52907af8451026eaa20Chris Craik        clipRegion(region, SkRegion::kIntersect_Op);
516e4db79de127cfe961195f52907af8451026eaa20Chris Craik    }
517e4db79de127cfe961195f52907af8451026eaa20Chris Craik}
518e4db79de127cfe961195f52907af8451026eaa20Chris Craik
519487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk} /* namespace uirenderer */
520487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk} /* namespace android */
521