1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
28a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project
48a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
78a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifndef SkDescriptor_DEFINED
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SkDescriptor_DEFINED
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13ef76060cbf36032a5bef9cd8d18138704349c3aejunov@chromium.org#include "SkChecksum.h"
148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkTypes.h"
158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass SkDescriptor : SkNoncopyable {
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
18142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com    static size_t ComputeOverhead(int entryCount) {
198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(entryCount >= 0);
208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return sizeof(SkDescriptor) + entryCount * sizeof(Entry);
218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
23142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com    static SkDescriptor* Alloc(size_t length) {
248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(SkAlign4(length) == length);
258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkDescriptor* desc = (SkDescriptor*)sk_malloc_throw(length);
268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return desc;
278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
29142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com    static void Free(SkDescriptor* desc) {
308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        sk_free(desc);
318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
33142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com    void init() {
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fLength = sizeof(SkDescriptor);
358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fCount  = 0;
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t getLength() const { return fLength; }
398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
402cfa3200fda29279eba1240170c7e873d12f9d48commit-bot@chromium.org    void* addEntry(uint32_t tag, size_t length, const void* data = NULL) {
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(tag);
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(SkAlign4(length) == length);
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(this->findEntry(tag, NULL) == NULL);
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        Entry*  entry = (Entry*)((char*)this + fLength);
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        entry->fTag = tag;
472cfa3200fda29279eba1240170c7e873d12f9d48commit-bot@chromium.org        entry->fLen = SkToU32(length);
48142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com        if (data) {
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            memcpy(entry + 1, data, length);
50142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com        }
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fCount += 1;
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fLength += sizeof(Entry) + length;
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return (entry + 1); // return its data
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
57142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com    void computeChecksum() {
588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fChecksum = SkDescriptor::ComputeChecksum(this);
598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
62142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com    void assertChecksum() const {
63142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com        SkASSERT(SkDescriptor::ComputeChecksum(this) == fChecksum);
648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
67142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com    const void* findEntry(uint32_t tag, uint32_t* length) const {
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const Entry* entry = (const Entry*)(this + 1);
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int          count = fCount;
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
71142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com        while (--count >= 0) {
72142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com            if (entry->fTag == tag) {
73142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com                if (length) {
748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    *length = entry->fLen;
75142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com                }
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                return entry + 1;
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            entry = (const Entry*)((const char*)(entry + 1) + entry->fLen);
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return NULL;
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
83142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com    SkDescriptor* copy() const {
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkDescriptor* desc = SkDescriptor::Alloc(fLength);
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        memcpy(desc, this, fLength);
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return desc;
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
89142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com    bool equals(const SkDescriptor& other) const {
908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // probe to see if we have a good checksum algo
918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//        SkASSERT(a.fChecksum != b.fChecksum || memcmp(&a, &b, a.fLength) == 0);
928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // the first value we should look at is the checksum, so this loop
948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // should terminate early if they descriptors are different.
958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // NOTE: if we wrote a sentinel value at the end of each, we chould
968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        //       remove the aa < stop test in the loop...
978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const uint32_t* aa = (const uint32_t*)this;
988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const uint32_t* bb = (const uint32_t*)&other;
998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const uint32_t* stop = (const uint32_t*)((const char*)aa + fLength);
1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        do {
1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (*aa++ != *bb++)
1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                return false;
1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } while (aa < stop);
1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return true;
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
107f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    uint32_t getChecksum() const { return fChecksum; }
108f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com
1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    struct Entry {
1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        uint32_t fTag;
1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        uint32_t fLen;
1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    };
1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t getCount() const { return fCount; }
1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t fChecksum;  // must be first
1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t fLength;    // must be second
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t fCount;
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
123142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com    static uint32_t ComputeChecksum(const SkDescriptor* desc) {
124ef76060cbf36032a5bef9cd8d18138704349c3aejunov@chromium.org        const uint32_t* ptr = (const uint32_t*)desc + 1; // skip the checksum field
125142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com        size_t len = desc->fLength - sizeof(uint32_t);
126142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com        return SkChecksum::Compute(ptr, len);
1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
128fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // private so no one can create one except our factories
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDescriptor() {}
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkScalerContext.h"
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass SkAutoDescriptor : SkNoncopyable {
1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
137142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com    SkAutoDescriptor(size_t size) {
138142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com        if (size <= sizeof(fStorage)) {
1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fDesc = (SkDescriptor*)(void*)fStorage;
140142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com        } else {
1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fDesc = SkDescriptor::Alloc(size);
142142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com        }
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
144142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com
145142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com    ~SkAutoDescriptor() {
146142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com        if (fDesc != (SkDescriptor*)(void*)fStorage) {
1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkDescriptor::Free(fDesc);
148142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com        }
1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
150142e1fe7cf5dc82e5d4c107b06756302f0cbf96dreed@google.com
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDescriptor* getDesc() const { return fDesc; }
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    enum {
1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kStorageSize =  sizeof(SkDescriptor)
1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        + sizeof(SkDescriptor::Entry) + sizeof(SkScalerContext::Rec)    // for rec
1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        + sizeof(SkDescriptor::Entry) + sizeof(void*)                   // for typeface
1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        + 32   // slop for occational small extras
1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    };
1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDescriptor*   fDesc;
1608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t        fStorage[(kStorageSize + 3) >> 2];
1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
162e61a86cfa00ea393ecc4a71fca94e1d476a37ecccommit-bot@chromium.org#define SkAutoDescriptor(...) SK_REQUIRE_LOCAL_VAR(SkAutoDescriptor)
1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
166