/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_HWUI_SNAPSHOT_H #define ANDROID_HWUI_SNAPSHOT_H #include #include #include #include #include #include "Layer.h" #include "Matrix.h" #include "Rect.h" namespace android { namespace uirenderer { /** * A snapshot holds information about the current state of the rendering * surface. A snapshot is usually created whenever the user calls save() * and discarded when the user calls restore(). Once a snapshot is created, * it can hold information for deferred rendering. * * Each snapshot has a link to a previous snapshot, indicating the previous * state of the renderer. */ class Snapshot: public LightRefBase { public: Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0), invisible(false) { transform = &mTransformRoot; clipRect = &mClipRectRoot; region = NULL; } /** * Copies the specified snapshot/ The specified snapshot is stored as * the previous snapshot. */ Snapshot(const sp& s, int saveFlags): flags(0), previous(s), layer(NULL), fbo(s->fbo), invisible(s->invisible), viewport(s->viewport), height(s->height) { if (saveFlags & SkCanvas::kMatrix_SaveFlag) { mTransformRoot.load(*s->transform); transform = &mTransformRoot; } else { transform = s->transform; } if (saveFlags & SkCanvas::kClip_SaveFlag) { mClipRectRoot.set(*s->clipRect); clipRect = &mClipRectRoot; } else { clipRect = s->clipRect; } if ((s->flags & Snapshot::kFlagClipSet) && !(s->flags & Snapshot::kFlagDirtyLocalClip)) { mLocalClip.set(s->mLocalClip); } else { flags |= Snapshot::kFlagDirtyLocalClip; } if (s->flags & Snapshot::kFlagFboTarget) { flags |= Snapshot::kFlagFboTarget; region = s->region; } else { region = NULL; } } /** * Various flags set on #flags. */ enum Flags { /** * Indicates that the clip region was modified. When this * snapshot is restored so must the clip. */ kFlagClipSet = 0x1, /** * Indicates that this snapshot was created when saving * a new layer. */ kFlagIsLayer = 0x2, /** * Indicates that this snapshot is a special type of layer * backed by an FBO. This flag only makes sense when the * flag kFlagIsLayer is also set. */ kFlagIsFboLayer = 0x4, /** * Indicates that the local clip should be recomputed. */ kFlagDirtyLocalClip = 0x8, /** * Indicates that this snapshot has changed the ortho matrix. */ kFlagDirtyOrtho = 0x10, /** * Indicates that this snapshot or an ancestor snapshot is * an FBO layer. */ kFlagFboTarget = 0x20 }; /** * Modifies the current clip with the new clip rectangle and * the specified operation. The specified rectangle is transformed * by this snapshot's trasnformation. */ bool clip(float left, float top, float right, float bottom, SkRegion::Op op = SkRegion::kIntersect_Op) { Rect r(left, top, right, bottom); transform->mapRect(r); return clipTransformed(r, op); } /** * Modifies the current clip with the new clip rectangle and * the specified operation. The specified rectangle is considered * already transformed. */ bool clipTransformed(const Rect& r, SkRegion::Op op = SkRegion::kIntersect_Op) { bool clipped = false; // NOTE: The unimplemented operations require support for regions // Supporting regions would require using a stencil buffer instead // of the scissor. The stencil buffer itself is not too expensive // (memory cost excluded) but on fillrate limited devices, managing // the stencil might have a negative impact on the framerate. switch (op) { case SkRegion::kDifference_Op: break; case SkRegion::kIntersect_Op: clipped = clipRect->intersect(r); break; case SkRegion::kUnion_Op: clipped = clipRect->unionWith(r); break; case SkRegion::kXOR_Op: break; case SkRegion::kReverseDifference_Op: break; case SkRegion::kReplace_Op: clipRect->set(r); clipped = true; break; } if (clipped) { flags |= Snapshot::kFlagClipSet | Snapshot::kFlagDirtyLocalClip; } return clipped; } /** * Sets the current clip. */ void setClip(float left, float top, float right, float bottom) { clipRect->set(left, top, right, bottom); flags |= Snapshot::kFlagClipSet | Snapshot::kFlagDirtyLocalClip; } const Rect& getLocalClip() { if (flags & Snapshot::kFlagDirtyLocalClip) { mat4 inverse; inverse.loadInverse(*transform); mLocalClip.set(*clipRect); inverse.mapRect(mLocalClip); flags &= ~Snapshot::kFlagDirtyLocalClip; } return mLocalClip; } void resetTransform(float x, float y, float z) { transform = &mTransformRoot; transform->loadTranslate(x, y, z); } void resetClip(float left, float top, float right, float bottom) { clipRect = &mClipRectRoot; clipRect->set(left, top, right, bottom); flags |= Snapshot::kFlagClipSet | Snapshot::kFlagDirtyLocalClip; } /** * Dirty flags. */ int flags; /** * Previous snapshot. */ sp previous; /** * Only set when the flag kFlagIsLayer is set. */ Layer* layer; /** * Only set when the flag kFlagIsFboLayer is set. */ GLuint fbo; /** * Indicates that this snapshot is invisible and nothing should be drawn * inside it. */ bool invisible; /** * Current viewport. */ Rect viewport; /** * Height of the framebuffer the snapshot is rendering into. */ int height; /** * Contains the previous ortho matrix. */ mat4 orthoMatrix; /** * Local transformation. Holds the current translation, scale and * rotation values. */ mat4* transform; /** * Current clip region. The clip is stored in canvas-space coordinates, * (screen-space coordinates in the regular case.) */ Rect* clipRect; /** * The ancestor layer's dirty region.. */ Region* region; private: mat4 mTransformRoot; Rect mClipRectRoot; Rect mLocalClip; }; // class Snapshot }; // namespace uirenderer }; // namespace android #endif // ANDROID_HWUI_SNAPSHOT_H