DamageAccumulator.cpp revision e4267ea4f20740c37c01bfb6aefcf61fddc4566a
1/* 2 * Copyright (C) 2014 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 "DamageAccumulator" 18 19#include "DamageAccumulator.h" 20 21#include <cutils/log.h> 22 23#include "RenderNode.h" 24#include "utils/MathUtils.h" 25 26namespace android { 27namespace uirenderer { 28 29struct DirtyStack { 30 const RenderNode* node; 31 // When this frame is pop'd, this rect is mapped through the above transform 32 // and applied to the previous (aka parent) frame 33 SkRect pendingDirty; 34 DirtyStack* prev; 35 DirtyStack* next; 36}; 37 38DamageAccumulator::DamageAccumulator() { 39 mHead = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack)); 40 memset(mHead, 0, sizeof(DirtyStack)); 41 // Create a root that we will not pop off 42 mHead->prev = mHead; 43} 44 45void DamageAccumulator::pushNode(const RenderNode* node) { 46 if (!mHead->next) { 47 DirtyStack* nextFrame = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack)); 48 nextFrame->next = 0; 49 nextFrame->prev = mHead; 50 mHead->next = nextFrame; 51 } 52 mHead = mHead->next; 53 mHead->node = node; 54 mHead->pendingDirty.setEmpty(); 55} 56 57void DamageAccumulator::popNode() { 58 LOG_ALWAYS_FATAL_IF(mHead->prev == mHead, "Cannot pop the root frame!"); 59 DirtyStack* dirtyFrame = mHead; 60 mHead = mHead->prev; 61 if (!dirtyFrame->pendingDirty.isEmpty()) { 62 SkRect mappedDirty; 63 const RenderProperties& props = dirtyFrame->node->properties(); 64 const SkMatrix* transform = props.getTransformMatrix(); 65 if (transform && !transform->isIdentity()) { 66 transform->mapRect(&mappedDirty, dirtyFrame->pendingDirty); 67 } else { 68 mappedDirty = dirtyFrame->pendingDirty; 69 } 70 if (CC_LIKELY(mHead->node)) { 71 const RenderProperties& parentProps = mHead->node->properties(); 72 mappedDirty.offset(props.getLeft() - parentProps.getScrollX(), 73 props.getTop() - parentProps.getScrollY()); 74 if (props.getClipToBounds()) { 75 if (!mappedDirty.intersect(0, 0, parentProps.getWidth(), parentProps.getHeight())) { 76 mappedDirty.setEmpty(); 77 } 78 } 79 if (CC_UNLIKELY(!MathUtils::isZero(props.getTranslationZ()))) { 80 // TODO: Can we better bound the shadow damage area? For now 81 // match the old damageShadowReceiver() path and just dirty 82 // the entire parent bounds 83 mappedDirty.join(0, 0, parentProps.getWidth(), parentProps.getHeight()); 84 } 85 } else { 86 mappedDirty.offset(props.getLeft(), props.getTop()); 87 } 88 dirty(mappedDirty.fLeft, mappedDirty.fTop, mappedDirty.fRight, mappedDirty.fBottom); 89 } 90} 91 92void DamageAccumulator::dirty(float left, float top, float right, float bottom) { 93 mHead->pendingDirty.join(left, top, right, bottom); 94} 95 96void DamageAccumulator::finish(SkRect* totalDirty) { 97 LOG_ALWAYS_FATAL_IF(mHead->prev != mHead, "Cannot finish, mismatched push/pop calls! %p vs. %p", mHead->prev, mHead); 98 // Root node never has a transform, so this is the fully mapped dirty rect 99 *totalDirty = mHead->pendingDirty; 100 totalDirty->roundOut(); 101 mHead->pendingDirty.setEmpty(); 102} 103 104} /* namespace uirenderer */ 105} /* namespace android */ 106