blob: 0e91c3c2cf980befe48fc18f66ab83c924bc7cb9 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2006 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
epoger@google.comec3ed6a2011-07-28 14:26:00 +00008
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#ifndef SkDescriptor_DEFINED
10#define SkDescriptor_DEFINED
11
mtklein4e976072016-08-08 09:06:27 -070012#include "SkOpts.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkTypes.h"
bungeman520ced62016-10-18 08:03:42 -040014#include <memory>
reed@android.com8a1c16f2008-12-17 15:59:43 +000015
16class SkDescriptor : SkNoncopyable {
17public:
reed@google.com142e1fe2012-07-09 17:44:44 +000018 static size_t ComputeOverhead(int entryCount) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000019 SkASSERT(entryCount >= 0);
20 return sizeof(SkDescriptor) + entryCount * sizeof(Entry);
21 }
22
bungeman520ced62016-10-18 08:03:42 -040023 static std::unique_ptr<SkDescriptor> Alloc(size_t length) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000024 SkASSERT(SkAlign4(length) == length);
bungeman520ced62016-10-18 08:03:42 -040025 return std::unique_ptr<SkDescriptor>(static_cast<SkDescriptor*>(::operator new (length)));
reed@android.com8a1c16f2008-12-17 15:59:43 +000026 }
27
Ben Wagnere1d6ff12016-10-19 17:15:44 -040028 // Ensure the unsized delete is called.
29 void operator delete(void* p) { ::operator delete(p); }
30
reed@google.com142e1fe2012-07-09 17:44:44 +000031 void init() {
reed@android.com8a1c16f2008-12-17 15:59:43 +000032 fLength = sizeof(SkDescriptor);
33 fCount = 0;
34 }
35
36 uint32_t getLength() const { return fLength; }
37
halcanary96fcdcc2015-08-27 07:41:13 -070038 void* addEntry(uint32_t tag, size_t length, const void* data = nullptr) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000039 SkASSERT(tag);
40 SkASSERT(SkAlign4(length) == length);
halcanary96fcdcc2015-08-27 07:41:13 -070041 SkASSERT(this->findEntry(tag, nullptr) == nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +000042
bsalomonccb328d2014-12-11 13:31:06 -080043 Entry* entry = (Entry*)((char*)this + fLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +000044 entry->fTag = tag;
commit-bot@chromium.org2cfa3202014-04-19 22:00:40 +000045 entry->fLen = SkToU32(length);
reed@google.com142e1fe2012-07-09 17:44:44 +000046 if (data) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000047 memcpy(entry + 1, data, length);
reed@google.com142e1fe2012-07-09 17:44:44 +000048 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000049
50 fCount += 1;
bsalomonccb328d2014-12-11 13:31:06 -080051 fLength = SkToU32(fLength + sizeof(Entry) + length);
reed@android.com8a1c16f2008-12-17 15:59:43 +000052 return (entry + 1); // return its data
53 }
54
reed@google.com142e1fe2012-07-09 17:44:44 +000055 void computeChecksum() {
reed@android.com8a1c16f2008-12-17 15:59:43 +000056 fChecksum = SkDescriptor::ComputeChecksum(this);
57 }
58
59#ifdef SK_DEBUG
reed@google.com142e1fe2012-07-09 17:44:44 +000060 void assertChecksum() const {
61 SkASSERT(SkDescriptor::ComputeChecksum(this) == fChecksum);
reed@android.com8a1c16f2008-12-17 15:59:43 +000062 }
63#endif
64
reed@google.com142e1fe2012-07-09 17:44:44 +000065 const void* findEntry(uint32_t tag, uint32_t* length) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +000066 const Entry* entry = (const Entry*)(this + 1);
67 int count = fCount;
68
reed@google.com142e1fe2012-07-09 17:44:44 +000069 while (--count >= 0) {
70 if (entry->fTag == tag) {
71 if (length) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000072 *length = entry->fLen;
reed@google.com142e1fe2012-07-09 17:44:44 +000073 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000074 return entry + 1;
75 }
76 entry = (const Entry*)((const char*)(entry + 1) + entry->fLen);
77 }
halcanary96fcdcc2015-08-27 07:41:13 -070078 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +000079 }
80
bungeman520ced62016-10-18 08:03:42 -040081 std::unique_ptr<SkDescriptor> copy() const {
82 std::unique_ptr<SkDescriptor> desc = SkDescriptor::Alloc(fLength);
83 memcpy(desc.get(), this, fLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +000084 return desc;
85 }
86
bsalomonc5d07fa2016-05-17 10:17:45 -070087 bool operator==(const SkDescriptor& other) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +000088 // 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 }
bsalomond1c71fd2016-05-19 12:51:46 -0700104 bool operator!=(const SkDescriptor& other) const { return !(*this == other); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000105
reed@android.comf2b98d62010-12-20 18:26:13 +0000106 uint32_t getChecksum() const { return fChecksum; }
107
reed@android.com8a1c16f2008-12-17 15:59:43 +0000108 struct Entry {
109 uint32_t fTag;
110 uint32_t fLen;
111 };
112
113#ifdef SK_DEBUG
reed@android.com8a1c16f2008-12-17 15:59:43 +0000114 uint32_t getCount() const { return fCount; }
115#endif
116
117private:
118 uint32_t fChecksum; // must be first
119 uint32_t fLength; // must be second
120 uint32_t fCount;
121
reed@google.com142e1fe2012-07-09 17:44:44 +0000122 static uint32_t ComputeChecksum(const SkDescriptor* desc) {
junov@chromium.orgef760602012-06-27 20:03:16 +0000123 const uint32_t* ptr = (const uint32_t*)desc + 1; // skip the checksum field
reed@google.com142e1fe2012-07-09 17:44:44 +0000124 size_t len = desc->fLength - sizeof(uint32_t);
mtklein4e976072016-08-08 09:06:27 -0700125 return SkOpts::hash(ptr, len);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000127
reed@android.com8a1c16f2008-12-17 15:59:43 +0000128 // private so no one can create one except our factories
129 SkDescriptor() {}
130};
131
132#include "SkScalerContext.h"
133
134class SkAutoDescriptor : SkNoncopyable {
135public:
halcanary96fcdcc2015-08-27 07:41:13 -0700136 SkAutoDescriptor() : fDesc(nullptr) {}
137 SkAutoDescriptor(size_t size) : fDesc(nullptr) { this->reset(size); }
138 SkAutoDescriptor(const SkDescriptor& desc) : fDesc(nullptr) {
joshualitt73d5de52015-07-17 06:19:19 -0700139 size_t size = desc.getLength();
140 this->reset(size);
141 memcpy(fDesc, &desc, size);
142 }
joshualitt2b6acb42015-04-01 11:30:27 -0700143
144 ~SkAutoDescriptor() { this->free(); }
145
146 void reset(size_t size) {
147 this->free();
reed@google.com142e1fe2012-07-09 17:44:44 +0000148 if (size <= sizeof(fStorage)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000149 fDesc = (SkDescriptor*)(void*)fStorage;
reed@google.com142e1fe2012-07-09 17:44:44 +0000150 } else {
bungeman520ced62016-10-18 08:03:42 -0400151 fDesc = SkDescriptor::Alloc(size).release();
reed@google.com142e1fe2012-07-09 17:44:44 +0000152 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153 }
reed@google.com142e1fe2012-07-09 17:44:44 +0000154
joshualitt2b6acb42015-04-01 11:30:27 -0700155 SkDescriptor* getDesc() const { SkASSERT(fDesc); return fDesc; }
156private:
157 void free() {
reed@google.com142e1fe2012-07-09 17:44:44 +0000158 if (fDesc != (SkDescriptor*)(void*)fStorage) {
bungeman520ced62016-10-18 08:03:42 -0400159 delete fDesc;
reed@google.com142e1fe2012-07-09 17:44:44 +0000160 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161 }
reed@google.com142e1fe2012-07-09 17:44:44 +0000162
reed@android.com8a1c16f2008-12-17 15:59:43 +0000163 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};
commit-bot@chromium.orge61a86c2013-11-18 16:03:59 +0000172#define SkAutoDescriptor(...) SK_REQUIRE_LOCAL_VAR(SkAutoDescriptor)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000173
174
175#endif