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 getChecksum()123 uint32_t getChecksum() const { return fChecksum; } 124 125 struct Entry { 126 uint32_t fTag; 127 uint32_t fLen; 128 }; 129 130 #ifdef SK_DEBUG getCount()131 uint32_t getCount() const { return fCount; } 132 #endif 133 134 private: 135 uint32_t fChecksum; // must be first 136 uint32_t fLength; // must be second 137 uint32_t fCount; 138 ComputeChecksum(const SkDescriptor * desc)139 static uint32_t ComputeChecksum(const SkDescriptor* desc) 140 { 141 const uint32_t* ptr = (const uint32_t*)desc + 1; // skip the checksum field 142 const uint32_t* stop = (const uint32_t*)((const char*)desc + desc->fLength); 143 uint32_t sum = 0; 144 145 SkASSERT(ptr < stop); 146 do { 147 sum = (sum << 1) | (sum >> 31); 148 sum ^= *ptr++; 149 } while (ptr < stop); 150 151 return sum; 152 } 153 154 // private so no one can create one except our factories SkDescriptor()155 SkDescriptor() {} 156 }; 157 158 #include "SkScalerContext.h" 159 160 class SkAutoDescriptor : SkNoncopyable { 161 public: SkAutoDescriptor(size_t size)162 SkAutoDescriptor(size_t size) 163 { 164 if (size <= sizeof(fStorage)) 165 fDesc = (SkDescriptor*)(void*)fStorage; 166 else 167 fDesc = SkDescriptor::Alloc(size); 168 } ~SkAutoDescriptor()169 ~SkAutoDescriptor() 170 { 171 if (fDesc != (SkDescriptor*)(void*)fStorage) 172 SkDescriptor::Free(fDesc); 173 } getDesc()174 SkDescriptor* getDesc() const { return fDesc; } 175 private: 176 enum { 177 kStorageSize = sizeof(SkDescriptor) 178 + sizeof(SkDescriptor::Entry) + sizeof(SkScalerContext::Rec) // for rec 179 + sizeof(SkDescriptor::Entry) + sizeof(void*) // for typeface 180 + 32 // slop for occational small extras 181 }; 182 SkDescriptor* fDesc; 183 uint32_t fStorage[(kStorageSize + 3) >> 2]; 184 }; 185 186 187 #endif 188 189