ClipArea.cpp revision 02806288d1c56475413888a934c796e6e4eb11c5
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
4402806288d1c56475413888a934c796e6e4eb11c5Chris Craikvoid ClipBase::dump() const {
4502806288d1c56475413888a934c796e6e4eb11c5Chris Craik    ALOGD("mode %d" RECT_STRING, mode, RECT_ARGS(rect));
4602806288d1c56475413888a934c796e6e4eb11c5Chris Craik}
4702806288d1c56475413888a934c796e6e4eb11c5Chris Craik
48487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk/*
49487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk * TransformedRectangle
50487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk */
51487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
52487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob TsukTransformedRectangle::TransformedRectangle() {
53487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
54487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
55487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob TsukTransformedRectangle::TransformedRectangle(const Rect& bounds,
56487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        const Matrix4& transform)
57487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        : mBounds(bounds)
58487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        , mTransform(transform) {
59487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
60487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
61487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukbool TransformedRectangle::canSimplyIntersectWith(
62487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        const TransformedRectangle& other) const {
63487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
64487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    return mTransform == other.mTransform;
65487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
66487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
67ac02eb9035a13a3d09c2def9ed63d04225eb2509Chris Craikvoid TransformedRectangle::intersectWith(const TransformedRectangle& other) {
68ac02eb9035a13a3d09c2def9ed63d04225eb2509Chris Craik    mBounds.doIntersect(other.mBounds);
69487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
70487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
71487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukbool TransformedRectangle::isEmpty() const {
72487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    return mBounds.isEmpty();
73487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
74487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
75487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk/*
76487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk * RectangleList
77487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk */
78487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
79487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob TsukRectangleList::RectangleList()
80487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        : mTransformedRectanglesCount(0) {
81487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
82487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
83487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukbool RectangleList::isEmpty() const {
84487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    if (mTransformedRectanglesCount < 1) {
85487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        return true;
86487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
87487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
88487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    for (int i = 0; i < mTransformedRectanglesCount; i++) {
89487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        if (mTransformedRectangles[i].isEmpty()) {
90487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            return true;
91487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        }
92487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
93487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    return false;
94487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
95487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
96487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukint RectangleList::getTransformedRectanglesCount() const {
97487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    return mTransformedRectanglesCount;
98487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
99487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
100487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukconst TransformedRectangle& RectangleList::getTransformedRectangle(int i) const {
101487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    return mTransformedRectangles[i];
102487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
103487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
104487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukvoid RectangleList::setEmpty() {
105487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mTransformedRectanglesCount = 0;
106487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
107487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
108487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukvoid RectangleList::set(const Rect& bounds, const Matrix4& transform) {
109487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mTransformedRectanglesCount = 1;
110487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mTransformedRectangles[0] = TransformedRectangle(bounds, transform);
111487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
112487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
113487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukbool RectangleList::intersectWith(const Rect& bounds,
114487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        const Matrix4& transform) {
115487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    TransformedRectangle newRectangle(bounds, transform);
116487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
117487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    // Try to find a rectangle with a compatible transformation
118487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    int index = 0;
119487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    for (; index < mTransformedRectanglesCount; index++) {
120487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        TransformedRectangle& tr(mTransformedRectangles[index]);
121487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        if (tr.canSimplyIntersectWith(newRectangle)) {
122487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            tr.intersectWith(newRectangle);
123487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            return true;
124487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        }
125487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
126487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
127487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    // Add it to the list if there is room
128487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    if (index < kMaxTransformedRectangles) {
129487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        mTransformedRectangles[index] = newRectangle;
130487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        mTransformedRectanglesCount += 1;
131487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        return true;
132487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
133487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
134487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    // This rectangle list is full
135487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    return false;
136487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
137487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
138487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob TsukRect RectangleList::calculateBounds() const {
139487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    Rect bounds;
140487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    for (int index = 0; index < mTransformedRectanglesCount; index++) {
141487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        const TransformedRectangle& tr(mTransformedRectangles[index]);
142487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        if (index == 0) {
143487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            bounds = tr.transformedBounds();
144487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        } else {
145ac02eb9035a13a3d09c2def9ed63d04225eb2509Chris Craik            bounds.doIntersect(tr.transformedBounds());
146487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        }
147487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
148487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    return bounds;
149487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
150487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
151487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukstatic SkPath pathFromTransformedRectangle(const Rect& bounds,
152487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        const Matrix4& transform) {
153487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    SkPath rectPath;
154487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    SkPath rectPathTransformed;
155487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    rectPath.addRect(bounds.left, bounds.top, bounds.right, bounds.bottom);
156487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    SkMatrix skTransform;
157487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    transform.copyTo(skTransform);
158487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    rectPath.transform(skTransform, &rectPathTransformed);
159487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    return rectPathTransformed;
160487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
161487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
162487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob TsukSkRegion RectangleList::convertToRegion(const SkRegion& clip) const {
163487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    SkRegion rectangleListAsRegion;
164487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    for (int index = 0; index < mTransformedRectanglesCount; index++) {
165487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        const TransformedRectangle& tr(mTransformedRectangles[index]);
166487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        SkPath rectPathTransformed = pathFromTransformedRectangle(
167487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk                tr.getBounds(), tr.getTransform());
168487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        if (index == 0) {
169487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            rectangleListAsRegion.setPath(rectPathTransformed, clip);
170487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        } else {
171487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            SkRegion rectRegion;
172487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            rectRegion.setPath(rectPathTransformed, clip);
173487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            rectangleListAsRegion.op(rectRegion, SkRegion::kIntersect_Op);
174487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        }
175487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
176487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    return rectangleListAsRegion;
177487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
178487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
179e4db79de127cfe961195f52907af8451026eaa20Chris Craikvoid RectangleList::transform(const Matrix4& transform) {
180e4db79de127cfe961195f52907af8451026eaa20Chris Craik    for (int index = 0; index < mTransformedRectanglesCount; index++) {
181e4db79de127cfe961195f52907af8451026eaa20Chris Craik        mTransformedRectangles[index].transform(transform);
182e4db79de127cfe961195f52907af8451026eaa20Chris Craik    }
183e4db79de127cfe961195f52907af8451026eaa20Chris Craik}
184e4db79de127cfe961195f52907af8451026eaa20Chris Craik
185487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk/*
186487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk * ClipArea
187487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk */
188487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
189487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob TsukClipArea::ClipArea()
190e4db79de127cfe961195f52907af8451026eaa20Chris Craik        : mMode(ClipMode::Rectangle) {
191487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
192487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
193487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk/*
194487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk * Interface
195487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk */
196487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
197487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukvoid ClipArea::setViewportDimensions(int width, int height) {
198e4db79de127cfe961195f52907af8451026eaa20Chris Craik    mPostViewportClipObserved = false;
199487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mViewportBounds.set(0, 0, width, height);
200487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mClipRect = mViewportBounds;
201487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
202487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
203487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukvoid ClipArea::setEmpty() {
204e4db79de127cfe961195f52907af8451026eaa20Chris Craik    onClipUpdated();
205e4db79de127cfe961195f52907af8451026eaa20Chris Craik    mMode = ClipMode::Rectangle;
206487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mClipRect.setEmpty();
207487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mClipRegion.setEmpty();
208487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mRectangleList.setEmpty();
209487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
210487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
211487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukvoid ClipArea::setClip(float left, float top, float right, float bottom) {
212e4db79de127cfe961195f52907af8451026eaa20Chris Craik    onClipUpdated();
213e4db79de127cfe961195f52907af8451026eaa20Chris Craik    mMode = ClipMode::Rectangle;
214487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mClipRect.set(left, top, right, bottom);
215487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mClipRegion.setEmpty();
216487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
217487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
2184d3e704b04c6abd7995df640d12662b0271f6c7bChris Craikvoid ClipArea::clipRectWithTransform(const Rect& r, const mat4* transform,
219487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        SkRegion::Op op) {
2207fc1b0349bc2ac8c880120dc5611f703faa7f06fChris Craik    if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op;
221e4db79de127cfe961195f52907af8451026eaa20Chris Craik    onClipUpdated();
222487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    switch (mMode) {
223e4db79de127cfe961195f52907af8451026eaa20Chris Craik    case ClipMode::Rectangle:
2244d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        rectangleModeClipRectWithTransform(r, transform, op);
2254d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        break;
226e4db79de127cfe961195f52907af8451026eaa20Chris Craik    case ClipMode::RectangleList:
2274d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        rectangleListModeClipRectWithTransform(r, transform, op);
2284d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        break;
229e4db79de127cfe961195f52907af8451026eaa20Chris Craik    case ClipMode::Region:
2304d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        regionModeClipRectWithTransform(r, transform, op);
2314d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        break;
232487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
233487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
234487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
2354d3e704b04c6abd7995df640d12662b0271f6c7bChris Craikvoid ClipArea::clipRegion(const SkRegion& region, SkRegion::Op op) {
2367fc1b0349bc2ac8c880120dc5611f703faa7f06fChris Craik    if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op;
237e4db79de127cfe961195f52907af8451026eaa20Chris Craik    onClipUpdated();
238487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    enterRegionMode();
239487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mClipRegion.op(region, op);
240e30b53cec5eb6eaa5d24231feb3207b917c1baabTom Hudson    onClipRegionUpdated();
241487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
242487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
2434d3e704b04c6abd7995df640d12662b0271f6c7bChris Craikvoid ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform,
244487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        SkRegion::Op op) {
2457fc1b0349bc2ac8c880120dc5611f703faa7f06fChris Craik    if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op;
246e4db79de127cfe961195f52907af8451026eaa20Chris Craik    onClipUpdated();
247487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    SkMatrix skTransform;
248487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    transform->copyTo(skTransform);
249487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    SkPath transformed;
250487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    path.transform(skTransform, &transformed);
251487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    SkRegion region;
252487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    regionFromPath(transformed, region);
2534d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik    clipRegion(region, op);
254487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
255487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
256487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk/*
257487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk * Rectangle mode
258487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk */
259487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
260487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukvoid ClipArea::enterRectangleMode() {
261487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    // Entering rectangle mode discards any
262487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    // existing clipping information from the other modes.
263487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    // The only way this occurs is by a clip setting operation.
264e4db79de127cfe961195f52907af8451026eaa20Chris Craik    mMode = ClipMode::Rectangle;
265487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
266487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
2674d3e704b04c6abd7995df640d12662b0271f6c7bChris Craikvoid ClipArea::rectangleModeClipRectWithTransform(const Rect& r,
268487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        const mat4* transform, SkRegion::Op op) {
269487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
2708ce8f3f4d68a7750bc02b5254ebbd8658281e675Chris Craik    if (op == SkRegion::kReplace_Op && transform->rectToRect()) {
2718ce8f3f4d68a7750bc02b5254ebbd8658281e675Chris Craik        mClipRect = r;
2728ce8f3f4d68a7750bc02b5254ebbd8658281e675Chris Craik        transform->mapRect(mClipRect);
2734d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        return;
2748ce8f3f4d68a7750bc02b5254ebbd8658281e675Chris Craik    } else if (op != SkRegion::kIntersect_Op) {
275487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        enterRegionMode();
2764d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        regionModeClipRectWithTransform(r, transform, op);
2774d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        return;
278487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
279487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
280487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    if (transform->rectToRect()) {
281487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        Rect transformed(r);
282487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        transform->mapRect(transformed);
283ac02eb9035a13a3d09c2def9ed63d04225eb2509Chris Craik        mClipRect.doIntersect(transformed);
2844d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        return;
285487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
286487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
287487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    enterRectangleListMode();
2884d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik    rectangleListModeClipRectWithTransform(r, transform, op);
289487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
290487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
291487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk/*
292487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk * RectangleList mode implementation
293487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk */
294487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
295487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukvoid ClipArea::enterRectangleListMode() {
296487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    // Is is only legal to enter rectangle list mode from
297487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    // rectangle mode, since rectangle list mode cannot represent
298487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    // all clip areas that can be represented by a region.
299e4db79de127cfe961195f52907af8451026eaa20Chris Craik    ALOG_ASSERT(mMode == ClipMode::Rectangle);
300e4db79de127cfe961195f52907af8451026eaa20Chris Craik    mMode = ClipMode::RectangleList;
301487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mRectangleList.set(mClipRect, Matrix4::identity());
302487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
303487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
3044d3e704b04c6abd7995df640d12662b0271f6c7bChris Craikvoid ClipArea::rectangleListModeClipRectWithTransform(const Rect& r,
305487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        const mat4* transform, SkRegion::Op op) {
306487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    if (op != SkRegion::kIntersect_Op
307487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            || !mRectangleList.intersectWith(r, *transform)) {
308487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        enterRegionMode();
3094d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        regionModeClipRectWithTransform(r, transform, op);
310487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
311487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
312487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
313487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk/*
314487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk * Region mode implementation
315487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk */
316487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
317487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukvoid ClipArea::enterRegionMode() {
318e4db79de127cfe961195f52907af8451026eaa20Chris Craik    ClipMode oldMode = mMode;
319e4db79de127cfe961195f52907af8451026eaa20Chris Craik    mMode = ClipMode::Region;
320e4db79de127cfe961195f52907af8451026eaa20Chris Craik    if (oldMode != ClipMode::Region) {
321e4db79de127cfe961195f52907af8451026eaa20Chris Craik        if (oldMode == ClipMode::Rectangle) {
322e4db79de127cfe961195f52907af8451026eaa20Chris Craik            mClipRegion.setRect(mClipRect.toSkIRect());
323487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        } else {
324487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            mClipRegion = mRectangleList.convertToRegion(createViewportRegion());
325e30b53cec5eb6eaa5d24231feb3207b917c1baabTom Hudson            onClipRegionUpdated();
326487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        }
327487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
328487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
329487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
3304d3e704b04c6abd7995df640d12662b0271f6c7bChris Craikvoid ClipArea::regionModeClipRectWithTransform(const Rect& r,
331487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        const mat4* transform, SkRegion::Op op) {
332487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    SkPath transformedRect = pathFromTransformedRectangle(r, *transform);
333487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    SkRegion transformedRectRegion;
334487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    regionFromPath(transformedRect, transformedRectRegion);
335487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mClipRegion.op(transformedRectRegion, op);
336e30b53cec5eb6eaa5d24231feb3207b917c1baabTom Hudson    onClipRegionUpdated();
337487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
338487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
339e30b53cec5eb6eaa5d24231feb3207b917c1baabTom Hudsonvoid ClipArea::onClipRegionUpdated() {
340487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    if (!mClipRegion.isEmpty()) {
341487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        mClipRect.set(mClipRegion.getBounds());
342487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
343487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        if (mClipRegion.isRect()) {
344487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            mClipRegion.setEmpty();
345e30b53cec5eb6eaa5d24231feb3207b917c1baabTom Hudson            enterRectangleMode();
346487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        }
347487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    } else {
348487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        mClipRect.setEmpty();
349487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
350487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
351487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
352e4db79de127cfe961195f52907af8451026eaa20Chris Craik/**
353e4db79de127cfe961195f52907af8451026eaa20Chris Craik * Clip serialization
354e4db79de127cfe961195f52907af8451026eaa20Chris Craik */
355e4db79de127cfe961195f52907af8451026eaa20Chris Craik
356e4db79de127cfe961195f52907af8451026eaa20Chris Craikconst ClipBase* ClipArea::serializeClip(LinearAllocator& allocator) {
357e4db79de127cfe961195f52907af8451026eaa20Chris Craik    if (!mPostViewportClipObserved) {
358e4db79de127cfe961195f52907af8451026eaa20Chris Craik        // Only initial clip-to-viewport observed, so no serialization of clip necessary
359e4db79de127cfe961195f52907af8451026eaa20Chris Craik        return nullptr;
360e4db79de127cfe961195f52907af8451026eaa20Chris Craik    }
361e4db79de127cfe961195f52907af8451026eaa20Chris Craik
362e4db79de127cfe961195f52907af8451026eaa20Chris Craik    static_assert(std::is_trivially_destructible<Rect>::value,
363e4db79de127cfe961195f52907af8451026eaa20Chris Craik            "expect Rect to be trivially destructible");
364e4db79de127cfe961195f52907af8451026eaa20Chris Craik    static_assert(std::is_trivially_destructible<RectangleList>::value,
365e4db79de127cfe961195f52907af8451026eaa20Chris Craik            "expect RectangleList to be trivially destructible");
366e4db79de127cfe961195f52907af8451026eaa20Chris Craik
367e4db79de127cfe961195f52907af8451026eaa20Chris Craik    if (mLastSerialization == nullptr) {
3684f4c60820995bad73d87c2fff4b5c5b1c6b5e027Chris Craik        ClipBase* serialization = nullptr;
369e4db79de127cfe961195f52907af8451026eaa20Chris Craik        switch (mMode) {
370e4db79de127cfe961195f52907af8451026eaa20Chris Craik        case ClipMode::Rectangle:
371b4f4f3e16d8fbb2905dfc168383213161e988f83Chris Craik            serialization = allocator.create<ClipRect>(mClipRect);
372e4db79de127cfe961195f52907af8451026eaa20Chris Craik            break;
373e4db79de127cfe961195f52907af8451026eaa20Chris Craik        case ClipMode::RectangleList:
374b4f4f3e16d8fbb2905dfc168383213161e988f83Chris Craik            serialization = allocator.create<ClipRectList>(mRectangleList);
375b4f4f3e16d8fbb2905dfc168383213161e988f83Chris Craik            serialization->rect = mRectangleList.calculateBounds();
376e4db79de127cfe961195f52907af8451026eaa20Chris Craik            break;
377e4db79de127cfe961195f52907af8451026eaa20Chris Craik        case ClipMode::Region:
378b4f4f3e16d8fbb2905dfc168383213161e988f83Chris Craik            serialization = allocator.create<ClipRegion>(mClipRegion);
379b4f4f3e16d8fbb2905dfc168383213161e988f83Chris Craik            serialization->rect.set(mClipRegion.getBounds());
380e4db79de127cfe961195f52907af8451026eaa20Chris Craik            break;
381e4db79de127cfe961195f52907af8451026eaa20Chris Craik        }
38269aeabe6184bbbe6e731656205ffbef78b7b0f3fChris Craik        // TODO: this is only done for draw time, should eventually avoid for record time
38369aeabe6184bbbe6e731656205ffbef78b7b0f3fChris Craik        serialization->rect.snapToPixelBoundaries();
384b4f4f3e16d8fbb2905dfc168383213161e988f83Chris Craik        mLastSerialization = serialization;
385e4db79de127cfe961195f52907af8451026eaa20Chris Craik    }
386e4db79de127cfe961195f52907af8451026eaa20Chris Craik    return mLastSerialization;
387e4db79de127cfe961195f52907af8451026eaa20Chris Craik}
388e4db79de127cfe961195f52907af8451026eaa20Chris Craik
389e4db79de127cfe961195f52907af8451026eaa20Chris Craikinline static const RectangleList& getRectList(const ClipBase* scb) {
390e4db79de127cfe961195f52907af8451026eaa20Chris Craik    return reinterpret_cast<const ClipRectList*>(scb)->rectList;
391e4db79de127cfe961195f52907af8451026eaa20Chris Craik}
392e4db79de127cfe961195f52907af8451026eaa20Chris Craik
393e4db79de127cfe961195f52907af8451026eaa20Chris Craikinline static const SkRegion& getRegion(const ClipBase* scb) {
394e4db79de127cfe961195f52907af8451026eaa20Chris Craik    return reinterpret_cast<const ClipRegion*>(scb)->region;
395e4db79de127cfe961195f52907af8451026eaa20Chris Craik}
396e4db79de127cfe961195f52907af8451026eaa20Chris Craik
397e4db79de127cfe961195f52907af8451026eaa20Chris Craik// Conservative check for too many rectangles to fit in rectangle list.
398e4db79de127cfe961195f52907af8451026eaa20Chris Craik// For simplicity, doesn't account for rect merging
399e4db79de127cfe961195f52907af8451026eaa20Chris Craikstatic bool cannotFitInRectangleList(const ClipArea& clipArea, const ClipBase* scb) {
400e4db79de127cfe961195f52907af8451026eaa20Chris Craik    int currentRectCount = clipArea.isRectangleList()
401e4db79de127cfe961195f52907af8451026eaa20Chris Craik            ? clipArea.getRectangleList().getTransformedRectanglesCount()
402e4db79de127cfe961195f52907af8451026eaa20Chris Craik            : 1;
403e4db79de127cfe961195f52907af8451026eaa20Chris Craik    int recordedRectCount = (scb->mode == ClipMode::RectangleList)
404e4db79de127cfe961195f52907af8451026eaa20Chris Craik            ? getRectList(scb).getTransformedRectanglesCount()
405e4db79de127cfe961195f52907af8451026eaa20Chris Craik            : 1;
406e4db79de127cfe961195f52907af8451026eaa20Chris Craik    return currentRectCount + recordedRectCount > RectangleList::kMaxTransformedRectangles;
407e4db79de127cfe961195f52907af8451026eaa20Chris Craik}
408e4db79de127cfe961195f52907af8451026eaa20Chris Craik
409261725fdb2962271c222a049fcdf57bbdc8363c7Chris Craikstatic const ClipRect sEmptyClipRect(Rect(0, 0));
410261725fdb2962271c222a049fcdf57bbdc8363c7Chris Craik
411e4db79de127cfe961195f52907af8451026eaa20Chris Craikconst ClipBase* ClipArea::serializeIntersectedClip(LinearAllocator& allocator,
412e4db79de127cfe961195f52907af8451026eaa20Chris Craik        const ClipBase* recordedClip, const Matrix4& recordedClipTransform) {
413261725fdb2962271c222a049fcdf57bbdc8363c7Chris Craik
414e4db79de127cfe961195f52907af8451026eaa20Chris Craik    // if no recordedClip passed, just serialize current state
415e4db79de127cfe961195f52907af8451026eaa20Chris Craik    if (!recordedClip) return serializeClip(allocator);
416e4db79de127cfe961195f52907af8451026eaa20Chris Craik
417261725fdb2962271c222a049fcdf57bbdc8363c7Chris Craik    // if either is empty, clip is empty
418261725fdb2962271c222a049fcdf57bbdc8363c7Chris Craik    if (CC_UNLIKELY(recordedClip->rect.isEmpty())|| mClipRect.isEmpty()) return &sEmptyClipRect;
419261725fdb2962271c222a049fcdf57bbdc8363c7Chris Craik
420e4db79de127cfe961195f52907af8451026eaa20Chris Craik    if (!mLastResolutionResult
421e4db79de127cfe961195f52907af8451026eaa20Chris Craik            || recordedClip != mLastResolutionClip
422e4db79de127cfe961195f52907af8451026eaa20Chris Craik            || recordedClipTransform != mLastResolutionTransform) {
423e4db79de127cfe961195f52907af8451026eaa20Chris Craik        mLastResolutionClip = recordedClip;
424e4db79de127cfe961195f52907af8451026eaa20Chris Craik        mLastResolutionTransform = recordedClipTransform;
425e4db79de127cfe961195f52907af8451026eaa20Chris Craik
426e4db79de127cfe961195f52907af8451026eaa20Chris Craik        if (CC_LIKELY(mMode == ClipMode::Rectangle
427e4db79de127cfe961195f52907af8451026eaa20Chris Craik                && recordedClip->mode == ClipMode::Rectangle
428e4db79de127cfe961195f52907af8451026eaa20Chris Craik                && recordedClipTransform.rectToRect())) {
429e4db79de127cfe961195f52907af8451026eaa20Chris Craik            // common case - result is a single rectangle
43069aeabe6184bbbe6e731656205ffbef78b7b0f3fChris Craik            auto rectClip = allocator.create<ClipRect>(recordedClip->rect);
431e4db79de127cfe961195f52907af8451026eaa20Chris Craik            recordedClipTransform.mapRect(rectClip->rect);
432e4db79de127cfe961195f52907af8451026eaa20Chris Craik            rectClip->rect.doIntersect(mClipRect);
43369aeabe6184bbbe6e731656205ffbef78b7b0f3fChris Craik            rectClip->rect.snapToPixelBoundaries();
434e4db79de127cfe961195f52907af8451026eaa20Chris Craik            mLastResolutionResult = rectClip;
435e4db79de127cfe961195f52907af8451026eaa20Chris Craik        } else if (CC_UNLIKELY(mMode == ClipMode::Region
436e4db79de127cfe961195f52907af8451026eaa20Chris Craik                || recordedClip->mode == ClipMode::Region
437e4db79de127cfe961195f52907af8451026eaa20Chris Craik                || cannotFitInRectangleList(*this, recordedClip))) {
438e4db79de127cfe961195f52907af8451026eaa20Chris Craik            // region case
439e4db79de127cfe961195f52907af8451026eaa20Chris Craik            SkRegion other;
440e4db79de127cfe961195f52907af8451026eaa20Chris Craik            switch (recordedClip->mode) {
441e4db79de127cfe961195f52907af8451026eaa20Chris Craik            case ClipMode::Rectangle:
442e4db79de127cfe961195f52907af8451026eaa20Chris Craik                if (CC_LIKELY(recordedClipTransform.rectToRect())) {
443e4db79de127cfe961195f52907af8451026eaa20Chris Craik                    // simple transform, skip creating SkPath
44469aeabe6184bbbe6e731656205ffbef78b7b0f3fChris Craik                    Rect resultClip(recordedClip->rect);
445e4db79de127cfe961195f52907af8451026eaa20Chris Craik                    recordedClipTransform.mapRect(resultClip);
446e4db79de127cfe961195f52907af8451026eaa20Chris Craik                    other.setRect(resultClip.toSkIRect());
447e4db79de127cfe961195f52907af8451026eaa20Chris Craik                } else {
44869aeabe6184bbbe6e731656205ffbef78b7b0f3fChris Craik                    SkPath transformedRect = pathFromTransformedRectangle(recordedClip->rect,
449e4db79de127cfe961195f52907af8451026eaa20Chris Craik                            recordedClipTransform);
450e4db79de127cfe961195f52907af8451026eaa20Chris Craik                    other.setPath(transformedRect, createViewportRegion());
451e4db79de127cfe961195f52907af8451026eaa20Chris Craik                }
452e4db79de127cfe961195f52907af8451026eaa20Chris Craik                break;
453e4db79de127cfe961195f52907af8451026eaa20Chris Craik            case ClipMode::RectangleList: {
454e4db79de127cfe961195f52907af8451026eaa20Chris Craik                RectangleList transformedList(getRectList(recordedClip));
455e4db79de127cfe961195f52907af8451026eaa20Chris Craik                transformedList.transform(recordedClipTransform);
456e4db79de127cfe961195f52907af8451026eaa20Chris Craik                other = transformedList.convertToRegion(createViewportRegion());
457e4db79de127cfe961195f52907af8451026eaa20Chris Craik                break;
458e4db79de127cfe961195f52907af8451026eaa20Chris Craik            }
459e4db79de127cfe961195f52907af8451026eaa20Chris Craik            case ClipMode::Region:
460e4db79de127cfe961195f52907af8451026eaa20Chris Craik                other = getRegion(recordedClip);
461e4db79de127cfe961195f52907af8451026eaa20Chris Craik
462e4db79de127cfe961195f52907af8451026eaa20Chris Craik                // TODO: handle non-translate transforms properly!
463e4db79de127cfe961195f52907af8451026eaa20Chris Craik                other.translate(recordedClipTransform.getTranslateX(),
464e4db79de127cfe961195f52907af8451026eaa20Chris Craik                        recordedClipTransform.getTranslateY());
465e4db79de127cfe961195f52907af8451026eaa20Chris Craik            }
466e4db79de127cfe961195f52907af8451026eaa20Chris Craik
467e4db79de127cfe961195f52907af8451026eaa20Chris Craik            ClipRegion* regionClip = allocator.create<ClipRegion>();
468e4db79de127cfe961195f52907af8451026eaa20Chris Craik            switch (mMode) {
469e4db79de127cfe961195f52907af8451026eaa20Chris Craik            case ClipMode::Rectangle:
470e4db79de127cfe961195f52907af8451026eaa20Chris Craik                regionClip->region.op(mClipRect.toSkIRect(), other, SkRegion::kIntersect_Op);
471e4db79de127cfe961195f52907af8451026eaa20Chris Craik                break;
472e4db79de127cfe961195f52907af8451026eaa20Chris Craik            case ClipMode::RectangleList:
473e4db79de127cfe961195f52907af8451026eaa20Chris Craik                regionClip->region.op(mRectangleList.convertToRegion(createViewportRegion()),
474e4db79de127cfe961195f52907af8451026eaa20Chris Craik                        other, SkRegion::kIntersect_Op);
475e4db79de127cfe961195f52907af8451026eaa20Chris Craik                break;
476e4db79de127cfe961195f52907af8451026eaa20Chris Craik            case ClipMode::Region:
477e4db79de127cfe961195f52907af8451026eaa20Chris Craik                regionClip->region.op(mClipRegion, other, SkRegion::kIntersect_Op);
478e4db79de127cfe961195f52907af8451026eaa20Chris Craik                break;
479e4db79de127cfe961195f52907af8451026eaa20Chris Craik            }
48069aeabe6184bbbe6e731656205ffbef78b7b0f3fChris Craik            // Don't need to snap, since region's in int bounds
481e4db79de127cfe961195f52907af8451026eaa20Chris Craik            regionClip->rect.set(regionClip->region.getBounds());
482e4db79de127cfe961195f52907af8451026eaa20Chris Craik            mLastResolutionResult = regionClip;
483e4db79de127cfe961195f52907af8451026eaa20Chris Craik        } else {
484e4db79de127cfe961195f52907af8451026eaa20Chris Craik            auto rectListClip = allocator.create<ClipRectList>(mRectangleList);
485e4db79de127cfe961195f52907af8451026eaa20Chris Craik            auto&& rectList = rectListClip->rectList;
486e4db79de127cfe961195f52907af8451026eaa20Chris Craik            if (mMode == ClipMode::Rectangle) {
487e4db79de127cfe961195f52907af8451026eaa20Chris Craik                rectList.set(mClipRect, Matrix4::identity());
488e4db79de127cfe961195f52907af8451026eaa20Chris Craik            }
489e4db79de127cfe961195f52907af8451026eaa20Chris Craik
490e4db79de127cfe961195f52907af8451026eaa20Chris Craik            if (recordedClip->mode == ClipMode::Rectangle) {
49169aeabe6184bbbe6e731656205ffbef78b7b0f3fChris Craik                rectList.intersectWith(recordedClip->rect, recordedClipTransform);
492e4db79de127cfe961195f52907af8451026eaa20Chris Craik            } else {
493e4db79de127cfe961195f52907af8451026eaa20Chris Craik                const RectangleList& other = getRectList(recordedClip);
494e4db79de127cfe961195f52907af8451026eaa20Chris Craik                for (int i = 0; i < other.getTransformedRectanglesCount(); i++) {
495e4db79de127cfe961195f52907af8451026eaa20Chris Craik                    auto&& tr = other.getTransformedRectangle(i);
496e4db79de127cfe961195f52907af8451026eaa20Chris Craik                    Matrix4 totalTransform(recordedClipTransform);
497e4db79de127cfe961195f52907af8451026eaa20Chris Craik                    totalTransform.multiply(tr.getTransform());
498e4db79de127cfe961195f52907af8451026eaa20Chris Craik                    rectList.intersectWith(tr.getBounds(), totalTransform);
499e4db79de127cfe961195f52907af8451026eaa20Chris Craik                }
500e4db79de127cfe961195f52907af8451026eaa20Chris Craik            }
501e4db79de127cfe961195f52907af8451026eaa20Chris Craik            rectListClip->rect = rectList.calculateBounds();
50269aeabe6184bbbe6e731656205ffbef78b7b0f3fChris Craik            rectListClip->rect.snapToPixelBoundaries();
503e4db79de127cfe961195f52907af8451026eaa20Chris Craik            mLastResolutionResult = rectListClip;
504e4db79de127cfe961195f52907af8451026eaa20Chris Craik        }
505e4db79de127cfe961195f52907af8451026eaa20Chris Craik    }
506e4db79de127cfe961195f52907af8451026eaa20Chris Craik    return mLastResolutionResult;
507e4db79de127cfe961195f52907af8451026eaa20Chris Craik}
508e4db79de127cfe961195f52907af8451026eaa20Chris Craik
509e4db79de127cfe961195f52907af8451026eaa20Chris Craikvoid ClipArea::applyClip(const ClipBase* clip, const Matrix4& transform) {
510e4db79de127cfe961195f52907af8451026eaa20Chris Craik    if (!clip) return; // nothing to do
511e4db79de127cfe961195f52907af8451026eaa20Chris Craik
512e4db79de127cfe961195f52907af8451026eaa20Chris Craik    if (CC_LIKELY(clip->mode == ClipMode::Rectangle)) {
51369aeabe6184bbbe6e731656205ffbef78b7b0f3fChris Craik        clipRectWithTransform(clip->rect, &transform, SkRegion::kIntersect_Op);
514e4db79de127cfe961195f52907af8451026eaa20Chris Craik    } else if (CC_LIKELY(clip->mode == ClipMode::RectangleList)) {
515e4db79de127cfe961195f52907af8451026eaa20Chris Craik        auto&& rectList = getRectList(clip);
516e4db79de127cfe961195f52907af8451026eaa20Chris Craik        for (int i = 0; i < rectList.getTransformedRectanglesCount(); i++) {
517e4db79de127cfe961195f52907af8451026eaa20Chris Craik            auto&& tr = rectList.getTransformedRectangle(i);
518e4db79de127cfe961195f52907af8451026eaa20Chris Craik            Matrix4 totalTransform(transform);
519e4db79de127cfe961195f52907af8451026eaa20Chris Craik            totalTransform.multiply(tr.getTransform());
520e4db79de127cfe961195f52907af8451026eaa20Chris Craik            clipRectWithTransform(tr.getBounds(), &totalTransform, SkRegion::kIntersect_Op);
521e4db79de127cfe961195f52907af8451026eaa20Chris Craik        }
522e4db79de127cfe961195f52907af8451026eaa20Chris Craik    } else {
523e4db79de127cfe961195f52907af8451026eaa20Chris Craik        SkRegion region(getRegion(clip));
524e4db79de127cfe961195f52907af8451026eaa20Chris Craik        // TODO: handle non-translate transforms properly!
525e4db79de127cfe961195f52907af8451026eaa20Chris Craik        region.translate(transform.getTranslateX(), transform.getTranslateY());
526e4db79de127cfe961195f52907af8451026eaa20Chris Craik        clipRegion(region, SkRegion::kIntersect_Op);
527e4db79de127cfe961195f52907af8451026eaa20Chris Craik    }
528e4db79de127cfe961195f52907af8451026eaa20Chris Craik}
529e4db79de127cfe961195f52907af8451026eaa20Chris Craik
530487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk} /* namespace uirenderer */
531487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk} /* namespace android */
532