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