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) {
6069e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik    case TransformRenderNode:
6169e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik        currentFrame->renderNode->applyViewPropertyTransforms(*outMatrix);
6269e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik        break;
6369e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik    case TransformMatrix4:
6469e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik        outMatrix->multiply(*currentFrame->matrix4);
6569e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik        break;
6669e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik    case TransformNone:
6769e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik        // nothing to be done
6869e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik        break;
6969e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik    default:
7069e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik        LOG_ALWAYS_FATAL("Tried to compute transform with an invalid type: %d", currentFrame->type);
7169e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik    }
7269e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik}
7369e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik
7469e5adffb19135d51bde8e458f4907d7265f3e23Chris Craikvoid DamageAccumulator::computeCurrentTransform(Matrix4* outMatrix) const {
7569e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik    outMatrix->loadIdentity();
7669e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik    computeTransformImpl(mHead, outMatrix);
7769e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik}
7869e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik
79a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::pushCommon() {
80e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    if (!mHead->next) {
817df9ff2a08fd4bbd9b2e734a357cffcf64675df9John Reck        DirtyStack* nextFrame = mAllocator.create_trivial<DirtyStack>();
82d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik        nextFrame->next = nullptr;
83e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck        nextFrame->prev = mHead;
84e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck        mHead->next = nextFrame;
85e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    }
86e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    mHead = mHead->next;
87e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    mHead->pendingDirty.setEmpty();
88e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck}
89e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
90a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::pushTransform(const RenderNode* transform) {
91a447d29c65fb811cd184775a3476101a1cede929John Reck    pushCommon();
92a447d29c65fb811cd184775a3476101a1cede929John Reck    mHead->type = TransformRenderNode;
93a447d29c65fb811cd184775a3476101a1cede929John Reck    mHead->renderNode = transform;
94a447d29c65fb811cd184775a3476101a1cede929John Reck}
95a447d29c65fb811cd184775a3476101a1cede929John Reck
96a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::pushTransform(const Matrix4* transform) {
97a447d29c65fb811cd184775a3476101a1cede929John Reck    pushCommon();
98a447d29c65fb811cd184775a3476101a1cede929John Reck    mHead->type = TransformMatrix4;
99a447d29c65fb811cd184775a3476101a1cede929John Reck    mHead->matrix4 = transform;
100a447d29c65fb811cd184775a3476101a1cede929John Reck}
101a447d29c65fb811cd184775a3476101a1cede929John Reck
102a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::popTransform() {
103e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    LOG_ALWAYS_FATAL_IF(mHead->prev == mHead, "Cannot pop the root frame!");
104e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    DirtyStack* dirtyFrame = mHead;
105e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    mHead = mHead->prev;
10625fbb3fa1138675379102a44405852555cefccbdJohn Reck    switch (dirtyFrame->type) {
10725fbb3fa1138675379102a44405852555cefccbdJohn Reck    case TransformRenderNode:
108a447d29c65fb811cd184775a3476101a1cede929John Reck        applyRenderNodeTransform(dirtyFrame);
10925fbb3fa1138675379102a44405852555cefccbdJohn Reck        break;
11025fbb3fa1138675379102a44405852555cefccbdJohn Reck    case TransformMatrix4:
111a447d29c65fb811cd184775a3476101a1cede929John Reck        applyMatrix4Transform(dirtyFrame);
11225fbb3fa1138675379102a44405852555cefccbdJohn Reck        break;
11325fbb3fa1138675379102a44405852555cefccbdJohn Reck    case TransformNone:
11425fbb3fa1138675379102a44405852555cefccbdJohn Reck        mHead->pendingDirty.join(dirtyFrame->pendingDirty);
11525fbb3fa1138675379102a44405852555cefccbdJohn Reck        break;
1162dc223d23764a78f052529e86a59a1979d03b811John Reck    default:
1172dc223d23764a78f052529e86a59a1979d03b811John Reck        LOG_ALWAYS_FATAL("Tried to pop an invalid type: %d", dirtyFrame->type);
118a447d29c65fb811cd184775a3476101a1cede929John Reck    }
119a447d29c65fb811cd184775a3476101a1cede929John Reck}
120a447d29c65fb811cd184775a3476101a1cede929John Reck
121a447d29c65fb811cd184775a3476101a1cede929John Reckstatic inline void mapRect(const Matrix4* matrix, const SkRect& in, SkRect* out) {
122a447d29c65fb811cd184775a3476101a1cede929John Reck    if (in.isEmpty()) return;
123a447d29c65fb811cd184775a3476101a1cede929John Reck    Rect temp(in);
124c128823940fb0be96eda810fa9f0c75f66d944b0John Reck    if (CC_LIKELY(!matrix->isPerspective())) {
125c128823940fb0be96eda810fa9f0c75f66d944b0John Reck        matrix->mapRect(temp);
126c128823940fb0be96eda810fa9f0c75f66d944b0John Reck    } else {
127c128823940fb0be96eda810fa9f0c75f66d944b0John Reck        // Don't attempt to calculate damage for a perspective transform
128c128823940fb0be96eda810fa9f0c75f66d944b0John Reck        // as the numbers this works with can break the perspective
129c128823940fb0be96eda810fa9f0c75f66d944b0John Reck        // calculations. Just give up and expand to DIRTY_MIN/DIRTY_MAX
130c128823940fb0be96eda810fa9f0c75f66d944b0John Reck        temp.set(DIRTY_MIN, DIRTY_MIN, DIRTY_MAX, DIRTY_MAX);
131c128823940fb0be96eda810fa9f0c75f66d944b0John Reck    }
132a447d29c65fb811cd184775a3476101a1cede929John Reck    out->join(RECT_ARGS(temp));
133a447d29c65fb811cd184775a3476101a1cede929John Reck}
134a447d29c65fb811cd184775a3476101a1cede929John Reck
135a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::applyMatrix4Transform(DirtyStack* frame) {
136a447d29c65fb811cd184775a3476101a1cede929John Reck    mapRect(frame->matrix4, frame->pendingDirty, &mHead->pendingDirty);
137a447d29c65fb811cd184775a3476101a1cede929John Reck}
138a447d29c65fb811cd184775a3476101a1cede929John Reck
139a447d29c65fb811cd184775a3476101a1cede929John Reckstatic inline void mapRect(const RenderProperties& props, const SkRect& in, SkRect* out) {
140a447d29c65fb811cd184775a3476101a1cede929John Reck    if (in.isEmpty()) return;
141a447d29c65fb811cd184775a3476101a1cede929John Reck    const SkMatrix* transform = props.getTransformMatrix();
142a447d29c65fb811cd184775a3476101a1cede929John Reck    SkRect temp(in);
143a447d29c65fb811cd184775a3476101a1cede929John Reck    if (transform && !transform->isIdentity()) {
144c128823940fb0be96eda810fa9f0c75f66d944b0John Reck        if (CC_LIKELY(!transform->hasPerspective())) {
145c128823940fb0be96eda810fa9f0c75f66d944b0John Reck            transform->mapRect(&temp);
146c128823940fb0be96eda810fa9f0c75f66d944b0John Reck        } else {
147c128823940fb0be96eda810fa9f0c75f66d944b0John Reck            // Don't attempt to calculate damage for a perspective transform
148c128823940fb0be96eda810fa9f0c75f66d944b0John Reck            // as the numbers this works with can break the perspective
149c128823940fb0be96eda810fa9f0c75f66d944b0John Reck            // calculations. Just give up and expand to DIRTY_MIN/DIRTY_MAX
150c128823940fb0be96eda810fa9f0c75f66d944b0John Reck            temp.set(DIRTY_MIN, DIRTY_MIN, DIRTY_MAX, DIRTY_MAX);
151c128823940fb0be96eda810fa9f0c75f66d944b0John Reck        }
152a447d29c65fb811cd184775a3476101a1cede929John Reck    }
153a447d29c65fb811cd184775a3476101a1cede929John Reck    temp.offset(props.getLeft(), props.getTop());
154a447d29c65fb811cd184775a3476101a1cede929John Reck    out->join(temp);
155a447d29c65fb811cd184775a3476101a1cede929John Reck}
156a447d29c65fb811cd184775a3476101a1cede929John Reck
157a447d29c65fb811cd184775a3476101a1cede929John Reckstatic DirtyStack* findParentRenderNode(DirtyStack* frame) {
158a447d29c65fb811cd184775a3476101a1cede929John Reck    while (frame->prev != frame) {
159a447d29c65fb811cd184775a3476101a1cede929John Reck        frame = frame->prev;
160a447d29c65fb811cd184775a3476101a1cede929John Reck        if (frame->type == TransformRenderNode) {
161a447d29c65fb811cd184775a3476101a1cede929John Reck            return frame;
162e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck        }
163a447d29c65fb811cd184775a3476101a1cede929John Reck    }
164d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik    return nullptr;
165a447d29c65fb811cd184775a3476101a1cede929John Reck}
166a447d29c65fb811cd184775a3476101a1cede929John Reck
167a447d29c65fb811cd184775a3476101a1cede929John Reckstatic DirtyStack* findProjectionReceiver(DirtyStack* frame) {
168a447d29c65fb811cd184775a3476101a1cede929John Reck    if (frame) {
169a447d29c65fb811cd184775a3476101a1cede929John Reck        while (frame->prev != frame) {
170a447d29c65fb811cd184775a3476101a1cede929John Reck            frame = frame->prev;
171a447d29c65fb811cd184775a3476101a1cede929John Reck            if (frame->type == TransformRenderNode
172a447d29c65fb811cd184775a3476101a1cede929John Reck                    && 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) {
236e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    LOG_ALWAYS_FATAL_IF(mHead->prev != mHead, "Cannot finish, mismatched push/pop calls! %p vs. %p", mHead->prev, mHead);
237e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    // Root node never has a transform, so this is the fully mapped dirty rect
238e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    *totalDirty = mHead->pendingDirty;
23971487eb0ceb2b7dea02649e78d99bb5952f5eaefMike Reed    totalDirty->roundOut(totalDirty);
240e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    mHead->pendingDirty.setEmpty();
241e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck}
242e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
243e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck} /* namespace uirenderer */
244e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck} /* namespace android */
245