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.op(*s->clipRegion, SkRegion::kUnion_Op); 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 clipRegion->setRect(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom); 88 } 89 #endif 90 } 91 92 void Snapshot::copyClipRectFromRegion() { 93 #if STENCIL_BUFFER_SIZE 94 if (!clipRegion->isEmpty()) { 95 const SkIRect& bounds = clipRegion->getBounds(); 96 clipRect->set(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom); 97 98 if (clipRegion->isRect()) { 99 clipRegion->setEmpty(); 100 clipRegion = NULL; 101 } 102 } else { 103 clipRect->setEmpty(); 104 clipRegion = NULL; 105 } 106 #endif 107 } 108 109 bool Snapshot::clipRegionOp(float left, float top, float right, float bottom, SkRegion::Op op) { 110 #if STENCIL_BUFFER_SIZE 111 SkIRect tmp; 112 tmp.set(left, top, right, bottom); 113 clipRegion->op(tmp, op); 114 copyClipRectFromRegion(); 115 return true; 116 #else 117 return false; 118 #endif 119 } 120 121 bool Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) { 122 Rect r(left, top, right, bottom); 123 transform->mapRect(r); 124 return clipTransformed(r, op); 125 } 126 127 bool Snapshot::clipTransformed(const Rect& r, SkRegion::Op op) { 128 bool clipped = false; 129 130 switch (op) { 131 case SkRegion::kIntersect_Op: { 132 if (CC_UNLIKELY(clipRegion)) { 133 clipped = clipRegionOp(r.left, r.top, r.right, r.bottom, SkRegion::kIntersect_Op); 134 } else { 135 clipped = clipRect->intersect(r); 136 if (!clipped) { 137 clipRect->setEmpty(); 138 clipped = true; 139 } 140 } 141 break; 142 } 143 case SkRegion::kUnion_Op: { 144 if (CC_UNLIKELY(clipRegion)) { 145 clipped = clipRegionOp(r.left, r.top, r.right, r.bottom, SkRegion::kUnion_Op); 146 } else { 147 clipped = clipRect->unionWith(r); 148 } 149 break; 150 } 151 case SkRegion::kReplace_Op: { 152 setClip(r.left, r.top, r.right, r.bottom); 153 clipped = true; 154 break; 155 } 156 default: { 157 ensureClipRegion(); 158 clipped = clipRegionOp(r.left, r.top, r.right, r.bottom, op); 159 break; 160 } 161 } 162 163 if (clipped) { 164 flags |= Snapshot::kFlagClipSet; 165 } 166 167 return clipped; 168 } 169 170 void Snapshot::setClip(float left, float top, float right, float bottom) { 171 clipRect->set(left, top, right, bottom); 172 #if STENCIL_BUFFER_SIZE 173 if (clipRegion) { 174 clipRegion->setEmpty(); 175 clipRegion = NULL; 176 } 177 #endif 178 flags |= Snapshot::kFlagClipSet; 179 } 180 181 bool Snapshot::hasPerspectiveTransform() const { 182 return transform->isPerspective(); 183 } 184 185 const Rect& Snapshot::getLocalClip() { 186 mat4 inverse; 187 inverse.loadInverse(*transform); 188 189 mLocalClip.set(*clipRect); 190 inverse.mapRect(mLocalClip); 191 192 return mLocalClip; 193 } 194 195 void Snapshot::resetClip(float left, float top, float right, float bottom) { 196 clipRect = &mClipRectRoot; 197 setClip(left, top, right, bottom); 198 } 199 200 /////////////////////////////////////////////////////////////////////////////// 201 // Transforms 202 /////////////////////////////////////////////////////////////////////////////// 203 204 void Snapshot::resetTransform(float x, float y, float z) { 205 transform = &mTransformRoot; 206 transform->loadTranslate(x, y, z); 207 } 208 209 /////////////////////////////////////////////////////////////////////////////// 210 // Queries 211 /////////////////////////////////////////////////////////////////////////////// 212 213 bool Snapshot::isIgnored() const { 214 return invisible || empty; 215 } 216 217 }; // namespace uirenderer 218 }; // namespace android 219