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 23 namespace android { 24 namespace uirenderer { 25 26 /////////////////////////////////////////////////////////////////////////////// 27 // Constructors 28 /////////////////////////////////////////////////////////////////////////////// 29 30 Snapshot::Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0), 31 invisible(false), empty(false), alpha(1.0f) { 32 33 transform = &mTransformRoot; 34 clipRect = &mClipRectRoot; 35 region = NULL; 36 clipRegion = &mClipRegionRoot; 37 } 38 39 /** 40 * Copies the specified snapshot/ The specified snapshot is stored as 41 * the previous snapshot. 42 */ 43 Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags): 44 flags(0), previous(s), layer(s->layer), fbo(s->fbo), 45 invisible(s->invisible), empty(false), 46 viewport(s->viewport), height(s->height), alpha(s->alpha) { 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 (!s->clipRegion->isEmpty()) { 59 mClipRegionRoot.op(*s->clipRegion, SkRegion::kUnion_Op); 60 } 61 clipRegion = &mClipRegionRoot; 62 } else { 63 clipRect = s->clipRect; 64 clipRegion = s->clipRegion; 65 } 66 67 if (s->flags & Snapshot::kFlagFboTarget) { 68 flags |= Snapshot::kFlagFboTarget; 69 region = s->region; 70 } else { 71 region = NULL; 72 } 73 } 74 75 /////////////////////////////////////////////////////////////////////////////// 76 // Clipping 77 /////////////////////////////////////////////////////////////////////////////// 78 79 void Snapshot::ensureClipRegion() { 80 if (clipRegion->isEmpty()) { 81 clipRegion->setRect(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom); 82 } 83 } 84 85 void Snapshot::copyClipRectFromRegion() { 86 if (!clipRegion->isEmpty()) { 87 const SkIRect& bounds = clipRegion->getBounds(); 88 clipRect->set(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom); 89 90 if (clipRegion->isRect()) { 91 clipRegion->setEmpty(); 92 } 93 } else { 94 clipRect->setEmpty(); 95 } 96 } 97 98 bool Snapshot::clipRegionOp(float left, float top, float right, float bottom, SkRegion::Op op) { 99 SkIRect tmp; 100 tmp.set(left, top, right, bottom); 101 clipRegion->op(tmp, op); 102 copyClipRectFromRegion(); 103 return true; 104 } 105 106 bool Snapshot::clipRegionTransformed(const SkRegion& region, SkRegion::Op op) { 107 ensureClipRegion(); 108 clipRegion->op(region, op); 109 copyClipRectFromRegion(); 110 flags |= Snapshot::kFlagClipSet; 111 return true; 112 } 113 114 bool Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) { 115 Rect r(left, top, right, bottom); 116 transform->mapRect(r); 117 return clipTransformed(r, op); 118 } 119 120 bool Snapshot::clipTransformed(const Rect& r, SkRegion::Op op) { 121 bool clipped = false; 122 123 switch (op) { 124 case SkRegion::kIntersect_Op: { 125 if (CC_UNLIKELY(!clipRegion->isEmpty())) { 126 ensureClipRegion(); 127 clipped = clipRegionOp(r.left, r.top, r.right, r.bottom, SkRegion::kIntersect_Op); 128 } else { 129 clipped = clipRect->intersect(r); 130 if (!clipped) { 131 clipRect->setEmpty(); 132 clipped = true; 133 } 134 } 135 break; 136 } 137 case SkRegion::kReplace_Op: { 138 setClip(r.left, r.top, r.right, r.bottom); 139 clipped = true; 140 break; 141 } 142 default: { 143 ensureClipRegion(); 144 clipped = clipRegionOp(r.left, r.top, r.right, r.bottom, op); 145 break; 146 } 147 } 148 149 if (clipped) { 150 flags |= Snapshot::kFlagClipSet; 151 } 152 153 return clipped; 154 } 155 156 void Snapshot::setClip(float left, float top, float right, float bottom) { 157 clipRect->set(left, top, right, bottom); 158 if (!clipRegion->isEmpty()) { 159 clipRegion->setEmpty(); 160 } 161 flags |= Snapshot::kFlagClipSet; 162 } 163 164 bool Snapshot::hasPerspectiveTransform() const { 165 return transform->isPerspective(); 166 } 167 168 const Rect& Snapshot::getLocalClip() { 169 mat4 inverse; 170 inverse.loadInverse(*transform); 171 172 mLocalClip.set(*clipRect); 173 inverse.mapRect(mLocalClip); 174 175 return mLocalClip; 176 } 177 178 void Snapshot::resetClip(float left, float top, float right, float bottom) { 179 // TODO: This is incorrect, when we start rendering into a new layer, 180 // we may have to modify the previous snapshot's clip rect and clip 181 // region if the previous restore() call did not restore the clip 182 clipRect = &mClipRectRoot; 183 clipRegion = &mClipRegionRoot; 184 setClip(left, top, right, bottom); 185 } 186 187 /////////////////////////////////////////////////////////////////////////////// 188 // Transforms 189 /////////////////////////////////////////////////////////////////////////////// 190 191 void Snapshot::resetTransform(float x, float y, float z) { 192 transform = &mTransformRoot; 193 transform->loadTranslate(x, y, z); 194 } 195 196 /////////////////////////////////////////////////////////////////////////////// 197 // Queries 198 /////////////////////////////////////////////////////////////////////////////// 199 200 bool Snapshot::isIgnored() const { 201 return invisible || empty; 202 } 203 204 void Snapshot::dump() const { 205 ALOGD("Snapshot %p, flags %x, prev %p, height %d, ignored %d, hasComplexClip %d", 206 this, flags, previous.get(), height, isIgnored(), clipRegion && !clipRegion->isEmpty()); 207 ALOGD(" ClipRect (at %p) %.1f %.1f %.1f %.1f", 208 clipRect, clipRect->left, clipRect->top, clipRect->right, clipRect->bottom); 209 ALOGD(" Transform (at %p):", transform); 210 transform->dump(); 211 } 212 213 }; // namespace uirenderer 214 }; // namespace android 215