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