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