aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkMultiPictureDraw.cpp
blob: 19b26ca60775e1b03d89cfd34952a936254525d2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#if SK_SUPPORT_GPU
#include "GrLayerHoister.h"
#include "GrRecordReplaceDraw.h"
#endif

#include "SkCanvas.h"
#include "SkMultiPictureDraw.h"
#include "SkPicture.h"

SkMultiPictureDraw::SkMultiPictureDraw(int reserve) {
    if (reserve > 0) {
        fDrawData.setReserve(reserve);
    }
}

void SkMultiPictureDraw::reset() {
    for (int i = 0; i < fDrawData.count(); ++i) {
        fDrawData[i].picture->unref();
        fDrawData[i].canvas->unref();
        SkDELETE(fDrawData[i].paint);
    }

    fDrawData.rewind();
}

void SkMultiPictureDraw::add(SkCanvas* canvas, 
                             const SkPicture* picture,
                             const SkMatrix* matrix, 
                             const SkPaint* paint) {
    if (NULL == canvas || NULL == picture) {
        SkDEBUGFAIL("parameters to SkMultiPictureDraw::add should be non-NULL");
        return;
    }

    DrawData* data = fDrawData.append();

    data->picture = SkRef(picture);
    data->canvas = SkRef(canvas);
    if (matrix) {
        data->matrix = *matrix;
    } else {
        data->matrix.setIdentity();
    }
    if (paint) {
        data->paint = SkNEW_ARGS(SkPaint, (*paint));
    } else {
        data->paint = NULL;
    }
}

#undef SK_IGNORE_GPU_LAYER_HOISTING
#define SK_IGNORE_GPU_LAYER_HOISTING 1

void SkMultiPictureDraw::draw() {

#ifndef SK_IGNORE_GPU_LAYER_HOISTING
    GrContext* context = NULL;

    SkTDArray<GrHoistedLayer> atlased, nonAtlased, recycled;

    for (int i = 0; i < fDrawData.count(); ++i) {
        if (fDrawData[i].canvas->getGrContext() &&
            !fDrawData[i].paint && fDrawData[i].matrix.isIdentity()) {
            SkASSERT(NULL == context || context == fDrawData[i].canvas->getGrContext());
            context = fDrawData[i].canvas->getGrContext();

            // TODO: this path always tries to optimize pictures. Should we
            // switch to this API approach (vs. SkCanvas::EXPERIMENTAL_optimize)?
            fDrawData[i].canvas->EXPERIMENTAL_optimize(fDrawData[i].picture);

            SkRect clipBounds;
            if (!fDrawData[i].canvas->getClipBounds(&clipBounds)) {
                continue;
            }

            GrLayerHoister::FindLayersToHoist(context, fDrawData[i].picture,
                                              clipBounds, &atlased, &nonAtlased, &recycled);
        }
    }

    GrReplacements replacements;

    if (NULL != context) {
        GrLayerHoister::DrawLayers(atlased, nonAtlased, recycled, &replacements);
    }
#endif

    for (int i = 0; i < fDrawData.count(); ++i) {
#ifndef SK_IGNORE_GPU_LAYER_HOISTING
        if (fDrawData[i].canvas->getGrContext() && 
            !fDrawData[i].paint && fDrawData[i].matrix.isIdentity()) {
            // Render the entire picture using new layers
            const SkMatrix initialMatrix = fDrawData[i].canvas->getTotalMatrix();

            GrRecordReplaceDraw(fDrawData[i].picture, fDrawData[i].canvas, 
                                &replacements, initialMatrix, NULL);
        } else 
#endif
        {
            fDrawData[i].canvas->drawPicture(fDrawData[i].picture,
                                             &fDrawData[i].matrix,
                                             fDrawData[i].paint);
        }
    }

#ifndef SK_IGNORE_GPU_LAYER_HOISTING
    if (NULL != context) {
        GrLayerHoister::UnlockLayers(context, atlased, nonAtlased, recycled);
    }
#endif

    this->reset();
}