1e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck/* 2e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck * Copyright (C) 2014 The Android Open Source Project 3e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck * 4e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck * Licensed under the Apache License, Version 2.0 (the "License"); 5e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck * you may not use this file except in compliance with the License. 6e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck * You may obtain a copy of the License at 7e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck * 8e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck * http://www.apache.org/licenses/LICENSE-2.0 9e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck * 10e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck * Unless required by applicable law or agreed to in writing, software 11e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck * distributed under the License is distributed on an "AS IS" BASIS, 12e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck * See the License for the specific language governing permissions and 14e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck * limitations under the License. 15e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck */ 16e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck 17e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck#include "DamageAccumulator.h" 18e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck 1952eb4e01a49fe2e94555c000de38bbcbbb13401bMark Salyzyn#include <log/log.h> 20e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck 21e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck#include "RenderNode.h" 22e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck#include "utils/MathUtils.h" 23e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck 24e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Recknamespace android { 25e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Recknamespace uirenderer { 26e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck 27a447d29c65fb811cd184775a3476101a1cede929John Reckenum TransformType { 282dc223d23764a78f052529e86a59a1979d03b811John Reck TransformInvalid = 0, 29a447d29c65fb811cd184775a3476101a1cede929John Reck TransformRenderNode, 30a447d29c65fb811cd184775a3476101a1cede929John Reck TransformMatrix4, 3125fbb3fa1138675379102a44405852555cefccbdJohn Reck TransformNone, 32a447d29c65fb811cd184775a3476101a1cede929John Reck}; 33a447d29c65fb811cd184775a3476101a1cede929John Reck 34e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reckstruct DirtyStack { 35a447d29c65fb811cd184775a3476101a1cede929John Reck TransformType type; 36a447d29c65fb811cd184775a3476101a1cede929John Reck union { 37a447d29c65fb811cd184775a3476101a1cede929John Reck const RenderNode* renderNode; 38a447d29c65fb811cd184775a3476101a1cede929John Reck const Matrix4* matrix4; 39a447d29c65fb811cd184775a3476101a1cede929John Reck }; 40e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck // When this frame is pop'd, this rect is mapped through the above transform 41e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck // and applied to the previous (aka parent) frame 42e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck SkRect pendingDirty; 43e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck DirtyStack* prev; 44e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck DirtyStack* next; 45e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck}; 46e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck 47e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn ReckDamageAccumulator::DamageAccumulator() { 487df9ff2a08fd4bbd9b2e734a357cffcf64675df9John Reck mHead = mAllocator.create_trivial<DirtyStack>(); 49e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck memset(mHead, 0, sizeof(DirtyStack)); 50e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck // Create a root that we will not pop off 51e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck mHead->prev = mHead; 522dc223d23764a78f052529e86a59a1979d03b811John Reck mHead->type = TransformNone; 53e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck} 54e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck 5569e5adffb19135d51bde8e458f4907d7265f3e23Chris Craikstatic void computeTransformImpl(const DirtyStack* currentFrame, Matrix4* outMatrix) { 5669e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik if (currentFrame->prev != currentFrame) { 5769e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik computeTransformImpl(currentFrame->prev, outMatrix); 5869e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik } 5969e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik switch (currentFrame->type) { 601bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck case TransformRenderNode: 611bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck currentFrame->renderNode->applyViewPropertyTransforms(*outMatrix); 621bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck break; 631bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck case TransformMatrix4: 641bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck outMatrix->multiply(*currentFrame->matrix4); 651bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck break; 661bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck case TransformNone: 671bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck // nothing to be done 681bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck break; 691bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck default: 701bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck LOG_ALWAYS_FATAL("Tried to compute transform with an invalid type: %d", 711bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck currentFrame->type); 7269e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik } 7369e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik} 7469e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik 7569e5adffb19135d51bde8e458f4907d7265f3e23Chris Craikvoid DamageAccumulator::computeCurrentTransform(Matrix4* outMatrix) const { 7669e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik outMatrix->loadIdentity(); 7769e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik computeTransformImpl(mHead, outMatrix); 7869e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik} 7969e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik 80a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::pushCommon() { 81e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck if (!mHead->next) { 827df9ff2a08fd4bbd9b2e734a357cffcf64675df9John Reck DirtyStack* nextFrame = mAllocator.create_trivial<DirtyStack>(); 83d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik nextFrame->next = nullptr; 84e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck nextFrame->prev = mHead; 85e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck mHead->next = nextFrame; 86e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck } 87e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck mHead = mHead->next; 88e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck mHead->pendingDirty.setEmpty(); 89e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck} 90e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck 91a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::pushTransform(const RenderNode* transform) { 92a447d29c65fb811cd184775a3476101a1cede929John Reck pushCommon(); 93a447d29c65fb811cd184775a3476101a1cede929John Reck mHead->type = TransformRenderNode; 94a447d29c65fb811cd184775a3476101a1cede929John Reck mHead->renderNode = transform; 95a447d29c65fb811cd184775a3476101a1cede929John Reck} 96a447d29c65fb811cd184775a3476101a1cede929John Reck 97a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::pushTransform(const Matrix4* transform) { 98a447d29c65fb811cd184775a3476101a1cede929John Reck pushCommon(); 99a447d29c65fb811cd184775a3476101a1cede929John Reck mHead->type = TransformMatrix4; 100a447d29c65fb811cd184775a3476101a1cede929John Reck mHead->matrix4 = transform; 101a447d29c65fb811cd184775a3476101a1cede929John Reck} 102a447d29c65fb811cd184775a3476101a1cede929John Reck 103a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::popTransform() { 104e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck LOG_ALWAYS_FATAL_IF(mHead->prev == mHead, "Cannot pop the root frame!"); 105e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck DirtyStack* dirtyFrame = mHead; 106e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck mHead = mHead->prev; 10725fbb3fa1138675379102a44405852555cefccbdJohn Reck switch (dirtyFrame->type) { 1081bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck case TransformRenderNode: 1091bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck applyRenderNodeTransform(dirtyFrame); 1101bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck break; 1111bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck case TransformMatrix4: 1121bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck applyMatrix4Transform(dirtyFrame); 1131bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck break; 1141bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck case TransformNone: 1151bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck mHead->pendingDirty.join(dirtyFrame->pendingDirty); 1161bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck break; 1171bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck default: 1181bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck LOG_ALWAYS_FATAL("Tried to pop an invalid type: %d", dirtyFrame->type); 119a447d29c65fb811cd184775a3476101a1cede929John Reck } 120a447d29c65fb811cd184775a3476101a1cede929John Reck} 121a447d29c65fb811cd184775a3476101a1cede929John Reck 122a447d29c65fb811cd184775a3476101a1cede929John Reckstatic inline void mapRect(const Matrix4* matrix, const SkRect& in, SkRect* out) { 123a447d29c65fb811cd184775a3476101a1cede929John Reck if (in.isEmpty()) return; 124a447d29c65fb811cd184775a3476101a1cede929John Reck Rect temp(in); 125c128823940fb0be96eda810fa9f0c75f66d944b0John Reck if (CC_LIKELY(!matrix->isPerspective())) { 126c128823940fb0be96eda810fa9f0c75f66d944b0John Reck matrix->mapRect(temp); 127c128823940fb0be96eda810fa9f0c75f66d944b0John Reck } else { 128c128823940fb0be96eda810fa9f0c75f66d944b0John Reck // Don't attempt to calculate damage for a perspective transform 129c128823940fb0be96eda810fa9f0c75f66d944b0John Reck // as the numbers this works with can break the perspective 130c128823940fb0be96eda810fa9f0c75f66d944b0John Reck // calculations. Just give up and expand to DIRTY_MIN/DIRTY_MAX 131c128823940fb0be96eda810fa9f0c75f66d944b0John Reck temp.set(DIRTY_MIN, DIRTY_MIN, DIRTY_MAX, DIRTY_MAX); 132c128823940fb0be96eda810fa9f0c75f66d944b0John Reck } 133a447d29c65fb811cd184775a3476101a1cede929John Reck out->join(RECT_ARGS(temp)); 134a447d29c65fb811cd184775a3476101a1cede929John Reck} 135a447d29c65fb811cd184775a3476101a1cede929John Reck 136a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::applyMatrix4Transform(DirtyStack* frame) { 137a447d29c65fb811cd184775a3476101a1cede929John Reck mapRect(frame->matrix4, frame->pendingDirty, &mHead->pendingDirty); 138a447d29c65fb811cd184775a3476101a1cede929John Reck} 139a447d29c65fb811cd184775a3476101a1cede929John Reck 140a447d29c65fb811cd184775a3476101a1cede929John Reckstatic inline void mapRect(const RenderProperties& props, const SkRect& in, SkRect* out) { 141a447d29c65fb811cd184775a3476101a1cede929John Reck if (in.isEmpty()) return; 142a447d29c65fb811cd184775a3476101a1cede929John Reck const SkMatrix* transform = props.getTransformMatrix(); 143a447d29c65fb811cd184775a3476101a1cede929John Reck SkRect temp(in); 144a447d29c65fb811cd184775a3476101a1cede929John Reck if (transform && !transform->isIdentity()) { 145c128823940fb0be96eda810fa9f0c75f66d944b0John Reck if (CC_LIKELY(!transform->hasPerspective())) { 146c128823940fb0be96eda810fa9f0c75f66d944b0John Reck transform->mapRect(&temp); 147c128823940fb0be96eda810fa9f0c75f66d944b0John Reck } else { 148c128823940fb0be96eda810fa9f0c75f66d944b0John Reck // Don't attempt to calculate damage for a perspective transform 149c128823940fb0be96eda810fa9f0c75f66d944b0John Reck // as the numbers this works with can break the perspective 150c128823940fb0be96eda810fa9f0c75f66d944b0John Reck // calculations. Just give up and expand to DIRTY_MIN/DIRTY_MAX 151c128823940fb0be96eda810fa9f0c75f66d944b0John Reck temp.set(DIRTY_MIN, DIRTY_MIN, DIRTY_MAX, DIRTY_MAX); 152c128823940fb0be96eda810fa9f0c75f66d944b0John Reck } 153a447d29c65fb811cd184775a3476101a1cede929John Reck } 154a447d29c65fb811cd184775a3476101a1cede929John Reck temp.offset(props.getLeft(), props.getTop()); 155a447d29c65fb811cd184775a3476101a1cede929John Reck out->join(temp); 156a447d29c65fb811cd184775a3476101a1cede929John Reck} 157a447d29c65fb811cd184775a3476101a1cede929John Reck 158a447d29c65fb811cd184775a3476101a1cede929John Reckstatic DirtyStack* findParentRenderNode(DirtyStack* frame) { 159a447d29c65fb811cd184775a3476101a1cede929John Reck while (frame->prev != frame) { 160a447d29c65fb811cd184775a3476101a1cede929John Reck frame = frame->prev; 161a447d29c65fb811cd184775a3476101a1cede929John Reck if (frame->type == TransformRenderNode) { 162a447d29c65fb811cd184775a3476101a1cede929John Reck return frame; 163e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck } 164a447d29c65fb811cd184775a3476101a1cede929John Reck } 165d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik return nullptr; 166a447d29c65fb811cd184775a3476101a1cede929John Reck} 167a447d29c65fb811cd184775a3476101a1cede929John Reck 168a447d29c65fb811cd184775a3476101a1cede929John Reckstatic DirtyStack* findProjectionReceiver(DirtyStack* frame) { 169a447d29c65fb811cd184775a3476101a1cede929John Reck if (frame) { 170a447d29c65fb811cd184775a3476101a1cede929John Reck while (frame->prev != frame) { 171a447d29c65fb811cd184775a3476101a1cede929John Reck frame = frame->prev; 1721bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck if (frame->type == TransformRenderNode && frame->renderNode->hasProjectionReceiver()) { 173a447d29c65fb811cd184775a3476101a1cede929John Reck return frame; 174e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck } 175a447d29c65fb811cd184775a3476101a1cede929John Reck } 176a447d29c65fb811cd184775a3476101a1cede929John Reck } 177d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik return nullptr; 178a447d29c65fb811cd184775a3476101a1cede929John Reck} 179a447d29c65fb811cd184775a3476101a1cede929John Reck 180a447d29c65fb811cd184775a3476101a1cede929John Reckstatic void applyTransforms(DirtyStack* frame, DirtyStack* end) { 181a447d29c65fb811cd184775a3476101a1cede929John Reck SkRect* rect = &frame->pendingDirty; 182a447d29c65fb811cd184775a3476101a1cede929John Reck while (frame != end) { 183a447d29c65fb811cd184775a3476101a1cede929John Reck if (frame->type == TransformRenderNode) { 184a447d29c65fb811cd184775a3476101a1cede929John Reck mapRect(frame->renderNode->properties(), *rect, rect); 185a447d29c65fb811cd184775a3476101a1cede929John Reck } else { 186a447d29c65fb811cd184775a3476101a1cede929John Reck mapRect(frame->matrix4, *rect, rect); 187a447d29c65fb811cd184775a3476101a1cede929John Reck } 188a447d29c65fb811cd184775a3476101a1cede929John Reck frame = frame->prev; 189a447d29c65fb811cd184775a3476101a1cede929John Reck } 190a447d29c65fb811cd184775a3476101a1cede929John Reck} 191a447d29c65fb811cd184775a3476101a1cede929John Reck 192a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::applyRenderNodeTransform(DirtyStack* frame) { 193a447d29c65fb811cd184775a3476101a1cede929John Reck if (frame->pendingDirty.isEmpty()) { 194a447d29c65fb811cd184775a3476101a1cede929John Reck return; 195a447d29c65fb811cd184775a3476101a1cede929John Reck } 196a447d29c65fb811cd184775a3476101a1cede929John Reck 197a447d29c65fb811cd184775a3476101a1cede929John Reck const RenderProperties& props = frame->renderNode->properties(); 198ce9f308063cc2bc7851f3f58c881da8a7271eeccJohn Reck if (props.getAlpha() <= 0) { 199ce9f308063cc2bc7851f3f58c881da8a7271eeccJohn Reck return; 200ce9f308063cc2bc7851f3f58c881da8a7271eeccJohn Reck } 201a447d29c65fb811cd184775a3476101a1cede929John Reck 202a447d29c65fb811cd184775a3476101a1cede929John Reck // Perform clipping 203293e868bfc1b07aad2cb2ebeee5b07424852c510John Reck if (props.getClipDamageToBounds() && !frame->pendingDirty.isEmpty()) { 204a447d29c65fb811cd184775a3476101a1cede929John Reck if (!frame->pendingDirty.intersect(0, 0, props.getWidth(), props.getHeight())) { 205a447d29c65fb811cd184775a3476101a1cede929John Reck frame->pendingDirty.setEmpty(); 206a447d29c65fb811cd184775a3476101a1cede929John Reck } 207a447d29c65fb811cd184775a3476101a1cede929John Reck } 208a447d29c65fb811cd184775a3476101a1cede929John Reck 209a447d29c65fb811cd184775a3476101a1cede929John Reck // apply all transforms 210a447d29c65fb811cd184775a3476101a1cede929John Reck mapRect(props, frame->pendingDirty, &mHead->pendingDirty); 211a447d29c65fb811cd184775a3476101a1cede929John Reck 212a447d29c65fb811cd184775a3476101a1cede929John Reck // project backwards if necessary 213a447d29c65fb811cd184775a3476101a1cede929John Reck if (props.getProjectBackwards() && !frame->pendingDirty.isEmpty()) { 214a447d29c65fb811cd184775a3476101a1cede929John Reck // First, find our parent RenderNode: 215a447d29c65fb811cd184775a3476101a1cede929John Reck DirtyStack* parentNode = findParentRenderNode(frame); 216a447d29c65fb811cd184775a3476101a1cede929John Reck // Find our parent's projection receiver, which is what we project onto 217a447d29c65fb811cd184775a3476101a1cede929John Reck DirtyStack* projectionReceiver = findProjectionReceiver(parentNode); 218a447d29c65fb811cd184775a3476101a1cede929John Reck if (projectionReceiver) { 219a447d29c65fb811cd184775a3476101a1cede929John Reck applyTransforms(frame, projectionReceiver); 220a447d29c65fb811cd184775a3476101a1cede929John Reck projectionReceiver->pendingDirty.join(frame->pendingDirty); 221e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck } 222a447d29c65fb811cd184775a3476101a1cede929John Reck 223a447d29c65fb811cd184775a3476101a1cede929John Reck frame->pendingDirty.setEmpty(); 224e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck } 225e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck} 226e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck 227e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reckvoid DamageAccumulator::dirty(float left, float top, float right, float bottom) { 228e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck mHead->pendingDirty.join(left, top, right, bottom); 229e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck} 230e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck 231c71bfcaa182e3d4fd9874362d3b4781fda934a21Chris Craikvoid DamageAccumulator::peekAtDirty(SkRect* dest) const { 23225fbb3fa1138675379102a44405852555cefccbdJohn Reck *dest = mHead->pendingDirty; 23325fbb3fa1138675379102a44405852555cefccbdJohn Reck} 23425fbb3fa1138675379102a44405852555cefccbdJohn Reck 235e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reckvoid DamageAccumulator::finish(SkRect* totalDirty) { 2361bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck LOG_ALWAYS_FATAL_IF(mHead->prev != mHead, "Cannot finish, mismatched push/pop calls! %p vs. %p", 2371bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck mHead->prev, mHead); 238e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck // Root node never has a transform, so this is the fully mapped dirty rect 239e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck *totalDirty = mHead->pendingDirty; 24071487eb0ceb2b7dea02649e78d99bb5952f5eaefMike Reed totalDirty->roundOut(totalDirty); 241e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck mHead->pendingDirty.setEmpty(); 242e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck} 243e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck 244e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck} /* namespace uirenderer */ 245e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck} /* namespace android */ 246