Snapshot.cpp revision 0c0ec26366045e515790a6acdab782965efc63b4
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()
31        : flags(0)
32        , previous(NULL)
33        , layer(NULL)
34        , fbo(0)
35        , invisible(false)
36        , empty(false)
37        , height(0)
38        , alpha(1.0f) {
39    transform = &mTransformRoot;
40    clipRect = &mClipRectRoot;
41    region = NULL;
42    clipRegion = &mClipRegionRoot;
43}
44
45/**
46 * Copies the specified snapshot/ The specified snapshot is stored as
47 * the previous snapshot.
48 */
49Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags)
50        : flags(0)
51        , previous(s)
52        , layer(s->layer)
53        , fbo(s->fbo)
54        , invisible(s->invisible)
55        , empty(false)
56        , viewport(s->viewport)
57        , height(s->height)
58        , orthoMatrix(s->orthoMatrix)
59        , alpha(s->alpha) {
60
61    if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
62        mTransformRoot.load(*s->transform);
63        transform = &mTransformRoot;
64    } else {
65        transform = s->transform;
66    }
67
68    if (saveFlags & SkCanvas::kClip_SaveFlag) {
69        mClipRectRoot.set(*s->clipRect);
70        clipRect = &mClipRectRoot;
71        if (!s->clipRegion->isEmpty()) {
72            mClipRegionRoot.op(*s->clipRegion, SkRegion::kUnion_Op);
73        }
74        clipRegion = &mClipRegionRoot;
75    } else {
76        clipRect = s->clipRect;
77        clipRegion = s->clipRegion;
78    }
79
80    if (s->flags & Snapshot::kFlagFboTarget) {
81        flags |= Snapshot::kFlagFboTarget;
82        region = s->region;
83    } else {
84        region = NULL;
85    }
86}
87
88///////////////////////////////////////////////////////////////////////////////
89// Clipping
90///////////////////////////////////////////////////////////////////////////////
91
92void Snapshot::ensureClipRegion() {
93    if (clipRegion->isEmpty()) {
94        clipRegion->setRect(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
95    }
96}
97
98void Snapshot::copyClipRectFromRegion() {
99    if (!clipRegion->isEmpty()) {
100        const SkIRect& bounds = clipRegion->getBounds();
101        clipRect->set(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
102
103        if (clipRegion->isRect()) {
104            clipRegion->setEmpty();
105        }
106    } else {
107        clipRect->setEmpty();
108    }
109}
110
111bool Snapshot::clipRegionOp(float left, float top, float right, float bottom, SkRegion::Op op) {
112    SkIRect tmp;
113    tmp.set(left, top, right, bottom);
114    clipRegion->op(tmp, op);
115    copyClipRectFromRegion();
116    return true;
117}
118
119bool Snapshot::clipRegionTransformed(const SkRegion& region, SkRegion::Op op) {
120    ensureClipRegion();
121    clipRegion->op(region, op);
122    copyClipRectFromRegion();
123    flags |= Snapshot::kFlagClipSet;
124    return true;
125}
126
127bool Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) {
128    Rect r(left, top, right, bottom);
129    transform->mapRect(r);
130    return clipTransformed(r, op);
131}
132
133bool Snapshot::clipTransformed(const Rect& r, SkRegion::Op op) {
134    bool clipped = false;
135
136    switch (op) {
137        case SkRegion::kIntersect_Op: {
138            if (CC_UNLIKELY(!clipRegion->isEmpty())) {
139                ensureClipRegion();
140                clipped = clipRegionOp(r.left, r.top, r.right, r.bottom, SkRegion::kIntersect_Op);
141            } else {
142                clipped = clipRect->intersect(r);
143                if (!clipped) {
144                    clipRect->setEmpty();
145                    clipped = true;
146                }
147            }
148            break;
149        }
150        case SkRegion::kReplace_Op: {
151            setClip(r.left, r.top, r.right, r.bottom);
152            clipped = true;
153            break;
154        }
155        default: {
156            ensureClipRegion();
157            clipped = clipRegionOp(r.left, r.top, r.right, r.bottom, op);
158            break;
159        }
160    }
161
162    if (clipped) {
163        flags |= Snapshot::kFlagClipSet;
164    }
165
166    return clipped;
167}
168
169void Snapshot::setClip(float left, float top, float right, float bottom) {
170    clipRect->set(left, top, right, bottom);
171    if (!clipRegion->isEmpty()) {
172        clipRegion->setEmpty();
173    }
174    flags |= Snapshot::kFlagClipSet;
175}
176
177bool Snapshot::hasPerspectiveTransform() const {
178    return transform->isPerspective();
179}
180
181const Rect& Snapshot::getLocalClip() {
182    mat4 inverse;
183    inverse.loadInverse(*transform);
184
185    mLocalClip.set(*clipRect);
186    inverse.mapRect(mLocalClip);
187
188    return mLocalClip;
189}
190
191void Snapshot::resetClip(float left, float top, float right, float bottom) {
192    // TODO: This is incorrect, when we start rendering into a new layer,
193    // we may have to modify the previous snapshot's clip rect and clip
194    // region if the previous restore() call did not restore the clip
195    clipRect = &mClipRectRoot;
196    clipRegion = &mClipRegionRoot;
197    setClip(left, top, right, bottom);
198}
199
200///////////////////////////////////////////////////////////////////////////////
201// Transforms
202///////////////////////////////////////////////////////////////////////////////
203
204void Snapshot::resetTransform(float x, float y, float z) {
205    transform = &mTransformRoot;
206    transform->loadTranslate(x, y, z);
207}
208
209///////////////////////////////////////////////////////////////////////////////
210// Queries
211///////////////////////////////////////////////////////////////////////////////
212
213bool Snapshot::isIgnored() const {
214    return invisible || empty;
215}
216
217void Snapshot::dump() const {
218    ALOGD("Snapshot %p, flags %x, prev %p, height %d, ignored %d, hasComplexClip %d",
219            this, flags, previous.get(), height, isIgnored(), clipRegion && !clipRegion->isEmpty());
220    ALOGD("  ClipRect (at %p) %.1f %.1f %.1f %.1f",
221            clipRect, clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
222    ALOGD("  Transform (at %p):", transform);
223    transform->dump();
224}
225
226}; // namespace uirenderer
227}; // namespace android
228