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 21 namespace android { 22 namespace uirenderer { 23 24 /////////////////////////////////////////////////////////////////////////////// 25 // Constructors 26 /////////////////////////////////////////////////////////////////////////////// 27 28 Snapshot::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 */ 41 Snapshot::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 83 void 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 93 void 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 110 bool 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 121 bool 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 132 bool 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 143 bool 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 154 bool 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 160 bool 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 212 void 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 223 const 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 233 void 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 242 void Snapshot::resetTransform(float x, float y, float z) { 243 transform = &mTransformRoot; 244 transform->loadTranslate(x, y, z); 245 } 246 247 /////////////////////////////////////////////////////////////////////////////// 248 // Queries 249 /////////////////////////////////////////////////////////////////////////////// 250 251 bool Snapshot::isIgnored() const { 252 return invisible || empty; 253 } 254 255 }; // namespace uirenderer 256 }; // namespace android 257