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) {
22004d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    if (op == SkRegion::kReplace_Op) mReplaceOpObserved = true;
2217fc1b0349bc2ac8c880120dc5611f703faa7f06fChris Craik    if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op;
222e4db79de127cfe961195f52907af8451026eaa20Chris Craik    onClipUpdated();
223487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    switch (mMode) {
224e4db79de127cfe961195f52907af8451026eaa20Chris Craik    case ClipMode::Rectangle:
2254d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        rectangleModeClipRectWithTransform(r, transform, op);
2264d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        break;
227e4db79de127cfe961195f52907af8451026eaa20Chris Craik    case ClipMode::RectangleList:
2284d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        rectangleListModeClipRectWithTransform(r, transform, op);
2294d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        break;
230e4db79de127cfe961195f52907af8451026eaa20Chris Craik    case ClipMode::Region:
2314d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        regionModeClipRectWithTransform(r, transform, op);
2324d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        break;
233487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
234487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
235487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
2364d3e704b04c6abd7995df640d12662b0271f6c7bChris Craikvoid ClipArea::clipRegion(const SkRegion& region, SkRegion::Op op) {
23704d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    if (op == SkRegion::kReplace_Op) mReplaceOpObserved = true;
2387fc1b0349bc2ac8c880120dc5611f703faa7f06fChris Craik    if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op;
239e4db79de127cfe961195f52907af8451026eaa20Chris Craik    onClipUpdated();
240487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    enterRegionMode();
241487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mClipRegion.op(region, op);
242e30b53cec5eb6eaa5d24231feb3207b917c1baabTom Hudson    onClipRegionUpdated();
243487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
244487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
2454d3e704b04c6abd7995df640d12662b0271f6c7bChris Craikvoid ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform,
246487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        SkRegion::Op op) {
24704d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    if (op == SkRegion::kReplace_Op) mReplaceOpObserved = true;
2487fc1b0349bc2ac8c880120dc5611f703faa7f06fChris Craik    if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op;
249e4db79de127cfe961195f52907af8451026eaa20Chris Craik    onClipUpdated();
250487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    SkMatrix skTransform;
251487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    transform->copyTo(skTransform);
252487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    SkPath transformed;
253487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    path.transform(skTransform, &transformed);
254487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    SkRegion region;
255487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    regionFromPath(transformed, region);
256bf27b995ae1bc36ee0b24effcaf41ec477e7fae3Chris Craik    enterRegionMode();
257bf27b995ae1bc36ee0b24effcaf41ec477e7fae3Chris Craik    mClipRegion.op(region, op);
258bf27b995ae1bc36ee0b24effcaf41ec477e7fae3Chris Craik    onClipRegionUpdated();
259487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
260487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
261487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk/*
262487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk * Rectangle mode
263487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk */
264487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
265487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukvoid ClipArea::enterRectangleMode() {
266487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    // Entering rectangle mode discards any
267487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    // existing clipping information from the other modes.
268487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    // The only way this occurs is by a clip setting operation.
269e4db79de127cfe961195f52907af8451026eaa20Chris Craik    mMode = ClipMode::Rectangle;
270487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
271487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
2724d3e704b04c6abd7995df640d12662b0271f6c7bChris Craikvoid ClipArea::rectangleModeClipRectWithTransform(const Rect& r,
273487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        const mat4* transform, SkRegion::Op op) {
274487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
2758ce8f3f4d68a7750bc02b5254ebbd8658281e675Chris Craik    if (op == SkRegion::kReplace_Op && transform->rectToRect()) {
2768ce8f3f4d68a7750bc02b5254ebbd8658281e675Chris Craik        mClipRect = r;
2778ce8f3f4d68a7750bc02b5254ebbd8658281e675Chris Craik        transform->mapRect(mClipRect);
2784d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        return;
2798ce8f3f4d68a7750bc02b5254ebbd8658281e675Chris Craik    } else if (op != SkRegion::kIntersect_Op) {
280487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        enterRegionMode();
2814d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        regionModeClipRectWithTransform(r, transform, op);
2824d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        return;
283487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
284487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
285487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    if (transform->rectToRect()) {
286487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        Rect transformed(r);
287487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        transform->mapRect(transformed);
288ac02eb9035a13a3d09c2def9ed63d04225eb2509Chris Craik        mClipRect.doIntersect(transformed);
2894d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        return;
290487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
291487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
292487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    enterRectangleListMode();
2934d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik    rectangleListModeClipRectWithTransform(r, transform, op);
294487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
295487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
296487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk/*
297487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk * RectangleList mode implementation
298487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk */
299487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
300487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukvoid ClipArea::enterRectangleListMode() {
301487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    // Is is only legal to enter rectangle list mode from
302487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    // rectangle mode, since rectangle list mode cannot represent
303487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    // all clip areas that can be represented by a region.
304e4db79de127cfe961195f52907af8451026eaa20Chris Craik    ALOG_ASSERT(mMode == ClipMode::Rectangle);
305e4db79de127cfe961195f52907af8451026eaa20Chris Craik    mMode = ClipMode::RectangleList;
306487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mRectangleList.set(mClipRect, Matrix4::identity());
307487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
308487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
3094d3e704b04c6abd7995df640d12662b0271f6c7bChris Craikvoid ClipArea::rectangleListModeClipRectWithTransform(const Rect& r,
310487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        const mat4* transform, SkRegion::Op op) {
311487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    if (op != SkRegion::kIntersect_Op
312487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            || !mRectangleList.intersectWith(r, *transform)) {
313487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        enterRegionMode();
3144d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik        regionModeClipRectWithTransform(r, transform, op);
315487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
316487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
317487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
318487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk/*
319487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk * Region mode implementation
320487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk */
321487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
322487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukvoid ClipArea::enterRegionMode() {
323e4db79de127cfe961195f52907af8451026eaa20Chris Craik    ClipMode oldMode = mMode;
324e4db79de127cfe961195f52907af8451026eaa20Chris Craik    mMode = ClipMode::Region;
325e4db79de127cfe961195f52907af8451026eaa20Chris Craik    if (oldMode != ClipMode::Region) {
326e4db79de127cfe961195f52907af8451026eaa20Chris Craik        if (oldMode == ClipMode::Rectangle) {
327e4db79de127cfe961195f52907af8451026eaa20Chris Craik            mClipRegion.setRect(mClipRect.toSkIRect());
328487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        } else {
329487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            mClipRegion = mRectangleList.convertToRegion(createViewportRegion());
330e30b53cec5eb6eaa5d24231feb3207b917c1baabTom Hudson            onClipRegionUpdated();
331487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        }
332487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
333487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
334487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
3354d3e704b04c6abd7995df640d12662b0271f6c7bChris Craikvoid ClipArea::regionModeClipRectWithTransform(const Rect& r,
336487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        const mat4* transform, SkRegion::Op op) {
337487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    SkPath transformedRect = pathFromTransformedRectangle(r, *transform);
338487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    SkRegion transformedRectRegion;
339487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    regionFromPath(transformedRect, transformedRectRegion);
340487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mClipRegion.op(transformedRectRegion, op);
341e30b53cec5eb6eaa5d24231feb3207b917c1baabTom Hudson    onClipRegionUpdated();
342487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
343487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
344e30b53cec5eb6eaa5d24231feb3207b917c1baabTom Hudsonvoid ClipArea::onClipRegionUpdated() {
345487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    if (!mClipRegion.isEmpty()) {
346487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        mClipRect.set(mClipRegion.getBounds());
347487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
348487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        if (mClipRegion.isRect()) {
349487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            mClipRegion.setEmpty();
350e30b53cec5eb6eaa5d24231feb3207b917c1baabTom Hudson            enterRectangleMode();
351487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        }
352487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    } else {
353487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        mClipRect.setEmpty();
354487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
355487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
356487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
357e4db79de127cfe961195f52907af8451026eaa20Chris Craik/**
358e4db79de127cfe961195f52907af8451026eaa20Chris Craik * Clip serialization
359e4db79de127cfe961195f52907af8451026eaa20Chris Craik */
360e4db79de127cfe961195f52907af8451026eaa20Chris Craik
361e4db79de127cfe961195f52907af8451026eaa20Chris Craikconst ClipBase* ClipArea::serializeClip(LinearAllocator& allocator) {
362e4db79de127cfe961195f52907af8451026eaa20Chris Craik    if (!mPostViewportClipObserved) {
363e4db79de127cfe961195f52907af8451026eaa20Chris Craik        // Only initial clip-to-viewport observed, so no serialization of clip necessary
364e4db79de127cfe961195f52907af8451026eaa20Chris Craik        return nullptr;
365e4db79de127cfe961195f52907af8451026eaa20Chris Craik    }
366e4db79de127cfe961195f52907af8451026eaa20Chris Craik
367e4db79de127cfe961195f52907af8451026eaa20Chris Craik    static_assert(std::is_trivially_destructible<Rect>::value,
368e4db79de127cfe961195f52907af8451026eaa20Chris Craik            "expect Rect to be trivially destructible");
369e4db79de127cfe961195f52907af8451026eaa20Chris Craik    static_assert(std::is_trivially_destructible<RectangleList>::value,
370e4db79de127cfe961195f52907af8451026eaa20Chris Craik            "expect RectangleList to be trivially destructible");
371e4db79de127cfe961195f52907af8451026eaa20Chris Craik
372e4db79de127cfe961195f52907af8451026eaa20Chris Craik    if (mLastSerialization == nullptr) {
3734f4c60820995bad73d87c2fff4b5c5b1c6b5e027Chris Craik        ClipBase* serialization = nullptr;
374e4db79de127cfe961195f52907af8451026eaa20Chris Craik        switch (mMode) {
375e4db79de127cfe961195f52907af8451026eaa20Chris Craik        case ClipMode::Rectangle:
376b4f4f3e16d8fbb2905dfc168383213161e988f83Chris Craik            serialization = allocator.create<ClipRect>(mClipRect);
377e4db79de127cfe961195f52907af8451026eaa20Chris Craik            break;
378e4db79de127cfe961195f52907af8451026eaa20Chris Craik        case ClipMode::RectangleList:
379b4f4f3e16d8fbb2905dfc168383213161e988f83Chris Craik            serialization = allocator.create<ClipRectList>(mRectangleList);
380b4f4f3e16d8fbb2905dfc168383213161e988f83Chris Craik            serialization->rect = mRectangleList.calculateBounds();
381e4db79de127cfe961195f52907af8451026eaa20Chris Craik            break;
382e4db79de127cfe961195f52907af8451026eaa20Chris Craik        case ClipMode::Region:
383b4f4f3e16d8fbb2905dfc168383213161e988f83Chris Craik            serialization = allocator.create<ClipRegion>(mClipRegion);
384b4f4f3e16d8fbb2905dfc168383213161e988f83Chris Craik            serialization->rect.set(mClipRegion.getBounds());
385e4db79de127cfe961195f52907af8451026eaa20Chris Craik            break;
386e4db79de127cfe961195f52907af8451026eaa20Chris Craik        }
38704d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik        serialization->intersectWithRoot = mReplaceOpObserved;
38869aeabe6184bbbe6e731656205ffbef78b7b0f3fChris Craik        // TODO: this is only done for draw time, should eventually avoid for record time
38969aeabe6184bbbe6e731656205ffbef78b7b0f3fChris Craik        serialization->rect.snapToPixelBoundaries();
390b4f4f3e16d8fbb2905dfc168383213161e988f83Chris Craik        mLastSerialization = serialization;
391e4db79de127cfe961195f52907af8451026eaa20Chris Craik    }
392e4db79de127cfe961195f52907af8451026eaa20Chris Craik    return mLastSerialization;
393e4db79de127cfe961195f52907af8451026eaa20Chris Craik}
394e4db79de127cfe961195f52907af8451026eaa20Chris Craik
395e4db79de127cfe961195f52907af8451026eaa20Chris Craikinline static const RectangleList& getRectList(const ClipBase* scb) {
396e4db79de127cfe961195f52907af8451026eaa20Chris Craik    return reinterpret_cast<const ClipRectList*>(scb)->rectList;
397e4db79de127cfe961195f52907af8451026eaa20Chris Craik}
398e4db79de127cfe961195f52907af8451026eaa20Chris Craik
399e4db79de127cfe961195f52907af8451026eaa20Chris Craikinline static const SkRegion& getRegion(const ClipBase* scb) {
400e4db79de127cfe961195f52907af8451026eaa20Chris Craik    return reinterpret_cast<const ClipRegion*>(scb)->region;
401e4db79de127cfe961195f52907af8451026eaa20Chris Craik}
402e4db79de127cfe961195f52907af8451026eaa20Chris Craik
403e4db79de127cfe961195f52907af8451026eaa20Chris Craik// Conservative check for too many rectangles to fit in rectangle list.
404e4db79de127cfe961195f52907af8451026eaa20Chris Craik// For simplicity, doesn't account for rect merging
405e4db79de127cfe961195f52907af8451026eaa20Chris Craikstatic bool cannotFitInRectangleList(const ClipArea& clipArea, const ClipBase* scb) {
406e4db79de127cfe961195f52907af8451026eaa20Chris Craik    int currentRectCount = clipArea.isRectangleList()
407e4db79de127cfe961195f52907af8451026eaa20Chris Craik            ? clipArea.getRectangleList().getTransformedRectanglesCount()
408e4db79de127cfe961195f52907af8451026eaa20Chris Craik            : 1;
409e4db79de127cfe961195f52907af8451026eaa20Chris Craik    int recordedRectCount = (scb->mode == ClipMode::RectangleList)
410e4db79de127cfe961195f52907af8451026eaa20Chris Craik            ? getRectList(scb).getTransformedRectanglesCount()
411e4db79de127cfe961195f52907af8451026eaa20Chris Craik            : 1;
412e4db79de127cfe961195f52907af8451026eaa20Chris Craik    return currentRectCount + recordedRectCount > RectangleList::kMaxTransformedRectangles;
413e4db79de127cfe961195f52907af8451026eaa20Chris Craik}
414e4db79de127cfe961195f52907af8451026eaa20Chris Craik
415261725fdb2962271c222a049fcdf57bbdc8363c7Chris Craikstatic const ClipRect sEmptyClipRect(Rect(0, 0));
416261725fdb2962271c222a049fcdf57bbdc8363c7Chris Craik
417e4db79de127cfe961195f52907af8451026eaa20Chris Craikconst ClipBase* ClipArea::serializeIntersectedClip(LinearAllocator& allocator,
418e4db79de127cfe961195f52907af8451026eaa20Chris Craik        const ClipBase* recordedClip, const Matrix4& recordedClipTransform) {
419261725fdb2962271c222a049fcdf57bbdc8363c7Chris Craik
420e4db79de127cfe961195f52907af8451026eaa20Chris Craik    // if no recordedClip passed, just serialize current state
421e4db79de127cfe961195f52907af8451026eaa20Chris Craik    if (!recordedClip) return serializeClip(allocator);
422e4db79de127cfe961195f52907af8451026eaa20Chris Craik
423261725fdb2962271c222a049fcdf57bbdc8363c7Chris Craik    // if either is empty, clip is empty
424261725fdb2962271c222a049fcdf57bbdc8363c7Chris Craik    if (CC_UNLIKELY(recordedClip->rect.isEmpty())|| mClipRect.isEmpty()) return &sEmptyClipRect;
425261725fdb2962271c222a049fcdf57bbdc8363c7Chris Craik
426e4db79de127cfe961195f52907af8451026eaa20Chris Craik    if (!mLastResolutionResult
427e4db79de127cfe961195f52907af8451026eaa20Chris Craik            || recordedClip != mLastResolutionClip
428e4db79de127cfe961195f52907af8451026eaa20Chris Craik            || recordedClipTransform != mLastResolutionTransform) {
429e4db79de127cfe961195f52907af8451026eaa20Chris Craik        mLastResolutionClip = recordedClip;
430e4db79de127cfe961195f52907af8451026eaa20Chris Craik        mLastResolutionTransform = recordedClipTransform;
431e4db79de127cfe961195f52907af8451026eaa20Chris Craik
432e4db79de127cfe961195f52907af8451026eaa20Chris Craik        if (CC_LIKELY(mMode == ClipMode::Rectangle
433e4db79de127cfe961195f52907af8451026eaa20Chris Craik                && recordedClip->mode == ClipMode::Rectangle
434e4db79de127cfe961195f52907af8451026eaa20Chris Craik                && recordedClipTransform.rectToRect())) {
435e4db79de127cfe961195f52907af8451026eaa20Chris Craik            // common case - result is a single rectangle
43669aeabe6184bbbe6e731656205ffbef78b7b0f3fChris Craik            auto rectClip = allocator.create<ClipRect>(recordedClip->rect);
437e4db79de127cfe961195f52907af8451026eaa20Chris Craik            recordedClipTransform.mapRect(rectClip->rect);
438e4db79de127cfe961195f52907af8451026eaa20Chris Craik            rectClip->rect.doIntersect(mClipRect);
43969aeabe6184bbbe6e731656205ffbef78b7b0f3fChris Craik            rectClip->rect.snapToPixelBoundaries();
440e4db79de127cfe961195f52907af8451026eaa20Chris Craik            mLastResolutionResult = rectClip;
441e4db79de127cfe961195f52907af8451026eaa20Chris Craik        } else if (CC_UNLIKELY(mMode == ClipMode::Region
442e4db79de127cfe961195f52907af8451026eaa20Chris Craik                || recordedClip->mode == ClipMode::Region
443e4db79de127cfe961195f52907af8451026eaa20Chris Craik                || cannotFitInRectangleList(*this, recordedClip))) {
444e4db79de127cfe961195f52907af8451026eaa20Chris Craik            // region case
445e4db79de127cfe961195f52907af8451026eaa20Chris Craik            SkRegion other;
446e4db79de127cfe961195f52907af8451026eaa20Chris Craik            switch (recordedClip->mode) {
447e4db79de127cfe961195f52907af8451026eaa20Chris Craik            case ClipMode::Rectangle:
448e4db79de127cfe961195f52907af8451026eaa20Chris Craik                if (CC_LIKELY(recordedClipTransform.rectToRect())) {
449e4db79de127cfe961195f52907af8451026eaa20Chris Craik                    // simple transform, skip creating SkPath
45069aeabe6184bbbe6e731656205ffbef78b7b0f3fChris Craik                    Rect resultClip(recordedClip->rect);
451e4db79de127cfe961195f52907af8451026eaa20Chris Craik                    recordedClipTransform.mapRect(resultClip);
452e4db79de127cfe961195f52907af8451026eaa20Chris Craik                    other.setRect(resultClip.toSkIRect());
453e4db79de127cfe961195f52907af8451026eaa20Chris Craik                } else {
45469aeabe6184bbbe6e731656205ffbef78b7b0f3fChris Craik                    SkPath transformedRect = pathFromTransformedRectangle(recordedClip->rect,
455e4db79de127cfe961195f52907af8451026eaa20Chris Craik                            recordedClipTransform);
456e4db79de127cfe961195f52907af8451026eaa20Chris Craik                    other.setPath(transformedRect, createViewportRegion());
457e4db79de127cfe961195f52907af8451026eaa20Chris Craik                }
458e4db79de127cfe961195f52907af8451026eaa20Chris Craik                break;
459e4db79de127cfe961195f52907af8451026eaa20Chris Craik            case ClipMode::RectangleList: {
460e4db79de127cfe961195f52907af8451026eaa20Chris Craik                RectangleList transformedList(getRectList(recordedClip));
461e4db79de127cfe961195f52907af8451026eaa20Chris Craik                transformedList.transform(recordedClipTransform);
462e4db79de127cfe961195f52907af8451026eaa20Chris Craik                other = transformedList.convertToRegion(createViewportRegion());
463e4db79de127cfe961195f52907af8451026eaa20Chris Craik                break;
464e4db79de127cfe961195f52907af8451026eaa20Chris Craik            }
465e4db79de127cfe961195f52907af8451026eaa20Chris Craik            case ClipMode::Region:
466e4db79de127cfe961195f52907af8451026eaa20Chris Craik                other = getRegion(recordedClip);
467e4db79de127cfe961195f52907af8451026eaa20Chris Craik
468e4db79de127cfe961195f52907af8451026eaa20Chris Craik                // TODO: handle non-translate transforms properly!
469e4db79de127cfe961195f52907af8451026eaa20Chris Craik                other.translate(recordedClipTransform.getTranslateX(),
470e4db79de127cfe961195f52907af8451026eaa20Chris Craik                        recordedClipTransform.getTranslateY());
471e4db79de127cfe961195f52907af8451026eaa20Chris Craik            }
472e4db79de127cfe961195f52907af8451026eaa20Chris Craik
473e4db79de127cfe961195f52907af8451026eaa20Chris Craik            ClipRegion* regionClip = allocator.create<ClipRegion>();
474e4db79de127cfe961195f52907af8451026eaa20Chris Craik            switch (mMode) {
475e4db79de127cfe961195f52907af8451026eaa20Chris Craik            case ClipMode::Rectangle:
476e4db79de127cfe961195f52907af8451026eaa20Chris Craik                regionClip->region.op(mClipRect.toSkIRect(), other, SkRegion::kIntersect_Op);
477e4db79de127cfe961195f52907af8451026eaa20Chris Craik                break;
478e4db79de127cfe961195f52907af8451026eaa20Chris Craik            case ClipMode::RectangleList:
479e4db79de127cfe961195f52907af8451026eaa20Chris Craik                regionClip->region.op(mRectangleList.convertToRegion(createViewportRegion()),
480e4db79de127cfe961195f52907af8451026eaa20Chris Craik                        other, SkRegion::kIntersect_Op);
481e4db79de127cfe961195f52907af8451026eaa20Chris Craik                break;
482e4db79de127cfe961195f52907af8451026eaa20Chris Craik            case ClipMode::Region:
483e4db79de127cfe961195f52907af8451026eaa20Chris Craik                regionClip->region.op(mClipRegion, other, SkRegion::kIntersect_Op);
484e4db79de127cfe961195f52907af8451026eaa20Chris Craik                break;
485e4db79de127cfe961195f52907af8451026eaa20Chris Craik            }
48669aeabe6184bbbe6e731656205ffbef78b7b0f3fChris Craik            // Don't need to snap, since region's in int bounds
487e4db79de127cfe961195f52907af8451026eaa20Chris Craik            regionClip->rect.set(regionClip->region.getBounds());
488e4db79de127cfe961195f52907af8451026eaa20Chris Craik            mLastResolutionResult = regionClip;
489e4db79de127cfe961195f52907af8451026eaa20Chris Craik        } else {
490e4db79de127cfe961195f52907af8451026eaa20Chris Craik            auto rectListClip = allocator.create<ClipRectList>(mRectangleList);
491e4db79de127cfe961195f52907af8451026eaa20Chris Craik            auto&& rectList = rectListClip->rectList;
492e4db79de127cfe961195f52907af8451026eaa20Chris Craik            if (mMode == ClipMode::Rectangle) {
493e4db79de127cfe961195f52907af8451026eaa20Chris Craik                rectList.set(mClipRect, Matrix4::identity());
494e4db79de127cfe961195f52907af8451026eaa20Chris Craik            }
495e4db79de127cfe961195f52907af8451026eaa20Chris Craik
496e4db79de127cfe961195f52907af8451026eaa20Chris Craik            if (recordedClip->mode == ClipMode::Rectangle) {
49769aeabe6184bbbe6e731656205ffbef78b7b0f3fChris Craik                rectList.intersectWith(recordedClip->rect, recordedClipTransform);
498e4db79de127cfe961195f52907af8451026eaa20Chris Craik            } else {
499e4db79de127cfe961195f52907af8451026eaa20Chris Craik                const RectangleList& other = getRectList(recordedClip);
500e4db79de127cfe961195f52907af8451026eaa20Chris Craik                for (int i = 0; i < other.getTransformedRectanglesCount(); i++) {
501e4db79de127cfe961195f52907af8451026eaa20Chris Craik                    auto&& tr = other.getTransformedRectangle(i);
502e4db79de127cfe961195f52907af8451026eaa20Chris Craik                    Matrix4 totalTransform(recordedClipTransform);
503e4db79de127cfe961195f52907af8451026eaa20Chris Craik                    totalTransform.multiply(tr.getTransform());
504e4db79de127cfe961195f52907af8451026eaa20Chris Craik                    rectList.intersectWith(tr.getBounds(), totalTransform);
505e4db79de127cfe961195f52907af8451026eaa20Chris Craik                }
506e4db79de127cfe961195f52907af8451026eaa20Chris Craik            }
507e4db79de127cfe961195f52907af8451026eaa20Chris Craik            rectListClip->rect = rectList.calculateBounds();
50869aeabe6184bbbe6e731656205ffbef78b7b0f3fChris Craik            rectListClip->rect.snapToPixelBoundaries();
509e4db79de127cfe961195f52907af8451026eaa20Chris Craik            mLastResolutionResult = rectListClip;
510e4db79de127cfe961195f52907af8451026eaa20Chris Craik        }
511e4db79de127cfe961195f52907af8451026eaa20Chris Craik    }
512e4db79de127cfe961195f52907af8451026eaa20Chris Craik    return mLastResolutionResult;
513e4db79de127cfe961195f52907af8451026eaa20Chris Craik}
514e4db79de127cfe961195f52907af8451026eaa20Chris Craik
515e4db79de127cfe961195f52907af8451026eaa20Chris Craikvoid ClipArea::applyClip(const ClipBase* clip, const Matrix4& transform) {
516e4db79de127cfe961195f52907af8451026eaa20Chris Craik    if (!clip) return; // nothing to do
517e4db79de127cfe961195f52907af8451026eaa20Chris Craik
518e4db79de127cfe961195f52907af8451026eaa20Chris Craik    if (CC_LIKELY(clip->mode == ClipMode::Rectangle)) {
51969aeabe6184bbbe6e731656205ffbef78b7b0f3fChris Craik        clipRectWithTransform(clip->rect, &transform, SkRegion::kIntersect_Op);
520e4db79de127cfe961195f52907af8451026eaa20Chris Craik    } else if (CC_LIKELY(clip->mode == ClipMode::RectangleList)) {
521e4db79de127cfe961195f52907af8451026eaa20Chris Craik        auto&& rectList = getRectList(clip);
522e4db79de127cfe961195f52907af8451026eaa20Chris Craik        for (int i = 0; i < rectList.getTransformedRectanglesCount(); i++) {
523e4db79de127cfe961195f52907af8451026eaa20Chris Craik            auto&& tr = rectList.getTransformedRectangle(i);
524e4db79de127cfe961195f52907af8451026eaa20Chris Craik            Matrix4 totalTransform(transform);
525e4db79de127cfe961195f52907af8451026eaa20Chris Craik            totalTransform.multiply(tr.getTransform());
526e4db79de127cfe961195f52907af8451026eaa20Chris Craik            clipRectWithTransform(tr.getBounds(), &totalTransform, SkRegion::kIntersect_Op);
527e4db79de127cfe961195f52907af8451026eaa20Chris Craik        }
528e4db79de127cfe961195f52907af8451026eaa20Chris Craik    } else {
529e4db79de127cfe961195f52907af8451026eaa20Chris Craik        SkRegion region(getRegion(clip));
530e4db79de127cfe961195f52907af8451026eaa20Chris Craik        // TODO: handle non-translate transforms properly!
531e4db79de127cfe961195f52907af8451026eaa20Chris Craik        region.translate(transform.getTranslateX(), transform.getTranslateY());
532e4db79de127cfe961195f52907af8451026eaa20Chris Craik        clipRegion(region, SkRegion::kIntersect_Op);
533e4db79de127cfe961195f52907af8451026eaa20Chris Craik    }
534e4db79de127cfe961195f52907af8451026eaa20Chris Craik}
535e4db79de127cfe961195f52907af8451026eaa20Chris Craik
536487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk} /* namespace uirenderer */
537487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk} /* namespace android */
538