use non-deprecated encoding ids for freetype 2
[imager.git] / context.c
1 #include "imageri.h"
2 #include <stdio.h>
3
4 static volatile im_slot_t slot_count = 1;
5 static im_slot_destroy_t *volatile slot_destructors;
6 static volatile i_mutex_t slot_mutex;
7
8 /*
9 =item im_context_new()
10
11 Create a new Imager context object.
12
13 =cut
14 */
15
16 im_context_t
17 im_context_new(void) {
18   im_context_t ctx = malloc(sizeof(im_context_struct));
19   int i;
20
21   if (!slot_mutex)
22     slot_mutex = i_mutex_new();
23
24   if (!ctx)
25     return NULL;
26   
27   ctx->error_sp = IM_ERROR_COUNT-1;
28   for (i = 0; i < IM_ERROR_COUNT; ++i) {
29     ctx->error_alloc[i] = 0;
30     ctx->error_stack[i].msg = NULL;
31     ctx->error_stack[i].code = 0;
32   }
33 #ifdef IMAGER_LOG
34   ctx->log_level = 0;
35   ctx->lg_file = NULL;
36 #endif
37   ctx->max_width = 0;
38   ctx->max_height = 0;
39   ctx->max_bytes = DEF_BYTES_LIMIT;
40
41   ctx->slot_alloc = slot_count;
42   ctx->slots = calloc(sizeof(void *), ctx->slot_alloc);
43   if (!ctx->slots) {
44     free(ctx);
45     return NULL;
46   }
47
48   ctx->refcount = 1;
49
50 #ifdef IMAGER_TRACE_CONTEXT
51   fprintf(stderr, "im_context: created %p\n", ctx);
52 #endif
53
54
55   return ctx;
56 }
57
58 /*
59 =item im_context_refinc(ctx, where)
60 X<im_context_refinc API>
61 =section Context objects
62 =synopsis im_context_refinc(aIMCTX, "a description");
63
64 Add a new reference to the context.
65
66 =cut
67 */
68
69 void
70 im_context_refinc(im_context_t ctx, const char *where) {
71   ++ctx->refcount;
72
73 #ifdef IMAGER_TRACE_CONTEXT
74   fprintf(stderr, "im_context:%s: refinc %p (count now %lu)\n", where,
75           ctx, (unsigned long)ctx->refcount);
76 #endif
77 }
78
79 /*
80 =item im_context_refdec(ctx, where)
81 X<im_context_refdec API>
82 =section Context objects
83 =synopsis im_context_refdec(aIMCTX, "a description");
84
85 Remove a reference to the context, releasing it if all references have
86 been removed.
87
88 =cut
89 */
90
91 void
92 im_context_refdec(im_context_t ctx, const char *where) {
93   int i;
94   im_slot_t slot;
95
96   im_assert(ctx->refcount > 0);
97
98   --ctx->refcount;
99
100 #ifdef IMAGER_TRACE_CONTEXT
101   fprintf(stderr, "im_context:%s: delete %p (count now %lu)\n", where,
102           ctx, (unsigned long)ctx->refcount);
103 #endif
104
105   if (ctx->refcount != 0)
106     return;
107
108   /* lock here to avoid slot_destructors from being moved under us */
109   i_mutex_lock(slot_mutex);
110   for (slot = 0; slot < ctx->slot_alloc; ++slot) {
111     if (ctx->slots[slot] && slot_destructors[slot])
112       slot_destructors[slot](ctx->slots[slot]);
113   }
114   i_mutex_unlock(slot_mutex);
115
116   free(ctx->slots);
117
118   for (i = 0; i < IM_ERROR_COUNT; ++i) {
119     if (ctx->error_stack[i].msg)
120       myfree(ctx->error_stack[i].msg);
121   }
122 #ifdef IMAGER_LOG
123   if (ctx->lg_file && ctx->own_log)
124     fclose(ctx->lg_file);
125 #endif
126
127   free(ctx);
128 }
129
130 /*
131 =item im_context_clone(ctx)
132
133 Clone an Imager context object, returning the result.
134
135 The error stack is not copied from the original context.
136
137 =cut
138 */
139
140 im_context_t
141 im_context_clone(im_context_t ctx, const char *where) {
142   im_context_t nctx = malloc(sizeof(im_context_struct));
143   int i;
144
145   if (!nctx)
146     return NULL;
147
148   nctx->slot_alloc = slot_count;
149   nctx->slots = calloc(sizeof(void *), nctx->slot_alloc);
150   if (!nctx->slots) {
151     free(nctx);
152     return NULL;
153   }
154
155   nctx->error_sp = IM_ERROR_COUNT-1;
156   for (i = 0; i < IM_ERROR_COUNT; ++i) {
157     nctx->error_alloc[i] = 0;
158     nctx->error_stack[i].msg = NULL;
159   }
160 #ifdef IMAGER_LOG
161   nctx->log_level = ctx->log_level;
162   if (ctx->lg_file) {
163     if (ctx->own_log) {
164       int newfd = dup(fileno(ctx->lg_file));
165       if (newfd >= 0) {
166         nctx->own_log = 1;
167         nctx->lg_file = fdopen(newfd, "w");
168         if (nctx->lg_file)
169           setvbuf(nctx->lg_file, NULL, _IONBF, BUFSIZ);
170       }
171       else {
172 #ifdef IMAGER_TRACE_CONTEXT
173         perror("im_context:failed to clone log");
174 #endif
175         free(nctx->slots);
176         free(nctx);
177         return NULL;
178       }
179     }
180     else {
181       /* stderr */
182       nctx->lg_file = ctx->lg_file;
183       nctx->own_log = 0;
184     }
185   }
186   else {
187     nctx->lg_file = NULL;
188   }
189 #endif
190   nctx->max_width = ctx->max_width;
191   nctx->max_height = ctx->max_height;
192   nctx->max_bytes = ctx->max_bytes;
193
194   nctx->refcount = 1;
195
196 #ifdef IMAGER_TRACE_CONTEXT
197   fprintf(stderr, "im_context:%s: cloned %p to %p\n", where, ctx, nctx);
198 #endif
199
200   return nctx;
201 }
202
203 /*
204 =item im_context_slot_new(destructor)
205
206 Allocate a new context-local-storage slot.
207
208 C<desctructor> will be called when the context is destroyed if the
209 corresponding slot is non-NULL.
210
211 =cut
212 */
213
214 im_slot_t
215 im_context_slot_new(im_slot_destroy_t destructor) {
216   im_slot_t new_slot;
217   im_slot_destroy_t *new_destructors;
218   if (!slot_mutex)
219     slot_mutex = i_mutex_new();
220
221   i_mutex_lock(slot_mutex);
222
223   new_slot = slot_count++;
224   new_destructors = realloc(slot_destructors, sizeof(void *) * slot_count);
225   if (!new_destructors)
226     i_fatal(1, "Cannot allocate memory for slot destructors");
227   slot_destructors = new_destructors;
228
229   slot_destructors[new_slot] = destructor;
230
231   i_mutex_unlock(slot_mutex);
232
233   return new_slot;
234 }
235
236 /*
237 =item im_context_slot_set(slot, value)
238
239 Set the value of a slot.
240
241 Returns true on success.
242
243 Aborts if the slot supplied is invalid.
244
245 If reallocation of slot storage fails, returns false.
246
247 =cut
248 */
249
250 int
251 im_context_slot_set(im_context_t ctx, im_slot_t slot, void *value) {
252   if (slot < 0 || slot >= slot_count) {
253     fprintf(stderr, "Invalid slot %d (valid 0 - %d)\n",
254             (int)slot, (int)slot_count-1);
255     abort();
256   }
257
258   if (slot >= ctx->slot_alloc) {
259     ssize_t i;
260     size_t new_alloc = slot_count;
261     void **new_slots = realloc(ctx->slots, sizeof(void *) * new_alloc);
262
263     if (!new_slots)
264       return 0;
265
266     for (i = ctx->slot_alloc; i < new_alloc; ++i)
267       new_slots[i] = NULL;
268
269     ctx->slots = new_slots;
270     ctx->slot_alloc = new_alloc;
271   }
272
273   ctx->slots[slot] = value;
274
275   return 1;
276 }
277
278 /*
279 =item im_context_slot_get(ctx, slot)
280
281 Retrieve the value previously stored in the given slot of the context
282 object.
283
284 =cut
285 */
286
287 void *
288 im_context_slot_get(im_context_t ctx, im_slot_t slot) {
289   if (slot < 0 || slot >= slot_count) {
290     fprintf(stderr, "Invalid slot %d (valid 0 - %d)\n",
291             (int)slot, (int)slot_count-1);
292     abort();
293   }
294
295   if (slot >= ctx->slot_alloc)
296     return NULL;
297
298   return ctx->slots[slot];
299 }