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

#ifndef SkOffsetTable_DEFINED
#define SkOffsetTable_DEFINED

#include "SkRefCnt.h"
#include "SkTDArray.h"

// A 2D table of skp offsets. Each row is indexed by an int. This is used
// to store the command offsets that reference a particular bitmap using
// the bitmap's index in the bitmap heap as the 'id' here. It has to be
// ref-countable so SkPicturePlayback can take ownership of it.
// Note that this class assumes that the ids are densely packed.

// TODO: This needs to be sped up. We could replace the offset table with
// a hash table.
class SkOffsetTable : public SkRefCnt {
public:
    SkOffsetTable() {}
    ~SkOffsetTable() {
        fOffsetArrays.deleteAll();
    }

    // Record that this 'id' is used by the command starting at this 'offset'.
    // Offsets for a given 'id' should always be added in increasing order.
    void add(int id, size_t offset) {
        if (id >= fOffsetArrays.count()) {
            int oldCount = fOffsetArrays.count();
            fOffsetArrays.setCount(id+1);
            for (int i = oldCount; i <= id; ++i) {
                fOffsetArrays[i] = NULL;
            }
        }

        if (NULL == fOffsetArrays[id]) {
            fOffsetArrays[id] = SkNEW(OffsetArray);
        }
        fOffsetArrays[id]->add(offset);
    }

    int numIDs() const {
        return fOffsetArrays.count(); 
    }

    // Do the offsets of any commands referencing this ID fall in the 
    // range [min, max] (both inclusive)
    bool overlap(int id, size_t min, size_t max) {
        SkASSERT(id < fOffsetArrays.count());

        if (NULL == fOffsetArrays[id]) {
            return false;
        }

        // If this id has an offset array it should have at least one use
        SkASSERT(fOffsetArrays[id]->count() > 0);
        if (max < fOffsetArrays[id]->min() || min > fOffsetArrays[id]->max()) {
            return false;
        }

        return true;
    }

    bool includes(int id, size_t offset) {
        SkASSERT(id < fOffsetArrays.count());

        OffsetArray* array = fOffsetArrays[id];

        for (int i = 0; i < array->fOffsets.count(); ++i) {
            if (array->fOffsets[i] == offset) {
                return true;
            } else if (array->fOffsets[i] > offset) {
                return false;
            }
        }

        // Calls to 'includes' should be gaurded by an overlap() call, so we
        // should always find something.
        SkASSERT(0);
        return false;
    }

protected:
    class OffsetArray {
    public:
        void add(size_t offset) { 
            SkASSERT(fOffsets.count() == 0 || offset > this->max());
            *fOffsets.append() = offset;  
        }
        size_t min() const { 
            SkASSERT(fOffsets.count() > 0);
            return fOffsets[0]; 
        }
        size_t max() const { 
            SkASSERT(fOffsets.count() > 0);
            return fOffsets[fOffsets.count()-1]; 
        }
        int count() const {
            return fOffsets.count();
        }

        SkTDArray<size_t> fOffsets;
    };

    SkTDArray<OffsetArray*> fOffsetArrays;

private:
    typedef SkRefCnt INHERITED;
};

#endif