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#include "Snapshot.h" 18 19#include <SkCanvas.h> 20 21namespace android { 22namespace uirenderer { 23 24/////////////////////////////////////////////////////////////////////////////// 25// Constructors 26/////////////////////////////////////////////////////////////////////////////// 27 28Snapshot::Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0), 29 invisible(false), empty(false), alpha(1.0f) { 30 31 transform = &mTransformRoot; 32 clipRect = &mClipRectRoot; 33 region = NULL; 34 clipRegion = NULL; 35} 36 37/** 38 * Copies the specified snapshot/ The specified snapshot is stored as 39 * the previous snapshot. 40 */ 41Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags): 42 flags(0), previous(s), layer(NULL), fbo(s->fbo), 43 invisible(s->invisible), empty(false), 44 viewport(s->viewport), height(s->height), alpha(s->alpha) { 45 46 clipRegion = NULL; 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 STENCIL_BUFFER_SIZE 59 if (s->clipRegion) { 60 mClipRegionRoot.merge(*s->clipRegion); 61 clipRegion = &mClipRegionRoot; 62 } 63#endif 64 } else { 65 clipRect = s->clipRect; 66#if STENCIL_BUFFER_SIZE 67 clipRegion = s->clipRegion; 68#endif 69 } 70 71 if (s->flags & Snapshot::kFlagFboTarget) { 72 flags |= Snapshot::kFlagFboTarget; 73 region = s->region; 74 } else { 75 region = NULL; 76 } 77} 78 79/////////////////////////////////////////////////////////////////////////////// 80// Clipping 81/////////////////////////////////////////////////////////////////////////////// 82 83void Snapshot::ensureClipRegion() { 84#if STENCIL_BUFFER_SIZE 85 if (!clipRegion) { 86 clipRegion = &mClipRegionRoot; 87 android::Rect tmp(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom); 88 clipRegion->set(tmp); 89 } 90#endif 91} 92 93void Snapshot::copyClipRectFromRegion() { 94#if STENCIL_BUFFER_SIZE 95 if (!clipRegion->isEmpty()) { 96 android::Rect bounds(clipRegion->bounds()); 97 clipRect->set(bounds.left, bounds.top, bounds.right, bounds.bottom); 98 99 if (clipRegion->isRect()) { 100 clipRegion->clear(); 101 clipRegion = NULL; 102 } 103 } else { 104 clipRect->setEmpty(); 105 clipRegion = NULL; 106 } 107#endif 108} 109 110bool Snapshot::clipRegionOr(float left, float top, float right, float bottom) { 111#if STENCIL_BUFFER_SIZE 112 android::Rect tmp(left, top, right, bottom); 113 clipRegion->orSelf(tmp); 114 copyClipRectFromRegion(); 115 return true; 116#else 117 return false; 118#endif 119} 120 121bool Snapshot::clipRegionXor(float left, float top, float right, float bottom) { 122#if STENCIL_BUFFER_SIZE 123 android::Rect tmp(left, top, right, bottom); 124 clipRegion->xorSelf(tmp); 125 copyClipRectFromRegion(); 126 return true; 127#else 128 return false; 129#endif 130} 131 132bool Snapshot::clipRegionAnd(float left, float top, float right, float bottom) { 133#if STENCIL_BUFFER_SIZE 134 android::Rect tmp(left, top, right, bottom); 135 clipRegion->andSelf(tmp); 136 copyClipRectFromRegion(); 137 return true; 138#else 139 return false; 140#endif 141} 142 143bool Snapshot::clipRegionNand(float left, float top, float right, float bottom) { 144#if STENCIL_BUFFER_SIZE 145 android::Rect tmp(left, top, right, bottom); 146 clipRegion->subtractSelf(tmp); 147 copyClipRectFromRegion(); 148 return true; 149#else 150 return false; 151#endif 152} 153 154bool Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) { 155 Rect r(left, top, right, bottom); 156 transform->mapRect(r); 157 return clipTransformed(r, op); 158} 159 160bool Snapshot::clipTransformed(const Rect& r, SkRegion::Op op) { 161 bool clipped = false; 162 163 switch (op) { 164 case SkRegion::kDifference_Op: { 165 ensureClipRegion(); 166 clipped = clipRegionNand(r.left, r.top, r.right, r.bottom); 167 break; 168 } 169 case SkRegion::kIntersect_Op: { 170 if (CC_UNLIKELY(clipRegion)) { 171 clipped = clipRegionOr(r.left, r.top, r.right, r.bottom); 172 } else { 173 clipped = clipRect->intersect(r); 174 if (!clipped) { 175 clipRect->setEmpty(); 176 clipped = true; 177 } 178 } 179 break; 180 } 181 case SkRegion::kUnion_Op: { 182 if (CC_UNLIKELY(clipRegion)) { 183 clipped = clipRegionAnd(r.left, r.top, r.right, r.bottom); 184 } else { 185 clipped = clipRect->unionWith(r); 186 } 187 break; 188 } 189 case SkRegion::kXOR_Op: { 190 ensureClipRegion(); 191 clipped = clipRegionXor(r.left, r.top, r.right, r.bottom); 192 break; 193 } 194 case SkRegion::kReverseDifference_Op: { 195 // TODO!!!!!!! 196 break; 197 } 198 case SkRegion::kReplace_Op: { 199 setClip(r.left, r.top, r.right, r.bottom); 200 clipped = true; 201 break; 202 } 203 } 204 205 if (clipped) { 206 flags |= Snapshot::kFlagClipSet; 207 } 208 209 return clipped; 210} 211 212void Snapshot::setClip(float left, float top, float right, float bottom) { 213 clipRect->set(left, top, right, bottom); 214#if STENCIL_BUFFER_SIZE 215 if (clipRegion) { 216 clipRegion->clear(); 217 clipRegion = NULL; 218 } 219#endif 220 flags |= Snapshot::kFlagClipSet; 221} 222 223const Rect& Snapshot::getLocalClip() { 224 mat4 inverse; 225 inverse.loadInverse(*transform); 226 227 mLocalClip.set(*clipRect); 228 inverse.mapRect(mLocalClip); 229 230 return mLocalClip; 231} 232 233void Snapshot::resetClip(float left, float top, float right, float bottom) { 234 clipRect = &mClipRectRoot; 235 setClip(left, top, right, bottom); 236} 237 238/////////////////////////////////////////////////////////////////////////////// 239// Transforms 240/////////////////////////////////////////////////////////////////////////////// 241 242void Snapshot::resetTransform(float x, float y, float z) { 243 transform = &mTransformRoot; 244 transform->loadTranslate(x, y, z); 245} 246 247/////////////////////////////////////////////////////////////////////////////// 248// Queries 249/////////////////////////////////////////////////////////////////////////////// 250 251bool Snapshot::isIgnored() const { 252 return invisible || empty; 253} 254 255}; // namespace uirenderer 256}; // namespace android 257