~ubuntu-branches/ubuntu/intrepid/cairo/intrepid-updates

« back to all changes in this revision

Viewing changes to src/cairo-scaled-font.c

  • Committer: Bazaar Package Importer
  • Author(s): Fabien Tassin
  • Date: 2008-09-25 16:22:33 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20080925162233-btx61ymk181i7mcc
Tags: 1.7.6-0ubuntu1
* New upstream version. Most noticable changes are:
  - some API changes with especially the removal of
    cairo_font_options_set_lcd_filter and cairo_font_options_get_lcd_filter
  - xlib: Faster bookkeeping
  - PS: Fix gradients with non-constant alpha
  - Fix deadlock in user-font code
* debian/patches/00list: Remove 03_from_git_fix_lcd_filter_default.dpatch,
  add debian/patches/03_fix_ftbfs_withing_xcb.dpatch
* debian/libcairo2.symbols, debian/libcairo-directfb2.symbols: update
  list of symbols

Show diffs side-by-side

added added

removed removed

Lines of Context:
299
299
#define CAIRO_SCALED_FONT_MAX_HOLDOVERS 256
300
300
 
301
301
typedef struct _cairo_scaled_font_map {
 
302
    cairo_scaled_font_t *mru_scaled_font;
302
303
    cairo_hash_table_t *hash_table;
303
304
    cairo_scaled_font_t *holdovers[CAIRO_SCALED_FONT_MAX_HOLDOVERS];
304
305
    int num_holdovers;
319
320
        if (cairo_scaled_font_map == NULL)
320
321
            goto CLEANUP_MUTEX_LOCK;
321
322
 
 
323
        cairo_scaled_font_map->mru_scaled_font = NULL;
322
324
        cairo_scaled_font_map->hash_table =
323
325
            _cairo_hash_table_create (_cairo_scaled_font_keys_equal);
324
326
 
358
360
        goto CLEANUP_MUTEX_LOCK;
359
361
    }
360
362
 
 
363
    scaled_font = font_map->mru_scaled_font;
 
364
    if (scaled_font != NULL) {
 
365
        CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
 
366
        cairo_scaled_font_destroy (scaled_font);
 
367
        CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
 
368
    }
 
369
 
361
370
    /* remove scaled_fonts starting from the end so that font_map->holdovers
362
371
     * is always in a consistent state when we release the mutex. */
363
372
    while (font_map->num_holdovers) {
364
373
        scaled_font = font_map->holdovers[font_map->num_holdovers-1];
365
 
 
366
374
        assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
367
375
        _cairo_hash_table_remove (font_map->hash_table,
368
376
                                  &scaled_font->hash_entry);
399
407
 *
400
408
 * The reason we have to create a fake scaled font instead of just using
401
409
 * scaled_font is for lifecycle management: we need to (or rather,
402
 
 * other code needs to) reference the scaked_font in the hash.
 
410
 * other code needs to) reference the scaked_font in the hash table.
403
411
 * We can't do that on the input scaled_font as it may be freed by
404
412
 * font backend upon error.
405
413
 */
469
477
    _cairo_hash_table_remove (cairo_scaled_font_map->hash_table,
470
478
                              &scaled_font->hash_entry);
471
479
 
472
 
    CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
 
480
    CAIRO_MUTEX_UNLOCK (placeholder_scaled_font->mutex);
473
481
 
474
482
    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
475
483
    cairo_scaled_font_destroy (placeholder_scaled_font);
477
485
}
478
486
 
479
487
static void
480
 
_cairo_scaled_font_placeholder_wait_for_creation_to_finish (cairo_scaled_font_t *scaled_font)
 
488
_cairo_scaled_font_placeholder_wait_for_creation_to_finish (cairo_scaled_font_t *placeholder_scaled_font)
481
489
{
482
490
    /* reference the place holder so it doesn't go away */
483
 
    cairo_scaled_font_reference (scaled_font);
 
491
    cairo_scaled_font_reference (placeholder_scaled_font);
484
492
 
485
493
    /* now unlock the fontmap mutex so creation has a chance to finish */
486
494
    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
487
495
 
488
496
    /* wait on placeholder mutex until we are awaken */
489
 
    CAIRO_MUTEX_LOCK (scaled_font->mutex);
 
497
    CAIRO_MUTEX_LOCK (placeholder_scaled_font->mutex);
490
498
 
491
499
    /* ok, creation done.  just clean up and back out */
492
 
    CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
 
500
    CAIRO_MUTEX_UNLOCK (placeholder_scaled_font->mutex);
493
501
    CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
494
 
    cairo_scaled_font_destroy (scaled_font);
 
502
    cairo_scaled_font_destroy (placeholder_scaled_font);
495
503
}
496
504
 
497
505
/* Fowler / Noll / Vo (FNV) Hash (http://www.isthe.com/chongo/tech/comp/fnv/)
673
681
    cairo_status_t status;
674
682
    double  font_scale_x, font_scale_y;
675
683
 
676
 
    status = _cairo_matrix_compute_scale_factors (&scaled_font->font_matrix,
 
684
    status = _cairo_matrix_compute_basis_scale_factors (&scaled_font->font_matrix,
677
685
                                                  &font_scale_x, &font_scale_y,
678
686
                                                  1);
679
687
    if (status)
745
753
{
746
754
    cairo_status_t status;
747
755
    cairo_scaled_font_map_t *font_map;
748
 
    cairo_scaled_font_t key, *scaled_font = NULL;
 
756
    cairo_scaled_font_t key, *old = NULL, *scaled_font = NULL;
749
757
 
750
758
    if (font_face->status)
751
759
        return _cairo_scaled_font_create_in_error (font_face->status);
763
771
 
764
772
    _cairo_scaled_font_init_key (&key, font_face,
765
773
                                 font_matrix, ctm, options);
766
 
 
767
 
 
768
 
    while (_cairo_hash_table_lookup (font_map->hash_table, &key.hash_entry,
769
 
                                     (cairo_hash_entry_t**) &scaled_font))
770
 
    {
771
 
        if (!scaled_font->placeholder)
772
 
            break;
773
 
 
774
 
        /* If the scaled font is being created (happens for user-font),
775
 
         * just wait until it's done, then retry */
776
 
        _cairo_scaled_font_placeholder_wait_for_creation_to_finish (scaled_font);
777
 
    }
778
 
 
779
 
    /* Return existing scaled_font if it exists in the hash table. */
780
 
    if (scaled_font)
781
 
    {
782
 
        /* If the original reference count is 0, then this font must have
783
 
         * been found in font_map->holdovers, (which means this caching is
784
 
         * actually working). So now we remove it from the holdovers
785
 
         * array. */
786
 
        if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count)) {
787
 
            int i;
788
 
 
789
 
            for (i = 0; i < font_map->num_holdovers; i++)
790
 
                if (font_map->holdovers[i] == scaled_font)
791
 
                    break;
792
 
            assert (i < font_map->num_holdovers);
793
 
 
794
 
            font_map->num_holdovers--;
795
 
            memmove (&font_map->holdovers[i],
796
 
                     &font_map->holdovers[i+1],
797
 
                     (font_map->num_holdovers - i) * sizeof (cairo_scaled_font_t*));
798
 
 
799
 
            /* reset any error status */
800
 
            scaled_font->status = CAIRO_STATUS_SUCCESS;
801
 
        }
 
774
    scaled_font = font_map->mru_scaled_font;
 
775
    if (scaled_font != NULL &&
 
776
        scaled_font->hash_entry.hash == key.hash_entry.hash &&
 
777
        _cairo_scaled_font_keys_equal (scaled_font, &key))
 
778
    {
 
779
        assert (! scaled_font->placeholder);
802
780
 
803
781
        if (scaled_font->status == CAIRO_STATUS_SUCCESS) {
804
782
            /* We increment the reference count manually here, (rather
814
792
        _cairo_hash_table_remove (font_map->hash_table, &key.hash_entry);
815
793
        scaled_font->hash_entry.hash = ZOMBIE;
816
794
    }
 
795
    else
 
796
    {
 
797
        while (_cairo_hash_table_lookup (font_map->hash_table, &key.hash_entry,
 
798
                                         (cairo_hash_entry_t**) &scaled_font))
 
799
        {
 
800
            if (! scaled_font->placeholder)
 
801
                break;
 
802
 
 
803
            /* If the scaled font is being created (happens for user-font),
 
804
             * just wait until it's done, then retry */
 
805
            _cairo_scaled_font_placeholder_wait_for_creation_to_finish (scaled_font);
 
806
        }
 
807
 
 
808
        /* Return existing scaled_font if it exists in the hash table. */
 
809
        if (scaled_font != NULL) {
 
810
            /* If the original reference count is 0, then this font must have
 
811
             * been found in font_map->holdovers, (which means this caching is
 
812
             * actually working). So now we remove it from the holdovers
 
813
             * array. */
 
814
            if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count)) {
 
815
                int i;
 
816
 
 
817
                for (i = 0; i < font_map->num_holdovers; i++)
 
818
                    if (font_map->holdovers[i] == scaled_font)
 
819
                        break;
 
820
                assert (i < font_map->num_holdovers);
 
821
 
 
822
                font_map->num_holdovers--;
 
823
                memmove (&font_map->holdovers[i],
 
824
                         &font_map->holdovers[i+1],
 
825
                         (font_map->num_holdovers - i) * sizeof (cairo_scaled_font_t*));
 
826
 
 
827
                /* reset any error status */
 
828
                scaled_font->status = CAIRO_STATUS_SUCCESS;
 
829
            }
 
830
 
 
831
            if (scaled_font->status == CAIRO_STATUS_SUCCESS) {
 
832
                /* We increment the reference count manually here, (rather
 
833
                 * than calling into cairo_scaled_font_reference), since we
 
834
                 * must modify the reference count while our lock is still
 
835
                 * held. */
 
836
 
 
837
                old = font_map->mru_scaled_font;
 
838
                font_map->mru_scaled_font = scaled_font;
 
839
                /* increment reference count for the mru cache */
 
840
                _cairo_reference_count_inc (&scaled_font->ref_count);
 
841
                /* and increment for the returned reference */
 
842
                _cairo_reference_count_inc (&scaled_font->ref_count);
 
843
                _cairo_scaled_font_map_unlock ();
 
844
 
 
845
                cairo_scaled_font_destroy (old);
 
846
 
 
847
                return scaled_font;
 
848
            }
 
849
 
 
850
            /* the font has been put into an error status - abandon the cache */
 
851
            _cairo_hash_table_remove (font_map->hash_table, &key.hash_entry);
 
852
            scaled_font->hash_entry.hash = ZOMBIE;
 
853
        }
 
854
    }
817
855
 
818
856
    /* Otherwise create it and insert it into the hash table. */
819
857
    status = font_face->backend->scaled_font_create (font_face, font_matrix,
826
864
 
827
865
    status = _cairo_hash_table_insert (font_map->hash_table,
828
866
                                       &scaled_font->hash_entry);
 
867
    if (status == CAIRO_STATUS_SUCCESS) {
 
868
        old = font_map->mru_scaled_font;
 
869
        font_map->mru_scaled_font = scaled_font;
 
870
        _cairo_reference_count_inc (&scaled_font->ref_count);
 
871
    }
 
872
 
829
873
    _cairo_scaled_font_map_unlock ();
830
874
 
831
875
    if (status) {
837
881
        return _cairo_scaled_font_create_in_error (status);
838
882
    }
839
883
 
 
884
    cairo_scaled_font_destroy (old);
 
885
 
840
886
    return scaled_font;
841
887
}
842
888
slim_hidden_def (cairo_scaled_font_create);
1279
1325
 * @num_glyphs: pointer to number of glyphs
1280
1326
 * @clusters: pointer to array of cluster mapping information to fill, or %NULL
1281
1327
 * @num_clusters: pointer to number of clusters, or %NULL
1282
 
 * @backward: pointer to whether the text to glyphs mapping goes backward, or
1283
 
 *            %NULL
 
1328
 * @cluster_flags: pointer to location to store cluster flags corresponding to the
 
1329
 *                 output @clusters, or %NULL
1284
1330
 *
1285
1331
 * Converts UTF-8 text to an array of glyphs, optionally with cluster
1286
1332
 * mapping, that can be used to render later using @scaled_font.
1294
1340
 * after the call, the user is responsible for freeing the allocated glyph
1295
1341
 * array using cairo_glyph_free().
1296
1342
 *
1297
 
 * If @clusters is not %NULL, @num_clusters and @backward should not be %NULL,
 
1343
 * If @clusters is not %NULL, @num_clusters and @cluster_flags should not be %NULL,
1298
1344
 * and cluster mapping will be computed.
1299
1345
 * The semantics of how cluster array allocation works is similar to the glyph
1300
1346
 * array.  That is,
1316
1362
 * int num_glyphs;
1317
1363
 * cairo_text_cluster_t *clusters = NULL;
1318
1364
 * int num_clusters;
1319
 
 * cairo_bool_t backward;
 
1365
 * cairo_text_cluster_flags_t cluster_flags;
1320
1366
 *
1321
1367
 * status = cairo_scaled_font_text_to_glyphs (scaled_font,
1322
1368
 *                                            x, y,
1323
1369
 *                                            utf8, utf8_len,
1324
1370
 *                                            &amp;glyphs, &amp;num_glyphs,
1325
 
 *                                            &amp;clusters, &amp;num_clusters,
1326
 
 *                                            &amp;backward);
 
1371
 *                                            &amp;clusters, &amp;num_clusters, &amp;cluster_flags);
1327
1372
 *
1328
1373
 * if (status == CAIRO_STATUS_SUCCESS) {
1329
1374
 *     cairo_show_text_glyphs (cr,
1330
1375
 *                             utf8, utf8_len,
1331
1376
 *                             *glyphs, *num_glyphs,
1332
 
 *                             *clusters, *num_clusters,
1333
 
 *                             *backward);
 
1377
 *                             *clusters, *num_clusters, *cluster_flags);
1334
1378
 *
1335
1379
 *     cairo_glyph_free (*glyphs);
1336
1380
 *     cairo_text_cluster_free (*clusters);
1368
1412
 * cairo_text_cluster_t stack_clusters[40];
1369
1413
 * cairo_text_cluster_t *clusters = stack_clusters;
1370
1414
 * int num_clusters = sizeof (stack_clusters) / sizeof (stack_clusters[0]);
1371
 
 * cairo_bool_t backward;
 
1415
 * cairo_text_cluster_flags_t cluster_flags;
1372
1416
 *
1373
1417
 * status = cairo_scaled_font_text_to_glyphs (scaled_font,
1374
1418
 *                                            x, y,
1375
1419
 *                                            utf8, utf8_len,
1376
1420
 *                                            &amp;glyphs, &amp;num_glyphs,
1377
 
 *                                            &amp;clusters, &amp;num_clusters,
1378
 
 *                                            &amp;backward);
 
1421
 *                                            &amp;clusters, &amp;num_clusters, &amp;cluster_flags);
1379
1422
 *
1380
1423
 * if (status == CAIRO_STATUS_SUCCESS) {
1381
1424
 *     cairo_show_text_glyphs (cr,
1382
1425
 *                             utf8, utf8_len,
1383
1426
 *                             *glyphs, *num_glyphs,
1384
 
 *                             *clusters, *num_clusters,
1385
 
 *                             *backward);
 
1427
 *                             *clusters, *num_clusters, *cluster_flags);
1386
1428
 *
1387
1429
 *     if (glyphs != stack_glyphs)
1388
1430
 *         cairo_glyph_free (*glyphs);
1391
1433
 * }
1392
1434
 * </programlisting></informalexample>
1393
1435
 *
1394
 
 * For details of how (@clusters, @num_clusters, and @backward map input
 
1436
 * For details of how @clusters, @num_clusters, and @cluster_flags map input
1395
1437
 * UTF-8 text to the output glyphs see cairo_show_text_glyphs().
1396
1438
 *
1397
1439
 * The output values can be readily passed to cairo_show_text_glyphs()
1415
1457
                                  int                   *num_glyphs,
1416
1458
                                  cairo_text_cluster_t **clusters,
1417
1459
                                  int                   *num_clusters,
1418
 
                                  cairo_bool_t          *backward)
 
1460
                                  cairo_text_cluster_flags_t *cluster_flags)
1419
1461
{
1420
1462
    int i;
1421
1463
    int num_chars = 0;
1442
1484
        utf8_len = 0;
1443
1485
 
1444
1486
    /* No NULLs for non-NULLs! */
1445
 
    if ((utf8_len && utf8         == NULL) ||
1446
 
        (clusters && num_clusters == NULL) ||
1447
 
        (clusters && backward     == NULL)) {
 
1487
    if ((utf8_len && utf8          == NULL) ||
 
1488
        (clusters && num_clusters  == NULL) ||
 
1489
        (clusters && cluster_flags == NULL)) {
1448
1490
        status = CAIRO_STATUS_NULL_POINTER;
1449
1491
        goto BAIL;
1450
1492
    }
1465
1507
        num_clusters = NULL;
1466
1508
    }
1467
1509
 
1468
 
    if (backward) {
1469
 
        *backward = FALSE;
 
1510
    if (cluster_flags) {
 
1511
        *cluster_flags = FALSE;
1470
1512
    }
1471
1513
 
1472
 
    if (!clusters && backward) {
1473
 
        backward = NULL;
 
1514
    if (!clusters && cluster_flags) {
 
1515
        cluster_flags = NULL;
1474
1516
    }
1475
1517
 
1476
1518
    /* Apart from that, no negatives */
1503
1545
                                                       utf8, utf8_len,
1504
1546
                                                       glyphs, num_glyphs,
1505
1547
                                                       clusters, num_clusters,
1506
 
                                                       backward);
 
1548
                                                       cluster_flags);
1507
1549
 
1508
1550
        if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
1509
1551
 
1537
1579
                    status = _cairo_validate_text_clusters (utf8, utf8_len,
1538
1580
                                                            *glyphs, *num_glyphs,
1539
1581
                                                            *clusters, *num_clusters,
1540
 
                                                            *backward);
 
1582
                                                            *cluster_flags);
1541
1583
                }
1542
1584
            }
1543
1585
 
1736
1778
 
1737
1779
    /* Font display routine either does not exist or failed. */
1738
1780
 
1739
 
    status = CAIRO_STATUS_SUCCESS;
1740
 
 
1741
1781
    _cairo_pattern_init_solid (&white_pattern, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR);
1742
1782
 
1743
1783
    _cairo_cache_freeze (scaled_font->glyphs);
1979
2019
{
1980
2020
    cairo_status_t status;
1981
2021
    cairo_image_surface_t *a1_mask;
1982
 
    unsigned char *row, *byte_ptr, byte;
 
2022
    uint8_t *row, *byte_ptr, byte;
1983
2023
    int rows, cols, bytes_per_row;
1984
2024
    int x, y, bit;
1985
2025
    double xoff, yoff;
1999
2039
 
2000
2040
    bytes_per_row = (a1_mask->width + 7) / 8;
2001
2041
    for (y = 0, row = a1_mask->data, rows = a1_mask->height; rows; row += a1_mask->stride, rows--, y++) {
2002
 
        for (x = 0, byte_ptr = row, cols = (a1_mask->width + 7) / 8; cols; byte_ptr++, cols--) {
 
2042
        for (x = 0, byte_ptr = row, cols = bytes_per_row; cols; byte_ptr++, cols--) {
2003
2043
            byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte_ptr);
2004
2044
            for (bit = 7; bit >= 0 && x < a1_mask->width; bit--, x++) {
2005
2045
                if (byte & (1 << bit)) {