1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef MOZILLA_GFX_USERDATA_H_ 8 #define MOZILLA_GFX_USERDATA_H_ 9 10 #include <stdlib.h> 11 #include "Types.h" 12 #include "mozilla/Assertions.h" 13 14 namespace mozilla { 15 namespace gfx { 16 17 struct UserDataKey { 18 int unused; 19 }; 20 21 /* this class is basically a clone of the user data concept from cairo */ 22 class UserData { 23 typedef void (*destroyFunc)(void* data); 24 25 public: UserData()26 UserData() : count(0), entries(nullptr) {} 27 28 /* Attaches untyped userData associated with key. destroy is called on 29 * destruction */ Add(UserDataKey * key,void * userData,destroyFunc destroy)30 void Add(UserDataKey* key, void* userData, destroyFunc destroy) { 31 for (int i = 0; i < count; i++) { 32 if (key == entries[i].key) { 33 if (entries[i].destroy) { 34 entries[i].destroy(entries[i].userData); 35 } 36 entries[i].userData = userData; 37 entries[i].destroy = destroy; 38 return; 39 } 40 } 41 42 // We could keep entries in a std::vector instead of managing it by hand 43 // but that would propagate an stl dependency out which we'd rather not 44 // do (see bug 666609). Plus, the entries array is expect to stay small 45 // so doing a realloc everytime we add a new entry shouldn't be too costly 46 entries = 47 static_cast<Entry*>(realloc(entries, sizeof(Entry) * (count + 1))); 48 49 if (!entries) { 50 MOZ_CRASH("GFX: UserData::Add"); 51 } 52 53 entries[count].key = key; 54 entries[count].userData = userData; 55 entries[count].destroy = destroy; 56 57 count++; 58 } 59 60 /* Remove and return user data associated with key, without destroying it */ Remove(UserDataKey * key)61 void* Remove(UserDataKey* key) { 62 for (int i = 0; i < count; i++) { 63 if (key == entries[i].key) { 64 void* userData = entries[i].userData; 65 // decrement before looping so entries[i+1] doesn't read past the end: 66 --count; 67 for (; i < count; i++) { 68 entries[i] = entries[i + 1]; 69 } 70 return userData; 71 } 72 } 73 return nullptr; 74 } 75 76 /* Remove and destroy a given key */ RemoveAndDestroy(UserDataKey * key)77 void RemoveAndDestroy(UserDataKey* key) { 78 for (int i = 0; i < count; i++) { 79 if (key == entries[i].key) { 80 if (entries[i].destroy) { 81 entries[i].destroy(entries[i].userData); 82 } 83 // decrement before looping so entries[i+1] doesn't read past the end: 84 --count; 85 for (; i < count; i++) { 86 entries[i] = entries[i + 1]; 87 } 88 } 89 } 90 } 91 92 /* Retrives the userData for the associated key */ Get(UserDataKey * key)93 void* Get(UserDataKey* key) const { 94 for (int i = 0; i < count; i++) { 95 if (key == entries[i].key) { 96 return entries[i].userData; 97 } 98 } 99 return nullptr; 100 } 101 Has(UserDataKey * key)102 bool Has(UserDataKey* key) { 103 for (int i = 0; i < count; i++) { 104 if (key == entries[i].key) { 105 return true; 106 } 107 } 108 return false; 109 } 110 Destroy()111 void Destroy() { 112 for (int i = 0; i < count; i++) { 113 if (entries[i].destroy) { 114 entries[i].destroy(entries[i].userData); 115 } 116 } 117 free(entries); 118 entries = nullptr; 119 count = 0; 120 } 121 ~UserData()122 ~UserData() { Destroy(); } 123 124 private: 125 struct Entry { 126 const UserDataKey* key; 127 void* userData; 128 destroyFunc destroy; 129 }; 130 131 int count; 132 Entry* entries; 133 }; 134 135 } // namespace gfx 136 } // namespace mozilla 137 138 #endif /* MOZILLA_GFX_USERDATA_H_ */ 139