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