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