1
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#ifndef SkDescriptor_DEFINED
11#define SkDescriptor_DEFINED
12
13#include "SkTypes.h"
14
15class SkDescriptor : SkNoncopyable {
16public:
17    static size_t ComputeOverhead(int entryCount)
18    {
19        SkASSERT(entryCount >= 0);
20        return sizeof(SkDescriptor) + entryCount * sizeof(Entry);
21    }
22
23    static SkDescriptor* Alloc(size_t length)
24    {
25        SkASSERT(SkAlign4(length) == length);
26        SkDescriptor* desc = (SkDescriptor*)sk_malloc_throw(length);
27        return desc;
28    }
29
30    static void Free(SkDescriptor* desc)
31    {
32        sk_free(desc);
33    }
34
35    void init()
36    {
37        fLength = sizeof(SkDescriptor);
38        fCount  = 0;
39    }
40
41    uint32_t getLength() const { return fLength; }
42
43    void* addEntry(uint32_t tag, uint32_t length, const void* data = NULL)
44    {
45        SkASSERT(tag);
46        SkASSERT(SkAlign4(length) == length);
47        SkASSERT(this->findEntry(tag, NULL) == NULL);
48
49        Entry*  entry = (Entry*)((char*)this + fLength);
50        entry->fTag = tag;
51        entry->fLen = length;
52        if (data)
53            memcpy(entry + 1, data, length);
54
55        fCount += 1;
56        fLength += sizeof(Entry) + length;
57        return (entry + 1); // return its data
58    }
59
60    void computeChecksum()
61    {
62        fChecksum = SkDescriptor::ComputeChecksum(this);
63    }
64
65#ifdef SK_DEBUG
66    void assertChecksum() const
67    {
68        SkASSERT(fChecksum == SkDescriptor::ComputeChecksum(this));
69    }
70#endif
71
72    const void* findEntry(uint32_t tag, uint32_t* length) const
73    {
74        const Entry* entry = (const Entry*)(this + 1);
75        int          count = fCount;
76
77        while (--count >= 0)
78        {
79            if (entry->fTag == tag)
80            {
81                if (length)
82                    *length = entry->fLen;
83                return entry + 1;
84            }
85            entry = (const Entry*)((const char*)(entry + 1) + entry->fLen);
86        }
87        return NULL;
88    }
89
90    SkDescriptor* copy() const
91    {
92        SkDescriptor* desc = SkDescriptor::Alloc(fLength);
93        memcpy(desc, this, fLength);
94        return desc;
95    }
96
97    bool equals(const SkDescriptor& other) const
98    {
99        // probe to see if we have a good checksum algo
100//        SkASSERT(a.fChecksum != b.fChecksum || memcmp(&a, &b, a.fLength) == 0);
101
102        // the first value we should look at is the checksum, so this loop
103        // should terminate early if they descriptors are different.
104        // NOTE: if we wrote a sentinel value at the end of each, we chould
105        //       remove the aa < stop test in the loop...
106        const uint32_t* aa = (const uint32_t*)this;
107        const uint32_t* bb = (const uint32_t*)&other;
108        const uint32_t* stop = (const uint32_t*)((const char*)aa + fLength);
109        do {
110            if (*aa++ != *bb++)
111                return false;
112        } while (aa < stop);
113        return true;
114    }
115
116    uint32_t getChecksum() const { return fChecksum; }
117
118    struct Entry {
119        uint32_t fTag;
120        uint32_t fLen;
121    };
122
123#ifdef SK_DEBUG
124    uint32_t getCount() const { return fCount; }
125#endif
126
127private:
128    uint32_t fChecksum;  // must be first
129    uint32_t fLength;    // must be second
130    uint32_t fCount;
131
132    static uint32_t ComputeChecksum(const SkDescriptor* desc)
133    {
134        const uint32_t*  ptr = (const uint32_t*)desc + 1; // skip the checksum field
135        const uint32_t*  stop = (const uint32_t*)((const char*)desc + desc->fLength);
136        uint32_t         sum = 0;
137
138        SkASSERT(ptr < stop);
139        do {
140            sum = (sum << 1) | (sum >> 31);
141            sum ^= *ptr++;
142        } while (ptr < stop);
143
144        return sum;
145    }
146
147    // private so no one can create one except our factories
148    SkDescriptor() {}
149};
150
151#include "SkScalerContext.h"
152
153class SkAutoDescriptor : SkNoncopyable {
154public:
155    SkAutoDescriptor(size_t size)
156    {
157        if (size <= sizeof(fStorage))
158            fDesc = (SkDescriptor*)(void*)fStorage;
159        else
160            fDesc = SkDescriptor::Alloc(size);
161    }
162    ~SkAutoDescriptor()
163    {
164        if (fDesc != (SkDescriptor*)(void*)fStorage)
165            SkDescriptor::Free(fDesc);
166    }
167    SkDescriptor* getDesc() const { return fDesc; }
168private:
169    enum {
170        kStorageSize =  sizeof(SkDescriptor)
171                        + sizeof(SkDescriptor::Entry) + sizeof(SkScalerContext::Rec)    // for rec
172                        + sizeof(SkDescriptor::Entry) + sizeof(void*)                   // for typeface
173                        + 32   // slop for occational small extras
174    };
175    SkDescriptor*   fDesc;
176    uint32_t        fStorage[(kStorageSize + 3) >> 2];
177};
178
179
180#endif
181
182