aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/GrRecordReplaceDraw.cpp
blob: ab5192680de4a66bfa8413145bfea6afb93cf095 (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
/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrRecordReplaceDraw.h"
#include "SkImage.h"
#include "SkRecordDraw.h"

GrReplacements::ReplacementInfo* GrReplacements::push() {
    SkDEBUGCODE(this->validate());
    return fReplacements.push();
}

void GrReplacements::freeAll() {
    for (int i = 0; i < fReplacements.count(); ++i) {
        fReplacements[i].fImage->unref();
    }
    fReplacements.reset();
}

#ifdef SK_DEBUG
void GrReplacements::validate() const {
    // Check that the ranges are monotonically increasing and non-overlapping
    if (fReplacements.count() > 0) {
        SkASSERT(fReplacements[0].fStart < fReplacements[0].fStop);

        for (int i = 1; i < fReplacements.count(); ++i) {
            SkASSERT(fReplacements[i].fStart < fReplacements[i].fStop);
            SkASSERT(fReplacements[i - 1].fStop < fReplacements[i].fStart);
        }
    }
}
#endif

const GrReplacements::ReplacementInfo*
GrReplacements::lookupByStart(size_t start, int* searchStart) const {
    SkDEBUGCODE(this->validate());
    for (int i = *searchStart; i < fReplacements.count(); ++i) {
        if (start == fReplacements[i].fStart) {
            *searchStart = i + 1;
            return &fReplacements[i];
        } else if (start < fReplacements[i].fStart) {
            return NULL;  // the ranges are monotonically increasing and non-overlapping
        }
    }

    return NULL;
}

static inline void draw_replacement_bitmap(const GrReplacements::ReplacementInfo* ri,
                                           SkCanvas* canvas) {
    SkRect src = SkRect::Make(ri->fSrcRect);
    SkRect dst = SkRect::MakeXYWH(SkIntToScalar(ri->fPos.fX),
                                  SkIntToScalar(ri->fPos.fY),
                                  SkIntToScalar(ri->fSrcRect.width()), 
                                  SkIntToScalar(ri->fSrcRect.height()));
    ri->fImage->draw(canvas, &src, dst, ri->fPaint);
}

void GrRecordReplaceDraw(const SkRecord& record,
                         SkCanvas* canvas,
                         const SkBBoxHierarchy* bbh,
                         const GrReplacements* replacements,
                         SkDrawPictureCallback* callback) {
    SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/);

    SkRecords::Draw draw(canvas);
    const GrReplacements::ReplacementInfo* ri = NULL;
    int searchStart = 0;

    if (NULL != bbh) {
        // Draw only ops that affect pixels in the canvas's current clip.
        // The SkRecord and BBH were recorded in identity space.  This canvas
        // is not necessarily in that same space.  getClipBounds() returns us
        // this canvas' clip bounds transformed back into identity space, which
        // lets us query the BBH.
        SkRect query = { 0, 0, 0, 0 };
        (void)canvas->getClipBounds(&query);

        SkTDArray<void*> ops;
        bbh->search(query, &ops);

        for (int i = 0; i < ops.count(); i++) {
            if (NULL != callback && callback->abortDrawing()) {
                return;
            }
            ri = replacements->lookupByStart((uintptr_t)ops[i], &searchStart);
            if (NULL != ri) {
                draw_replacement_bitmap(ri, canvas);

                while ((uintptr_t)ops[i] < ri->fStop) {
                    ++i;
                }
                SkASSERT((uintptr_t)ops[i] == ri->fStop);
                continue;
            }

            record.visit<void>((uintptr_t)ops[i], draw);
        }
    } else {
        for (unsigned int i = 0; i < record.count(); ++i) {
            if (NULL != callback && callback->abortDrawing()) {
                return;
            }
            ri = replacements->lookupByStart(i, &searchStart);
            if (NULL != ri) {
                draw_replacement_bitmap(ri, canvas);

                i = ri->fStop;
                continue;
            }

            record.visit<void>(i, draw);
        }
    }
}