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