Subversion Repositories Scribus

Rev

Rev 14952 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
14952 fschmid 1
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2
/* cairo - a vector graphics library with display and print output
3
 *
4
 * Copyright © 2002 University of Southern California
5
 * Copyright © 2005,2008 Red Hat Inc.
6
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it either under the terms of the GNU Lesser General Public
9
 * License version 2.1 as published by the Free Software Foundation
10
 * (the "LGPL") or, at your option, under the terms of the Mozilla
11
 * Public License Version 1.1 (the "MPL"). If you do not alter this
12
 * notice, a recipient may use your version of this file under either
13
 * the MPL or the LGPL.
14
 *
15
 * You should have received a copy of the LGPL along with this library
16
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18122 mrdocs 17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
14952 fschmid 18
 * You should have received a copy of the MPL along with this library
19
 * in the file COPYING-MPL-1.1
20
 *
21
 * The contents of this file are subject to the Mozilla Public License
22
 * Version 1.1 (the "License"); you may not use this file except in
23
 * compliance with the License. You may obtain a copy of the License at
24
 * http://www.mozilla.org/MPL/
25
 *
26
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28
 * the specific language governing rights and limitations.
29
 *
30
 * The Original Code is the cairo graphics library.
31
 *
32
 * The Initial Developer of the Original Code is University of Southern
33
 * California.
34
 *
35
 * Contributor(s):
36
 *      Carl D. Worth <cworth@cworth.org>
37
 *      Graydon Hoare <graydon@redhat.com>
38
 *      Owen Taylor <otaylor@redhat.com>
39
 *      Behdad Esfahbod <behdad@behdad.org>
40
 */
41
 
42
#define _BSD_SOURCE /* for strdup() */
43
#include "cairoint.h"
44
 
45
 
46
static const cairo_font_face_t _cairo_font_face_null_pointer = {
47
    { 0 },                              /* hash_entry */
48
    CAIRO_STATUS_NULL_POINTER,          /* status */
49
    CAIRO_REFERENCE_COUNT_INVALID,      /* ref_count */
50
    { 0, 0, 0, NULL },                  /* user_data */
51
    NULL
52
};
53
 
54
static const cairo_font_face_t _cairo_font_face_invalid_string = {
55
    { 0 },                              /* hash_entry */
56
    CAIRO_STATUS_INVALID_STRING,        /* status */
57
    CAIRO_REFERENCE_COUNT_INVALID,      /* ref_count */
58
    { 0, 0, 0, NULL },                  /* user_data */
59
    NULL
60
};
61
 
62
static const cairo_font_face_t _cairo_font_face_invalid_slant = {
63
    { 0 },                              /* hash_entry */
64
    CAIRO_STATUS_INVALID_SLANT,         /* status */
65
    CAIRO_REFERENCE_COUNT_INVALID,      /* ref_count */
66
    { 0, 0, 0, NULL },                  /* user_data */
67
    NULL
68
};
69
 
70
static const cairo_font_face_t _cairo_font_face_invalid_weight = {
71
    { 0 },                              /* hash_entry */
72
    CAIRO_STATUS_INVALID_WEIGHT,        /* status */
73
    CAIRO_REFERENCE_COUNT_INVALID,      /* ref_count */
74
    { 0, 0, 0, NULL },                  /* user_data */
75
    NULL
76
};
77
 
78
 
79
static const cairo_font_face_backend_t _cairo_toy_font_face_backend;
80
 
81
static int
82
_cairo_toy_font_face_keys_equal (const void *key_a,
83
                                 const void *key_b);
84
 
85
/* We maintain a hash table from family/weight/slant =>
86
 * #cairo_font_face_t for #cairo_toy_font_t. The primary purpose of
87
 * this mapping is to provide unique #cairo_font_face_t values so that
88
 * our cache and mapping from #cairo_font_face_t => #cairo_scaled_font_t
89
 * works. Once the corresponding #cairo_font_face_t objects fall out of
90
 * downstream caches, we don't need them in this hash table anymore.
91
 *
92
 * Modifications to this hash table are protected by
93
 * _cairo_toy_font_face_mutex.
94
 */
95
static cairo_hash_table_t *cairo_toy_font_face_hash_table = NULL;
96
 
97
static cairo_hash_table_t *
98
_cairo_toy_font_face_hash_table_lock (void)
99
{
100
    CAIRO_MUTEX_LOCK (_cairo_toy_font_face_mutex);
101
 
102
    if (cairo_toy_font_face_hash_table == NULL)
103
    {
104
        cairo_toy_font_face_hash_table =
105
            _cairo_hash_table_create (_cairo_toy_font_face_keys_equal);
106
 
107
        if (cairo_toy_font_face_hash_table == NULL) {
108
            CAIRO_MUTEX_UNLOCK (_cairo_toy_font_face_mutex);
109
            return NULL;
110
        }
111
    }
112
 
113
    return cairo_toy_font_face_hash_table;
114
}
115
 
116
static void
117
_cairo_toy_font_face_hash_table_unlock (void)
118
{
119
    CAIRO_MUTEX_UNLOCK (_cairo_toy_font_face_mutex);
120
}
121
 
122
/**
123
 * _cairo_toy_font_face_init_key:
124
 *
125
 * Initialize those portions of #cairo_toy_font_face_t needed to use
126
 * it as a hash table key, including the hash code buried away in
127
 * font_face->base.hash_entry. No memory allocation is performed here
128
 * so that no fini call is needed. We do this to make it easier to use
129
 * an automatic #cairo_toy_font_face_t variable as a key.
130
 **/
131
static void
132
_cairo_toy_font_face_init_key (cairo_toy_font_face_t *key,
133
                               const char            *family,
134
                               cairo_font_slant_t     slant,
135
                               cairo_font_weight_t    weight)
136
{
137
    unsigned long hash;
138
 
139
    key->family = family;
140
    key->owns_family = FALSE;
141
 
142
    key->slant = slant;
143
    key->weight = weight;
144
 
145
    /* 1607 and 1451 are just a couple of arbitrary primes. */
146
    hash = _cairo_hash_string (family);
147
    hash += ((unsigned long) slant) * 1607;
148
    hash += ((unsigned long) weight) * 1451;
149
 
150
    assert (hash != 0);
151
    key->base.hash_entry.hash = hash;
152
}
153
 
154
static cairo_status_t
155
_cairo_toy_font_face_create_impl_face (cairo_toy_font_face_t *font_face,
156
                                       cairo_font_face_t **impl_font_face)
157
{
158
    const cairo_font_face_backend_t * backend = CAIRO_FONT_FACE_BACKEND_DEFAULT;
159
    cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
160
 
161
    if (unlikely (font_face->base.status))
162
        return font_face->base.status;
163
 
164
    if (backend->create_for_toy != NULL &&
165
 
166
                      strlen (CAIRO_USER_FONT_FAMILY_DEFAULT)))
167
    {
168
        status = backend->create_for_toy (font_face, impl_font_face);
169
    }
170
 
171
    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
172
        backend = &_cairo_user_font_face_backend;
173
        status = backend->create_for_toy (font_face, impl_font_face);
174
    }
175
 
176
    return status;
177
}
178
 
179
static cairo_status_t
180
_cairo_toy_font_face_init (cairo_toy_font_face_t *font_face,
181
                           const char            *family,
182
                           cairo_font_slant_t     slant,
183
                           cairo_font_weight_t    weight)
184
{
185
    char *family_copy;
186
    cairo_status_t status;
187
 
188
    family_copy = strdup (family);
189
    if (unlikely (family_copy == NULL))
190
        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
191
 
192
    _cairo_toy_font_face_init_key (font_face, family_copy, slant, weight);
193
    font_face->owns_family = TRUE;
194
 
195
    _cairo_font_face_init (&font_face->base, &_cairo_toy_font_face_backend);
196
 
197
    status = _cairo_toy_font_face_create_impl_face (font_face,
198
                                                    &font_face->impl_face);
199
    if (unlikely (status)) {
200
        free (family_copy);
201
        return status;
202
    }
203
 
204
    return CAIRO_STATUS_SUCCESS;
205
}
206
 
207
static void
208
_cairo_toy_font_face_fini (cairo_toy_font_face_t *font_face)
209
{
210
    /* We assert here that we own font_face->family before casting
211
     * away the const qualifer. */
212
    assert (font_face->owns_family);
213
    free ((char*) font_face->family);
214
 
215
    if (font_face->impl_face)
216
        cairo_font_face_destroy (font_face->impl_face);
217
}
218
 
219
static int
220
_cairo_toy_font_face_keys_equal (const void *key_a,
221
                                 const void *key_b)
222
{
223
    const cairo_toy_font_face_t *face_a = key_a;
224
    const cairo_toy_font_face_t *face_b = key_b;
225
 
226
    return (strcmp (face_a->family, face_b->family) == 0 &&
227
            face_a->slant == face_b->slant &&
228
            face_a->weight == face_b->weight);
229
}
230
 
231
/**
232
 * cairo_toy_font_face_create:
233
 * @family: a font family name, encoded in UTF-8
234
 * @slant: the slant for the font
235
 * @weight: the weight for the font
236
 *
237
 * Creates a font face from a triplet of family, slant, and weight.
238
 * These font faces are used in implementation of the the #cairo_t "toy"
239
 * font API.
240
 *
241
 * If @family is the zero-length string "", the platform-specific default
242
 * family is assumed.  The default family then can be queried using
243
 * cairo_toy_font_face_get_family().
244
 *
245
 * The cairo_select_font_face() function uses this to create font faces.
246
 * See that function for limitations and other details of toy font faces.
247
 *
248
 * Return value: a newly created #cairo_font_face_t. Free with
249
 *  cairo_font_face_destroy() when you are done using it.
250
 *
251
 * Since: 1.8
252
 **/
253
cairo_font_face_t *
254
cairo_toy_font_face_create (const char          *family,
255
                            cairo_font_slant_t   slant,
256
                            cairo_font_weight_t  weight)
257
{
258
    cairo_status_t status;
259
    cairo_toy_font_face_t key, *font_face;
260
    cairo_hash_table_t *hash_table;
261
 
262
    if (family == NULL)
263
        return (cairo_font_face_t*) &_cairo_font_face_null_pointer;
264
 
265
    /* Make sure we've got valid UTF-8 for the family */
266
    status = _cairo_utf8_to_ucs4 (family, -1, NULL, NULL);
267
    if (unlikely (status)) {
268
        if (status == CAIRO_STATUS_INVALID_STRING)
269
            return (cairo_font_face_t*) &_cairo_font_face_invalid_string;
270
 
271
        return (cairo_font_face_t*) &_cairo_font_face_nil;
272
    }
273
 
274
    switch (slant) {
275
        case CAIRO_FONT_SLANT_NORMAL:
276
        case CAIRO_FONT_SLANT_ITALIC:
277
        case CAIRO_FONT_SLANT_OBLIQUE:
278
            break;
279
        default:
280
            return (cairo_font_face_t*) &_cairo_font_face_invalid_slant;
281
    }
282
 
283
    switch (weight) {
284
        case CAIRO_FONT_WEIGHT_NORMAL:
285
        case CAIRO_FONT_WEIGHT_BOLD:
286
            break;
287
        default:
288
            return (cairo_font_face_t*) &_cairo_font_face_invalid_weight;
289
    }
290
 
291
    if (*family == '\0')
292
        family = CAIRO_FONT_FAMILY_DEFAULT;
293
 
294
    hash_table = _cairo_toy_font_face_hash_table_lock ();
295
    if (unlikely (hash_table == NULL))
296
        goto UNWIND;
297
 
298
    _cairo_toy_font_face_init_key (&key, family, slant, weight);
299
 
300
    /* Return existing font_face if it exists in the hash table. */
301
    font_face = _cairo_hash_table_lookup (hash_table,
302
                                          &key.base.hash_entry);
303
    if (font_face != NULL) {
304
        if (font_face->base.status == CAIRO_STATUS_SUCCESS) {
305
            /* We increment the reference count here manually to avoid
306
               double-locking. */
307
            _cairo_reference_count_inc (&font_face->base.ref_count);
308
            _cairo_toy_font_face_hash_table_unlock ();
309
            return &font_face->base;
310
        }
311
 
312
        /* remove the bad font from the hash table */
313
        _cairo_hash_table_remove (hash_table, &font_face->base.hash_entry);
314
        font_face->base.hash_entry.hash = 0;
315
    }
316
 
317
    /* Otherwise create it and insert into hash table. */
318
    font_face = malloc (sizeof (cairo_toy_font_face_t));
319
    if (unlikely (font_face == NULL)) {
320
        status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
321
        goto UNWIND_HASH_TABLE_LOCK;
322
    }
323
 
324
    status = _cairo_toy_font_face_init (font_face, family, slant, weight);
325
    if (unlikely (status))
326
        goto UNWIND_FONT_FACE_MALLOC;
327
 
328
    assert (font_face->base.hash_entry.hash == key.base.hash_entry.hash);
329
    status = _cairo_hash_table_insert (hash_table, &font_face->base.hash_entry);
330
    if (unlikely (status))
331
        goto UNWIND_FONT_FACE_INIT;
332
 
333
    _cairo_toy_font_face_hash_table_unlock ();
334
 
335
    return &font_face->base;
336
 
337
 UNWIND_FONT_FACE_INIT:
338
    _cairo_toy_font_face_fini (font_face);
339
 UNWIND_FONT_FACE_MALLOC:
340
    free (font_face);
341
 UNWIND_HASH_TABLE_LOCK:
342
    _cairo_toy_font_face_hash_table_unlock ();
343
 UNWIND:
344
    return (cairo_font_face_t*) &_cairo_font_face_nil;
345
}
346
slim_hidden_def (cairo_toy_font_face_create);
347
 
348
static void
349
_cairo_toy_font_face_destroy (void *abstract_face)
350
{
351
    cairo_toy_font_face_t *font_face = abstract_face;
352
    cairo_hash_table_t *hash_table;
353
 
354
    if (font_face == NULL ||
355
            CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->base.ref_count))
356
        return;
357
 
358
    hash_table = _cairo_toy_font_face_hash_table_lock ();
359
    /* All created objects must have been mapped in the hash table. */
360
    assert (hash_table != NULL);
361
 
362
    if (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&font_face->base.ref_count)) {
363
        /* somebody recreated the font whilst we waited for the lock */
364
        _cairo_toy_font_face_hash_table_unlock ();
365
        return;
366
    }
367
 
368
    if (font_face->base.hash_entry.hash != 0)
369
        _cairo_hash_table_remove (hash_table, &font_face->base.hash_entry);
370
 
371
    _cairo_toy_font_face_hash_table_unlock ();
372
 
373
    _cairo_toy_font_face_fini (font_face);
374
}
375
 
376
static cairo_status_t
377
_cairo_toy_font_face_scaled_font_create (void                *abstract_font_face,
378
                                         const cairo_matrix_t       *font_matrix,
379
                                         const cairo_matrix_t       *ctm,
380
                                         const cairo_font_options_t *options,
381
                                         cairo_scaled_font_t       **scaled_font)
382
{
383
    cairo_toy_font_face_t *font_face = (cairo_toy_font_face_t *) abstract_font_face;
384
 
385
    ASSERT_NOT_REACHED;
386
 
387
    return _cairo_font_face_set_error (&font_face->base, CAIRO_STATUS_FONT_TYPE_MISMATCH);
388
}
389
 
390
static cairo_font_face_t *
391
_cairo_toy_font_face_get_implementation (void                *abstract_font_face,
392
                                         const cairo_matrix_t       *font_matrix,
393
                                         const cairo_matrix_t       *ctm,
394
                                         const cairo_font_options_t *options)
395
{
396
    cairo_toy_font_face_t *font_face = abstract_font_face;
397
 
398
    if (font_face->impl_face) {
399
        cairo_font_face_t *impl = font_face->impl_face;
400
 
401
        if (impl->backend->get_implementation != NULL) {
402
            return impl->backend->get_implementation (impl,
403
                                                      font_matrix,
404
                                                      ctm,
405
                                                      options);
406
        }
407
 
408
        return cairo_font_face_reference (impl);
409
    }
410
 
411
    return abstract_font_face;
412
}
413
 
414
static cairo_bool_t
415
_cairo_font_face_is_toy (cairo_font_face_t *font_face)
416
{
417
    return font_face->backend == &_cairo_toy_font_face_backend;
418
}
419
 
420
/**
421
 * cairo_toy_font_face_get_family:
422
 * @font_face: A toy font face
423
 *
424
 * Gets the familly name of a toy font.
425
 *
426
 * Return value: The family name.  This string is owned by the font face
427
 * and remains valid as long as the font face is alive (referenced).
428
 *
429
 * Since: 1.8
430
 **/
431
const char *
432
cairo_toy_font_face_get_family (cairo_font_face_t *font_face)
433
{
434
    cairo_toy_font_face_t *toy_font_face;
435
 
436
    if (font_face->status)
437
        return CAIRO_FONT_FAMILY_DEFAULT;
438
 
439
    toy_font_face = (cairo_toy_font_face_t *) font_face;
440
    if (! _cairo_font_face_is_toy (font_face)) {
441
        if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
442
            return CAIRO_FONT_FAMILY_DEFAULT;
443
    }
444
    assert (toy_font_face->owns_family);
445
    return toy_font_face->family;
446
}
447
 
448
/**
449
 * cairo_toy_font_face_get_slant:
450
 * @font_face: A toy font face
451
 *
452
 * Gets the slant a toy font.
453
 *
454
 * Return value: The slant value
455
 *
456
 * Since: 1.8
457
 **/
458
cairo_font_slant_t
459
cairo_toy_font_face_get_slant (cairo_font_face_t *font_face)
460
{
461
    cairo_toy_font_face_t *toy_font_face;
462
 
463
    if (font_face->status)
464
        return CAIRO_FONT_SLANT_DEFAULT;
465
 
466
    toy_font_face = (cairo_toy_font_face_t *) font_face;
467
    if (! _cairo_font_face_is_toy (font_face)) {
468
        if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
469
            return CAIRO_FONT_SLANT_DEFAULT;
470
    }
471
    return toy_font_face->slant;
472
}
473
slim_hidden_def (cairo_toy_font_face_get_slant);
474
 
475
/**
476
 * cairo_toy_font_face_get_weight:
477
 * @font_face: A toy font face
478
 *
479
 * Gets the weight a toy font.
480
 *
481
 * Return value: The weight value
482
 *
483
 * Since: 1.8
484
 **/
485
cairo_font_weight_t
486
cairo_toy_font_face_get_weight (cairo_font_face_t *font_face)
487
{
488
    cairo_toy_font_face_t *toy_font_face;
489
 
490
    if (font_face->status)
491
        return CAIRO_FONT_WEIGHT_DEFAULT;
492
 
493
    toy_font_face = (cairo_toy_font_face_t *) font_face;
494
    if (! _cairo_font_face_is_toy (font_face)) {
495
        if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
496
            return CAIRO_FONT_WEIGHT_DEFAULT;
497
    }
498
    return toy_font_face->weight;
499
}
500
slim_hidden_def (cairo_toy_font_face_get_weight);
501
 
502
static const cairo_font_face_backend_t _cairo_toy_font_face_backend = {
503
    CAIRO_FONT_TYPE_TOY,
504
    NULL,                                       /* create_for_toy */
505
    _cairo_toy_font_face_destroy,
506
    _cairo_toy_font_face_scaled_font_create,
507
    _cairo_toy_font_face_get_implementation
508
};
509
 
510
void
511
_cairo_toy_font_face_reset_static_data (void)
512
{
513
    cairo_hash_table_t *hash_table;
514
 
515
    /* We manually acquire the lock rather than calling
516
     * cairo_toy_font_face_hash_table_lock simply to avoid
517
     * creating the table only to destroy it again. */
518
    CAIRO_MUTEX_LOCK (_cairo_toy_font_face_mutex);
519
    hash_table = cairo_toy_font_face_hash_table;
520
    cairo_toy_font_face_hash_table = NULL;
521
    CAIRO_MUTEX_UNLOCK (_cairo_toy_font_face_mutex);
522
 
523
    if (hash_table != NULL)
524
        _cairo_hash_table_destroy (hash_table);
525
}