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