Subversion Repositories Kolibri OS

Rev

Rev 1892 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1892 serge 1
/* Cairo - a vector graphics library with display and print output
2
 *
3
 * Copyright © 2009 Intel Corporation
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it either under the terms of the GNU Lesser General Public
7
 * License version 2.1 as published by the Free Software Foundation
8
 * (the "LGPL") or, at your option, under the terms of the Mozilla
9
 * Public License Version 1.1 (the "MPL"). If you do not alter this
10
 * notice, a recipient may use your version of this file under either
11
 * the MPL or the LGPL.
12
 *
13
 * You should have received a copy of the LGPL along with this library
14
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16
 * You should have received a copy of the MPL along with this library
17
 * in the file COPYING-MPL-1.1
18
 *
19
 * The contents of this file are subject to the Mozilla Public License
20
 * Version 1.1 (the "License"); you may not use this file except in
21
 * compliance with the License. You may obtain a copy of the License at
22
 * http://www.mozilla.org/MPL/
23
 *
24
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26
 * the specific language governing rights and limitations.
27
 *
28
 * The Original Code is the cairo graphics library.
29
 *
30
 * The Initial Developer of the Original Code is Intel Corporation.
31
 *
32
 * Contributors(s):
33
 *	Chris Wilson 
34
 */
35
 
36
#include "cairoint.h"
37
#include "cairo-device-private.h"
38
#include "cairo-error-private.h"
39
 
40
/**
41
 * SECTION:cairo-device
42
 * @Title: cairo_device_t
43
 * @Short_Description: interface to underlying rendering system
44
 * @See_Also: #cairo_surface_t
45
 *
46
 * Devices are the abstraction Cairo employs for the rendering system
47
 * used by a #cairo_surface_t. You can get the device of a surface using
48
 * cairo_surface_get_device().
49
 *
50
 * Devices are created using custom functions specific to the rendering
51
 * system you want to use. See the documentation for the surface types
52
 * for those functions.
53
 *
54
 * An important function that devices fulfill is sharing access to the
55
 * rendering system between Cairo and your application. If you want to
56
 * access a device directly that you used to draw to with Cairo, you must
57
 * first call cairo_device_flush() to ensure that Cairo finishes all
58
 * operations on the device and resets it to a clean state.
59
 *
60
 * Cairo also provides the functions cairo_device_acquire() and
61
 * cairo_device_release() to synchronize access to the rendering system
62
 * in a multithreaded environment. This is done internally, but can also
63
 * be used by applications.
64
 *
65
 * Putting this all together, a function that works with devices should
66
 * look something like this:
67
 * 
68
 * void
69
 * my_device_modifying_function (cairo_device_t *device)
70
 * {
71
 *   cairo_status_t status;
72
 *
73
 *   // Ensure the device is properly reset
74
 *   cairo_device_flush (device);
75
 *   // Try to acquire the device
76
 *   status = cairo_device_acquire (device);
77
 *   if (status != CAIRO_STATUS_SUCCESS) {
78
 *     printf ("Failed to acquire the device: %s\n", cairo_status_to_string (status));
79
 *     return;
80
 *   }
81
 *
82
 *   // Do the custom operations on the device here.
83
 *   // But do not call any Cairo functions that might acquire devices.
84
 *
85
 *   // Release the device when done.
86
 *   cairo_device_release (device);
87
 * }
88
 * 
89
 *
90
 * Please refer to the documentation of each backend for
91
 * additional usage requirements, guarantees provided, and
92
 * interactions with existing surface API of the device functions for
93
 * surfaces of that type.
94
 * 
3959 Serge 95
 **/
1892 serge 96
 
97
static const cairo_device_t _nil_device = {
98
    CAIRO_REFERENCE_COUNT_INVALID,
99
    CAIRO_STATUS_NO_MEMORY,
100
};
101
 
102
static const cairo_device_t _mismatch_device = {
103
    CAIRO_REFERENCE_COUNT_INVALID,
104
    CAIRO_STATUS_DEVICE_TYPE_MISMATCH,
105
};
106
 
107
static const cairo_device_t _invalid_device = {
108
    CAIRO_REFERENCE_COUNT_INVALID,
109
    CAIRO_STATUS_DEVICE_ERROR,
110
};
111
 
112
cairo_device_t *
113
_cairo_device_create_in_error (cairo_status_t status)
114
{
115
    switch (status) {
116
    case CAIRO_STATUS_NO_MEMORY:
117
	return (cairo_device_t *) &_nil_device;
118
    case CAIRO_STATUS_DEVICE_ERROR:
119
	return (cairo_device_t *) &_invalid_device;
120
    case CAIRO_STATUS_DEVICE_TYPE_MISMATCH:
121
	return (cairo_device_t *) &_mismatch_device;
122
 
123
    case CAIRO_STATUS_SUCCESS:
124
    case CAIRO_STATUS_LAST_STATUS:
125
	ASSERT_NOT_REACHED;
126
	/* fall-through */
127
    case CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
128
    case CAIRO_STATUS_INVALID_STATUS:
129
    case CAIRO_STATUS_INVALID_FORMAT:
130
    case CAIRO_STATUS_INVALID_VISUAL:
131
    case CAIRO_STATUS_READ_ERROR:
132
    case CAIRO_STATUS_WRITE_ERROR:
133
    case CAIRO_STATUS_FILE_NOT_FOUND:
134
    case CAIRO_STATUS_TEMP_FILE_ERROR:
135
    case CAIRO_STATUS_INVALID_STRIDE:
136
    case CAIRO_STATUS_INVALID_SIZE:
137
    case CAIRO_STATUS_INVALID_RESTORE:
138
    case CAIRO_STATUS_INVALID_POP_GROUP:
139
    case CAIRO_STATUS_NO_CURRENT_POINT:
140
    case CAIRO_STATUS_INVALID_MATRIX:
141
    case CAIRO_STATUS_NULL_POINTER:
142
    case CAIRO_STATUS_INVALID_STRING:
143
    case CAIRO_STATUS_INVALID_PATH_DATA:
144
    case CAIRO_STATUS_SURFACE_FINISHED:
145
    case CAIRO_STATUS_PATTERN_TYPE_MISMATCH:
146
    case CAIRO_STATUS_INVALID_DASH:
147
    case CAIRO_STATUS_INVALID_DSC_COMMENT:
148
    case CAIRO_STATUS_INVALID_INDEX:
149
    case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE:
150
    case CAIRO_STATUS_FONT_TYPE_MISMATCH:
151
    case CAIRO_STATUS_USER_FONT_IMMUTABLE:
152
    case CAIRO_STATUS_USER_FONT_ERROR:
153
    case CAIRO_STATUS_NEGATIVE_COUNT:
154
    case CAIRO_STATUS_INVALID_CLUSTERS:
155
    case CAIRO_STATUS_INVALID_SLANT:
156
    case CAIRO_STATUS_INVALID_WEIGHT:
157
    case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED:
158
    case CAIRO_STATUS_INVALID_CONTENT:
3959 Serge 159
    case CAIRO_STATUS_INVALID_MESH_CONSTRUCTION:
160
    case CAIRO_STATUS_DEVICE_FINISHED:
1892 serge 161
    default:
162
	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
163
	return (cairo_device_t *) &_nil_device;
164
    }
165
}
166
 
167
void
168
_cairo_device_init (cairo_device_t *device,
169
		    const cairo_device_backend_t *backend)
170
{
171
    CAIRO_REFERENCE_COUNT_INIT (&device->ref_count, 1);
172
    device->status = CAIRO_STATUS_SUCCESS;
173
 
174
    device->backend = backend;
175
 
176
    CAIRO_RECURSIVE_MUTEX_INIT (device->mutex);
177
    device->mutex_depth = 0;
178
 
179
    device->finished = FALSE;
180
 
181
    _cairo_user_data_array_init (&device->user_data);
182
}
183
 
184
/**
185
 * cairo_device_reference:
186
 * @device: a #cairo_device_t
187
 *
188
 * Increases the reference count on @device by one. This prevents
189
 * @device from being destroyed until a matching call to
190
 * cairo_device_destroy() is made.
191
 *
192
 * The number of references to a #cairo_device_t can be get using
193
 * cairo_device_get_reference_count().
194
 *
195
 * Return value: the referenced #cairo_device_t.
196
 *
197
 * Since: 1.10
198
 **/
199
cairo_device_t *
200
cairo_device_reference (cairo_device_t *device)
201
{
202
    if (device == NULL ||
203
	CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
204
    {
205
	return device;
206
    }
207
 
208
    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count));
209
    _cairo_reference_count_inc (&device->ref_count);
210
 
211
    return device;
212
}
213
slim_hidden_def (cairo_device_reference);
214
 
215
/**
216
 * cairo_device_status:
217
 * @device: a #cairo_device_t
218
 *
219
 * Checks whether an error has previously occurred for this
220
 * device.
221
 *
222
 * Return value: %CAIRO_STATUS_SUCCESS on success or an error code if
223
 *               the device is in an error state.
224
 *
225
 * Since: 1.10
226
 **/
227
cairo_status_t
228
cairo_device_status (cairo_device_t *device)
229
{
230
    if (device == NULL)
231
	return CAIRO_STATUS_NULL_POINTER;
232
 
233
    return device->status;
234
}
235
 
236
/**
237
 * cairo_device_flush:
238
 * @device: a #cairo_device_t
239
 *
240
 * Finish any pending operations for the device and also restore any
241
 * temporary modifications cairo has made to the device's state.
242
 * This function must be called before switching from using the
243
 * device with Cairo to operating on it directly with native APIs.
244
 * If the device doesn't support direct access, then this function
245
 * does nothing.
246
 *
247
 * This function may acquire devices.
248
 *
249
 * Since: 1.10
250
 **/
251
void
252
cairo_device_flush (cairo_device_t *device)
253
{
254
    cairo_status_t status;
255
 
256
    if (device == NULL || device->status)
257
	return;
258
 
3959 Serge 259
    if (device->finished)
260
	return;
261
 
1892 serge 262
    if (device->backend->flush != NULL) {
263
	status = device->backend->flush (device);
264
	if (unlikely (status))
265
	    status = _cairo_device_set_error (device, status);
266
    }
267
}
268
slim_hidden_def (cairo_device_flush);
269
 
270
/**
271
 * cairo_device_finish:
272
 * @device: the #cairo_device_t to finish
273
 *
274
 * This function finishes the device and drops all references to
275
 * external resources. All surfaces, fonts and other objects created
276
 * for this @device will be finished, too.
277
 * Further operations on the @device will not affect the @device but
278
 * will instead trigger a %CAIRO_STATUS_DEVICE_FINISHED error.
279
 *
280
 * When the last call to cairo_device_destroy() decreases the
281
 * reference count to zero, cairo will call cairo_device_finish() if
282
 * it hasn't been called already, before freeing the resources
283
 * associated with the device.
284
 *
285
 * This function may acquire devices.
286
 *
287
 * Since: 1.10
288
 **/
289
void
290
cairo_device_finish (cairo_device_t *device)
291
{
292
    if (device == NULL ||
293
	CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
294
    {
295
	return;
296
    }
297
 
298
    if (device->finished)
299
	return;
300
 
301
    cairo_device_flush (device);
302
 
303
    if (device->backend->finish != NULL)
304
	device->backend->finish (device);
3959 Serge 305
 
306
    /* We only finish the device after the backend's callback returns because
307
     * the device might still be needed during the callback
308
     * (e.g. for cairo_device_acquire ()).
309
     */
310
    device->finished = TRUE;
1892 serge 311
}
312
slim_hidden_def (cairo_device_finish);
313
 
314
/**
315
 * cairo_device_destroy:
316
 * @device: a #cairo_device_t
317
 *
318
 * Decreases the reference count on @device by one. If the result is
319
 * zero, then @device and all associated resources are freed.  See
320
 * cairo_device_reference().
321
 *
322
 * This function may acquire devices if the last reference was dropped.
323
 *
324
 * Since: 1.10
325
 **/
326
void
327
cairo_device_destroy (cairo_device_t *device)
328
{
329
    cairo_user_data_array_t user_data;
330
 
331
    if (device == NULL ||
332
	CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
333
    {
334
	return;
335
    }
336
 
337
    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count));
338
    if (! _cairo_reference_count_dec_and_test (&device->ref_count))
339
	return;
340
 
341
    cairo_device_finish (device);
342
 
343
    assert (device->mutex_depth == 0);
344
    CAIRO_MUTEX_FINI (device->mutex);
345
 
346
    user_data = device->user_data;
347
 
348
    device->backend->destroy (device);
349
 
350
    _cairo_user_data_array_fini (&user_data);
351
 
352
}
353
slim_hidden_def (cairo_device_destroy);
354
 
355
/**
356
 * cairo_device_get_type:
357
 * @device: a #cairo_device_t
358
 *
359
 * This function returns the type of the device. See #cairo_device_type_t
360
 * for available types.
361
 *
362
 * Return value: The type of @device.
363
 *
364
 * Since: 1.10
365
 **/
366
cairo_device_type_t
367
cairo_device_get_type (cairo_device_t *device)
368
{
369
    if (device == NULL ||
370
	CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
371
    {
3959 Serge 372
	return CAIRO_DEVICE_TYPE_INVALID;
1892 serge 373
    }
374
 
375
    return device->backend->type;
376
}
377
 
378
/**
379
 * cairo_device_acquire:
380
 * @device: a #cairo_device_t
381
 *
382
 * Acquires the @device for the current thread. This function will block
383
 * until no other thread has acquired the device.
384
 *
385
 * If the return value is %CAIRO_STATUS_SUCCESS, you successfully acquired the
386
 * device. From now on your thread owns the device and no other thread will be
387
 * able to acquire it until a matching call to cairo_device_release(). It is
388
 * allowed to recursively acquire the device multiple times from the same
389
 * thread.
390
 *
391
 * You must never acquire two different devices at the same time
392
 * unless this is explicitly allowed. Otherwise the possibility of deadlocks
393
 * exist.
394
 *
395
 * As various Cairo functions can acquire devices when called, these functions
396
 * may also cause deadlocks when you call them with an acquired device. So you
397
 * must not have a device acquired when calling them. These functions are
398
 * marked in the documentation.
399
 * 
400
 *
401
 * Return value: %CAIRO_STATUS_SUCCESS on success or an error code if
402
 *               the device is in an error state and could not be
403
 *               acquired. After a successful call to cairo_device_acquire(),
404
 *               a matching call to cairo_device_release() is required.
405
 *
406
 * Since: 1.10
407
 **/
408
cairo_status_t
409
cairo_device_acquire (cairo_device_t *device)
410
{
411
    if (device == NULL)
412
	return CAIRO_STATUS_SUCCESS;
413
 
414
    if (unlikely (device->status))
415
	return device->status;
416
 
417
    if (unlikely (device->finished))
3959 Serge 418
	return _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_FINISHED);
1892 serge 419
 
420
    CAIRO_MUTEX_LOCK (device->mutex);
421
    if (device->mutex_depth++ == 0) {
422
	if (device->backend->lock != NULL)
423
	    device->backend->lock (device);
424
    }
425
 
426
    return CAIRO_STATUS_SUCCESS;
427
}
428
slim_hidden_def (cairo_device_acquire);
429
 
430
/**
431
 * cairo_device_release:
432
 * @device: a #cairo_device_t
433
 *
434
 * Releases a @device previously acquired using cairo_device_acquire(). See
435
 * that function for details.
436
 *
437
 * Since: 1.10
438
 **/
439
void
440
cairo_device_release (cairo_device_t *device)
441
{
442
    if (device == NULL)
443
	return;
444
 
445
    assert (device->mutex_depth > 0);
446
 
447
    if (--device->mutex_depth == 0) {
448
	if (device->backend->unlock != NULL)
449
	    device->backend->unlock (device);
450
    }
451
 
452
    CAIRO_MUTEX_UNLOCK (device->mutex);
453
}
454
slim_hidden_def (cairo_device_release);
455
 
456
cairo_status_t
457
_cairo_device_set_error (cairo_device_t *device,
458
			 cairo_status_t  status)
459
{
3959 Serge 460
    if (status == CAIRO_STATUS_SUCCESS)
461
        return CAIRO_STATUS_SUCCESS;
1892 serge 462
 
463
    _cairo_status_set_error (&device->status, status);
464
 
465
    return _cairo_error (status);
466
}
467
 
468
/**
469
 * cairo_device_get_reference_count:
470
 * @device: a #cairo_device_t
471
 *
472
 * Returns the current reference count of @device.
473
 *
474
 * Return value: the current reference count of @device.  If the
475
 * object is a nil object, 0 will be returned.
476
 *
477
 * Since: 1.10
478
 **/
479
unsigned int
480
cairo_device_get_reference_count (cairo_device_t *device)
481
{
482
    if (device == NULL ||
483
	CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
484
	return 0;
485
 
486
    return CAIRO_REFERENCE_COUNT_GET_VALUE (&device->ref_count);
487
}
488
 
489
/**
490
 * cairo_device_get_user_data:
491
 * @device: a #cairo_device_t
492
 * @key: the address of the #cairo_user_data_key_t the user data was
493
 * attached to
494
 *
495
 * Return user data previously attached to @device using the
496
 * specified key.  If no user data has been attached with the given
497
 * key this function returns %NULL.
498
 *
499
 * Return value: the user data previously attached or %NULL.
500
 *
501
 * Since: 1.10
502
 **/
503
void *
504
cairo_device_get_user_data (cairo_device_t		 *device,
505
			    const cairo_user_data_key_t *key)
506
{
507
    return _cairo_user_data_array_get_data (&device->user_data,
508
					    key);
509
}
510
 
511
/**
512
 * cairo_device_set_user_data:
513
 * @device: a #cairo_device_t
514
 * @key: the address of a #cairo_user_data_key_t to attach the user data to
515
 * @user_data: the user data to attach to the #cairo_device_t
516
 * @destroy: a #cairo_destroy_func_t which will be called when the
517
 * #cairo_t is destroyed or when new user data is attached using the
518
 * same key.
519
 *
520
 * Attach user data to @device.  To remove user data from a surface,
521
 * call this function with the key that was used to set it and %NULL
522
 * for @data.
523
 *
524
 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
525
 * slot could not be allocated for the user data.
526
 *
527
 * Since: 1.10
528
 **/
529
cairo_status_t
530
cairo_device_set_user_data (cairo_device_t		 *device,
531
			    const cairo_user_data_key_t *key,
532
			    void			 *user_data,
533
			    cairo_destroy_func_t	  destroy)
534
{
535
    if (CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
536
	return device->status;
537
 
538
    return _cairo_user_data_array_set_data (&device->user_data,
539
					    key, user_data, destroy);
540
}