Snapshot.cpp revision 5f803623559aab395a29d575c37c4e39c23a4b4e
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "OpenGLRenderer"
18
19#include "Snapshot.h"
20
21#include <SkCanvas.h>
22
23namespace android {
24namespace uirenderer {
25
26///////////////////////////////////////////////////////////////////////////////
27// Constructors
28///////////////////////////////////////////////////////////////////////////////
29
30Snapshot::Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0),
31        invisible(false), empty(false), alpha(1.0f) {
32
33    transform = &mTransformRoot;
34    clipRect = &mClipRectRoot;
35    region = NULL;
36    clipRegion = &mClipRegionRoot;
37}
38
39/**
40 * Copies the specified snapshot/ The specified snapshot is stored as
41 * the previous snapshot.
42 */
43Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags):
44        flags(0), previous(s), layer(s->layer), fbo(s->fbo),
45        invisible(s->invisible), empty(false),
46        viewport(s->viewport), height(s->height), alpha(s->alpha) {
47
48    if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
49        mTransformRoot.load(*s->transform);
50        transform = &mTransformRoot;
51    } else {
52        transform = s->transform;
53    }
54
55    if (saveFlags & SkCanvas::kClip_SaveFlag) {
56        mClipRectRoot.set(*s->clipRect);
57        clipRect = &mClipRectRoot;
58        if (!s->clipRegion->isEmpty()) {
59            mClipRegionRoot.op(*s->clipRegion, SkRegion::kUnion_Op);
60        }
61        clipRegion = &mClipRegionRoot;
62    } else {
63        clipRect = s->clipRect;
64        clipRegion = s->clipRegion;
65    }
66
67    if (s->flags & Snapshot::kFlagFboTarget) {
68        flags |= Snapshot::kFlagFboTarget;
69        region = s->region;
70    } else {
71        region = NULL;
72    }
73}
74
75///////////////////////////////////////////////////////////////////////////////
76// Clipping
77///////////////////////////////////////////////////////////////////////////////
78
79void Snapshot::ensureClipRegion() {
80    if (clipRegion->isEmpty()) {
81        clipRegion->setRect(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
82    }
83}
84
85void Snapshot::copyClipRectFromRegion() {
86    if (!clipRegion->isEmpty()) {
87        const SkIRect& bounds = clipRegion->getBounds();
88        clipRect->set(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
89
90        if (clipRegion->isRect()) {
91            clipRegion->setEmpty();
92        }
93    } else {
94        clipRect->setEmpty();
95    }
96}
97
98bool Snapshot::clipRegionOp(float left, float top, float right, float bottom, SkRegion::Op op) {
99    SkIRect tmp;
100    tmp.set(left, top, right, bottom);
101    clipRegion->op(tmp, op);
102    copyClipRectFromRegion();
103    return true;
104}
105
106bool Snapshot::clipRegionTransformed(const SkRegion& region, SkRegion::Op op) {
107    ensureClipRegion();
108    clipRegion->op(region, op);
109    copyClipRectFromRegion();
110    flags |= Snapshot::kFlagClipSet;
111    return true;
112}
113
114bool Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) {
115    Rect r(left, top, right, bottom);
116    transform->mapRect(r);
117    return clipTransformed(r, op);
118}
119
120bool Snapshot::clipTransformed(const Rect& r, SkRegion::Op op) {
121    bool clipped = false;
122
123    switch (op) {
124        case SkRegion::kIntersect_Op: {
125            if (CC_UNLIKELY(!clipRegion->isEmpty())) {
126                ensureClipRegion();
127                clipped = clipRegionOp(r.left, r.top, r.right, r.bottom, SkRegion::kIntersect_Op);
128            } else {
129                clipped = clipRect->intersect(r);
130                if (!clipped) {
131                    clipRect->setEmpty();
132                    clipped = true;
133                }
134            }
135            break;
136        }
137        case SkRegion::kReplace_Op: {
138            setClip(r.left, r.top, r.right, r.bottom);
139            clipped = true;
140            break;
141        }
142        default: {
143            ensureClipRegion();
144            clipped = clipRegionOp(r.left, r.top, r.right, r.bottom, op);
145            break;
146        }
147    }
148
149    if (clipped) {
150        flags |= Snapshot::kFlagClipSet;
151    }
152
153    return clipped;
154}
155
156void Snapshot::setClip(float left, float top, float right, float bottom) {
157    clipRect->set(left, top, right, bottom);
158    if (!clipRegion->isEmpty()) {
159        clipRegion->setEmpty();
160    }
161    flags |= Snapshot::kFlagClipSet;
162}
163
164bool Snapshot::hasPerspectiveTransform() const {
165    return transform->isPerspective();
166}
167
168const Rect& Snapshot::getLocalClip() {
169    mat4 inverse;
170    inverse.loadInverse(*transform);
171
172    mLocalClip.set(*clipRect);
173    inverse.mapRect(mLocalClip);
174
175    return mLocalClip;
176}
177
178void Snapshot::resetClip(float left, float top, float right, float bottom) {
179    // TODO: This is incorrect, when we start rendering into a new layer,
180    // we may have to modify the previous snapshot's clip rect and clip
181    // region if the previous restore() call did not restore the clip
182    clipRect = &mClipRectRoot;
183    clipRegion = &mClipRegionRoot;
184    setClip(left, top, right, bottom);
185}
186
187///////////////////////////////////////////////////////////////////////////////
188// Transforms
189///////////////////////////////////////////////////////////////////////////////
190
191void Snapshot::resetTransform(float x, float y, float z) {
192    transform = &mTransformRoot;
193    transform->loadTranslate(x, y, z);
194}
195
196///////////////////////////////////////////////////////////////////////////////
197// Queries
198///////////////////////////////////////////////////////////////////////////////
199
200bool Snapshot::isIgnored() const {
201    return invisible || empty;
202}
203
204void Snapshot::dump() const {
205    ALOGD("Snapshot %p, flags %x, prev %p, height %d, ignored %d, hasComplexClip %d",
206            this, flags, previous.get(), height, isIgnored(), clipRegion && !clipRegion->isEmpty());
207    ALOGD("  ClipRect (at %p) %.1f %.1f %.1f %.1f",
208            clipRect, clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
209    ALOGD("  Transform (at %p):", transform);
210    transform->dump();
211}
212
213}; // namespace uirenderer
214}; // namespace android
215