Snapshot.cpp revision 5e00c7ce063116c11315639f0035aca8ad73e8cc
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 "hwui/Canvas.h" 20 21namespace android { 22namespace uirenderer { 23 24/////////////////////////////////////////////////////////////////////////////// 25// Constructors 26/////////////////////////////////////////////////////////////////////////////// 27 28Snapshot::Snapshot() 29 : flags(0) 30 , previous(nullptr) 31 , layer(nullptr) 32 , fbo(0) 33 , alpha(1.0f) 34 , roundRectClipState(nullptr) 35 , projectionPathMask(nullptr) 36 , mClipArea(&mClipAreaRoot) { 37 transform = &mTransformRoot; 38} 39 40/** 41 * Copies the specified snapshot/ The specified snapshot is stored as 42 * the previous snapshot. 43 */ 44Snapshot::Snapshot(Snapshot* s, int saveFlags) 45 : flags(0) 46 , previous(s) 47 , layer(s->layer) 48 , fbo(s->fbo) 49 , alpha(s->alpha) 50 , roundRectClipState(s->roundRectClipState) 51 , projectionPathMask(s->projectionPathMask) 52 , mClipArea(nullptr) 53 , mViewportData(s->mViewportData) 54 , mRelativeLightCenter(s->mRelativeLightCenter) { 55 if (saveFlags & SaveFlags::Matrix) { 56 mTransformRoot = *s->transform; 57 transform = &mTransformRoot; 58 } else { 59 transform = s->transform; 60 } 61 62 if (saveFlags & SaveFlags::Clip) { 63 mClipAreaRoot = s->getClipArea(); 64 mClipArea = &mClipAreaRoot; 65 } else { 66 mClipArea = s->mClipArea; 67 } 68} 69 70/////////////////////////////////////////////////////////////////////////////// 71// Clipping 72/////////////////////////////////////////////////////////////////////////////// 73 74void Snapshot::clipRegionTransformed(const SkRegion& region, SkRegion::Op op) { 75 flags |= Snapshot::kFlagClipSet; 76 mClipArea->clipRegion(region, op); 77} 78 79void Snapshot::clip(const Rect& localClip, SkRegion::Op op) { 80 flags |= Snapshot::kFlagClipSet; 81 mClipArea->clipRectWithTransform(localClip, transform, op); 82} 83 84void Snapshot::clipPath(const SkPath& path, SkRegion::Op op) { 85 flags |= Snapshot::kFlagClipSet; 86 mClipArea->clipPathWithTransform(path, transform, op); 87} 88 89void Snapshot::setClip(float left, float top, float right, float bottom) { 90 flags |= Snapshot::kFlagClipSet; 91 mClipArea->setClip(left, top, right, bottom); 92} 93 94bool Snapshot::hasPerspectiveTransform() const { 95 return transform->isPerspective(); 96} 97 98const Rect& Snapshot::getLocalClip() { 99 mat4 inverse; 100 inverse.loadInverse(*transform); 101 102 mLocalClip.set(mClipArea->getClipRect()); 103 inverse.mapRect(mLocalClip); 104 105 return mLocalClip; 106} 107 108void Snapshot::resetClip(float left, float top, float right, float bottom) { 109 // TODO: This is incorrect, when we start rendering into a new layer, 110 // we may have to modify the previous snapshot's clip rect and clip 111 // region if the previous restore() call did not restore the clip 112 mClipArea = &mClipAreaRoot; 113 setClip(left, top, right, bottom); 114} 115 116/////////////////////////////////////////////////////////////////////////////// 117// Clipping round rect 118/////////////////////////////////////////////////////////////////////////////// 119 120void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds, 121 float radius, bool highPriority) { 122 if (bounds.isEmpty()) { 123 mClipArea->setEmpty(); 124 return; 125 } 126 127 if (roundRectClipState && roundRectClipState->highPriority) { 128 // ignore, don't replace, already have a high priority clip 129 return; 130 } 131 132 RoundRectClipState* state = new (allocator) RoundRectClipState; 133 134 state->highPriority = highPriority; 135 136 // store the inverse drawing matrix 137 Matrix4 roundRectDrawingMatrix = getOrthoMatrix(); 138 roundRectDrawingMatrix.multiply(*transform); 139 state->matrix.loadInverse(roundRectDrawingMatrix); 140 141 // compute area under rounded corners - only draws overlapping these rects need to be clipped 142 for (int i = 0 ; i < 4; i++) { 143 state->dangerRects[i] = bounds; 144 } 145 state->dangerRects[0].bottom = state->dangerRects[1].bottom = bounds.top + radius; 146 state->dangerRects[0].right = state->dangerRects[2].right = bounds.left + radius; 147 state->dangerRects[1].left = state->dangerRects[3].left = bounds.right - radius; 148 state->dangerRects[2].top = state->dangerRects[3].top = bounds.bottom - radius; 149 for (int i = 0; i < 4; i++) { 150 transform->mapRect(state->dangerRects[i]); 151 152 // round danger rects out as though they are AA geometry (since they essentially are) 153 state->dangerRects[i].snapGeometryToPixelBoundaries(true); 154 } 155 156 // store RR area 157 state->innerRect = bounds; 158 state->innerRect.inset(radius); 159 state->radius = radius; 160 161 // store as immutable so, for this frame, pointer uniquely identifies this bundle of shader info 162 roundRectClipState = state; 163} 164 165void Snapshot::setProjectionPathMask(const SkPath* path) { 166 projectionPathMask = path; 167} 168 169static Snapshot* getClipRoot(Snapshot* target) { 170 while (target->previous && target->previous->previous) { 171 target = target->previous; 172 } 173 return target; 174} 175 176const ClipBase* Snapshot::serializeIntersectedClip(LinearAllocator& allocator, 177 const ClipBase* recordedClip, const Matrix4& recordedClipTransform) { 178 auto target = this; 179 if (CC_UNLIKELY(recordedClip && recordedClip->intersectWithRoot)) { 180 // Clip must be intersected with root, instead of current clip. 181 target = getClipRoot(this); 182 } 183 184 return target->mClipArea->serializeIntersectedClip(allocator, 185 recordedClip, recordedClipTransform); 186} 187 188void Snapshot::applyClip(const ClipBase* recordedClip, const Matrix4& transform) { 189 if (CC_UNLIKELY(recordedClip && recordedClip->intersectWithRoot)) { 190 // current clip is being replaced, but must intersect with clip root 191 *mClipArea = *(getClipRoot(this)->mClipArea); 192 } 193 mClipArea->applyClip(recordedClip, transform); 194} 195 196/////////////////////////////////////////////////////////////////////////////// 197// Queries 198/////////////////////////////////////////////////////////////////////////////// 199 200void Snapshot::dump() const { 201 ALOGD("Snapshot %p, flags %x, prev %p, height %d, hasComplexClip %d", 202 this, flags, previous, getViewportHeight(), !mClipArea->isSimple()); 203 const Rect& clipRect(mClipArea->getClipRect()); 204 ALOGD(" ClipRect %.1f %.1f %.1f %.1f, clip simple %d", 205 clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, mClipArea->isSimple()); 206 207 ALOGD(" Transform (at %p):", transform); 208 transform->dump(); 209} 210 211}; // namespace uirenderer 212}; // namespace android 213