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