cairo_status_t _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets, cairo_scaled_font_t *scaled_font, unsigned long scaled_font_glyph_index, const char * utf8, int utf8_len, cairo_scaled_font_subsets_glyph_t *subset_glyph) { cairo_sub_font_t key, *sub_font; cairo_scaled_glyph_t *scaled_glyph; cairo_font_face_t *font_face; cairo_matrix_t identity; cairo_font_options_t font_options; cairo_scaled_font_t *unscaled_font; cairo_int_status_t status; int max_glyphs; cairo_bool_t type1_font; /* Lookup glyph in unscaled subsets */ if (subsets->type != CAIRO_SUBSETS_SCALED) { key.is_scaled = FALSE; _cairo_sub_font_init_key (&key, scaled_font); sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts, &key.base); if (sub_font != NULL) { status = _cairo_sub_font_lookup_glyph (sub_font, scaled_font_glyph_index, utf8, utf8_len, subset_glyph); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; } } /* Lookup glyph in scaled subsets */ key.is_scaled = TRUE; _cairo_sub_font_init_key (&key, scaled_font); sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts, &key.base); if (sub_font != NULL) { status = _cairo_sub_font_lookup_glyph (sub_font, scaled_font_glyph_index, utf8, utf8_len, subset_glyph); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; } /* Glyph not found. Determine whether the glyph is outline or * bitmap and add to the appropriate subset. * * glyph_index 0 (the .notdef glyph) is a special case. Some fonts * will return CAIRO_INT_STATUS_UNSUPPORTED when doing a * _scaled_glyph_lookup(_GLYPH_INFO_PATH). Type1-fallback creates * empty glyphs in this case so we can put the glyph in a unscaled * subset. */ if (scaled_font_glyph_index == 0 || _cairo_font_face_is_user (scaled_font->font_face)) { status = CAIRO_STATUS_SUCCESS; } else { _cairo_scaled_font_freeze_cache (scaled_font); status = _cairo_scaled_glyph_lookup (scaled_font, scaled_font_glyph_index, CAIRO_SCALED_GLYPH_INFO_PATH, &scaled_glyph); _cairo_scaled_font_thaw_cache (scaled_font); } if (_cairo_int_status_is_error (status)) return status; if (status == CAIRO_INT_STATUS_SUCCESS && subsets->type != CAIRO_SUBSETS_SCALED && ! _cairo_font_face_is_user (scaled_font->font_face)) { /* Path available. Add to unscaled subset. */ key.is_scaled = FALSE; _cairo_sub_font_init_key (&key, scaled_font); sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts, &key.base); if (sub_font == NULL) { font_face = cairo_scaled_font_get_font_face (scaled_font); cairo_matrix_init_identity (&identity); _cairo_font_options_init_default (&font_options); cairo_font_options_set_hint_style (&font_options, CAIRO_HINT_STYLE_NONE); cairo_font_options_set_hint_metrics (&font_options, CAIRO_HINT_METRICS_OFF); unscaled_font = cairo_scaled_font_create (font_face, &identity, &identity, &font_options); if (unlikely (unscaled_font->status)) return unscaled_font->status; subset_glyph->is_scaled = FALSE; type1_font = _cairo_type1_scaled_font_is_type1 (unscaled_font); if (subsets->type == CAIRO_SUBSETS_COMPOSITE && !type1_font) { max_glyphs = MAX_GLYPHS_PER_COMPOSITE_FONT; subset_glyph->is_composite = TRUE; } else { max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT; subset_glyph->is_composite = FALSE; } status = _cairo_sub_font_create (subsets, unscaled_font, subsets->num_sub_fonts, max_glyphs, subset_glyph->is_scaled, subset_glyph->is_composite, &sub_font); if (unlikely (status)) { cairo_scaled_font_destroy (unscaled_font); return status; } status = _cairo_hash_table_insert (subsets->unscaled_sub_fonts, &sub_font->base); if (unlikely (status)) { _cairo_sub_font_destroy (sub_font); return status; } if (!subsets->unscaled_sub_fonts_list) subsets->unscaled_sub_fonts_list = sub_font; else subsets->unscaled_sub_fonts_list_end->next = sub_font; subsets->unscaled_sub_fonts_list_end = sub_font; subsets->num_sub_fonts++; } } else { /* No path available. Add to scaled subset. */ key.is_scaled = TRUE; _cairo_sub_font_init_key (&key, scaled_font); sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts, &key.base); if (sub_font == NULL) { subset_glyph->is_scaled = TRUE; subset_glyph->is_composite = FALSE; if (subsets->type == CAIRO_SUBSETS_SCALED) max_glyphs = INT_MAX; else max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT; status = _cairo_sub_font_create (subsets, cairo_scaled_font_reference (scaled_font), subsets->num_sub_fonts, max_glyphs, subset_glyph->is_scaled, subset_glyph->is_composite, &sub_font); if (unlikely (status)) { cairo_scaled_font_destroy (scaled_font); return status; } status = _cairo_hash_table_insert (subsets->scaled_sub_fonts, &sub_font->base); if (unlikely (status)) { _cairo_sub_font_destroy (sub_font); return status; } if (!subsets->scaled_sub_fonts_list) subsets->scaled_sub_fonts_list = sub_font; else subsets->scaled_sub_fonts_list_end->next = sub_font; subsets->scaled_sub_fonts_list_end = sub_font; subsets->num_sub_fonts++; } } return _cairo_sub_font_map_glyph (sub_font, scaled_font_glyph_index, utf8, utf8_len, subset_glyph); }
static cairo_int_status_t _cairo_sub_font_lookup_glyph (cairo_sub_font_t *sub_font, unsigned long scaled_font_glyph_index, const char *utf8, int utf8_len, cairo_scaled_font_subsets_glyph_t *subset_glyph) { cairo_sub_font_glyph_t key, *sub_font_glyph; cairo_int_status_t status; _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index); sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs, &key.base); if (sub_font_glyph != NULL) { subset_glyph->font_id = sub_font->font_id; subset_glyph->subset_id = sub_font_glyph->subset_id; subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index; subset_glyph->is_scaled = sub_font->is_scaled; subset_glyph->is_composite = sub_font->is_composite; subset_glyph->x_advance = sub_font_glyph->x_advance; subset_glyph->y_advance = sub_font_glyph->y_advance; status = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph, utf8, utf8_len, &subset_glyph->utf8_is_mapped); subset_glyph->unicode = sub_font_glyph->unicode; return status; } return CAIRO_INT_STATUS_UNSUPPORTED; }
static cairo_bool_t _cairo_toy_font_face_destroy (void *abstract_face) { cairo_toy_font_face_t *font_face = abstract_face; cairo_hash_table_t *hash_table; hash_table = _cairo_toy_font_face_hash_table_lock (); /* All created objects must have been mapped in the hash table. */ assert (hash_table != NULL); if (! _cairo_reference_count_dec_and_test (&font_face->base.ref_count)) { /* somebody recreated the font whilst we waited for the lock */ _cairo_toy_font_face_hash_table_unlock (); return FALSE; } /* Font faces in SUCCESS status are guaranteed to be in the * hashtable. Font faces in an error status are removed from the * hashtable if they are found during a lookup, thus they should * only be removed if they are in the hashtable. */ if (likely (font_face->base.status == CAIRO_STATUS_SUCCESS) || _cairo_hash_table_lookup (hash_table, &font_face->base.hash_entry) == font_face) _cairo_hash_table_remove (hash_table, &font_face->base.hash_entry); _cairo_toy_font_face_hash_table_unlock (); _cairo_toy_font_face_fini (font_face); return TRUE; }
/** * _cairo_cache_lookup: * @cache: a cache * @key: the key of interest * @entry_return: pointer for return value * * Performs a lookup in @cache looking for an entry which has a key * that matches @key, (as determined by the keys_equal() function * passed to _cairo_cache_init()). * * Return value: %TRUE if there is an entry in the cache that matches * @key, (which will now be in *entry_return). %FALSE otherwise, (in * which case *entry_return will be %NULL). **/ void * _cairo_cache_lookup (cairo_cache_t *cache, cairo_cache_entry_t *key) { return _cairo_hash_table_lookup (cache->hash_table, (cairo_hash_entry_t *) key); }
static cairo_surface_t * _similar_surface_create (void *closure, cairo_content_t content, double width, double height, long uid) { struct trace *args = closure; cairo_surface_t *surface; struct scache skey, *s; if (args->observe) return cairo_surface_create_similar (args->surface, content, width, height); if (uid == 0 || surface_cache == NULL) return args->target->create_similar (args->surface, content, width, height); skey.entry.hash = uid; s = _cairo_hash_table_lookup (surface_cache, &skey.entry); if (s != NULL) { if (s->content == content && s->width == width && s->height == height) { return cairo_surface_reference (s->surface); } /* The surface has been resized, allow the original entry to expire * as it becomes inactive. */ } surface = args->target->create_similar (args->surface, content, width, height); s = malloc (sizeof (struct scache)); if (s == NULL) return surface; s->entry.hash = uid; s->content = content; s->width = width; s->height = height; s->surface = surface; if (_cairo_hash_table_insert (surface_cache, &s->entry)) { free (s); } else if (cairo_surface_set_user_data (surface, (const cairo_user_data_key_t *) &surface_cache, s, scache_remove)) { scache_remove (s); } return surface; }
/** * cairo_scaled_font_create: * @font_face: a #cairo_font_face_t * @font_matrix: font space to user space transformation matrix for the * font. In the simplest case of a N point font, this matrix is * just a scale by N, but it can also be used to shear the font * or stretch it unequally along the two axes. See * cairo_set_font_matrix(). * @ctm: user to device transformation matrix with which the font will * be used. * @options: options to use when getting metrics for the font and * rendering with it. * * Creates a #cairo_scaled_font_t object from a font face and matrices that * describe the size of the font and the environment in which it will * be used. * * Return value: a newly created #cairo_scaled_font_t. Destroy with * cairo_scaled_font_destroy() **/ cairo_scaled_font_t * cairo_scaled_font_create (cairo_font_face_t *font_face, const cairo_matrix_t *font_matrix, const cairo_matrix_t *ctm, const cairo_font_options_t *options) { cairo_status_t status; cairo_scaled_font_map_t *font_map; cairo_scaled_font_t key, *scaled_font = NULL; if (font_face->status) return (cairo_scaled_font_t *)&_cairo_scaled_font_nil; font_map = _cairo_scaled_font_map_lock (); if (font_map == NULL) goto UNWIND; _cairo_scaled_font_init_key (&key, font_face, font_matrix, ctm, options); /* Return existing scaled_font if it exists in the hash table. */ if (_cairo_hash_table_lookup (font_map->hash_table, &key.hash_entry, (cairo_hash_entry_t**) &scaled_font)) { _cairo_scaled_font_map_unlock (); return cairo_scaled_font_reference (scaled_font); } /* Otherwise create it and insert it into the hash table. */ status = font_face->backend->scaled_font_create (font_face, font_matrix, ctm, options, &scaled_font); if (status) goto UNWIND_FONT_MAP_LOCK; status = _cairo_hash_table_insert (font_map->hash_table, &scaled_font->hash_entry); if (status) goto UNWIND_SCALED_FONT_CREATE; _cairo_scaled_font_map_unlock (); return scaled_font; UNWIND_SCALED_FONT_CREATE: /* We can't call _cairo_scaled_font_destroy here since it expects * that the font has already been successfully inserted into the * hash table. */ _cairo_scaled_font_fini (scaled_font); free (scaled_font); UNWIND_FONT_MAP_LOCK: _cairo_scaled_font_map_unlock (); UNWIND: return NULL; }
/** * _cairo_toy_font_face_create: * @family: a font family name, encoded in UTF-8 * @slant: the slant for the font * @weight: the weight for the font * * Creates a font face from a triplet of family, slant, and weight. * These font faces are used in implementation of the the #cairo_t "toy" * font API. * * Return value: a newly created #cairo_font_face_t, destroy with * cairo_font_face_destroy() **/ cairo_font_face_t * _cairo_toy_font_face_create (const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight) { cairo_status_t status; cairo_toy_font_face_t key, *font_face; cairo_hash_table_t *hash_table; hash_table = _cairo_toy_font_face_hash_table_lock (); if (hash_table == NULL) goto UNWIND; _cairo_toy_font_face_init_key (&key, family, slant, weight); /* Return existing font_face if it exists in the hash table. */ if (_cairo_hash_table_lookup (hash_table, &key.base.hash_entry, (cairo_hash_entry_t **) &font_face)) { /* We increment the reference count here manually to avoid double-locking. */ font_face->base.ref_count++; _cairo_toy_font_face_hash_table_unlock (); return &font_face->base; } /* Otherwise create it and insert into hash table. */ font_face = malloc (sizeof (cairo_toy_font_face_t)); if (font_face == NULL) goto UNWIND_HASH_TABLE_LOCK; status = _cairo_toy_font_face_init (font_face, family, slant, weight); if (status) goto UNWIND_FONT_FACE_MALLOC; status = _cairo_hash_table_insert (hash_table, &font_face->base.hash_entry); if (status) goto UNWIND_FONT_FACE_INIT; _cairo_toy_font_face_hash_table_unlock (); return &font_face->base; UNWIND_FONT_FACE_INIT: UNWIND_FONT_FACE_MALLOC: free (font_face); UNWIND_HASH_TABLE_LOCK: _cairo_toy_font_face_hash_table_unlock (); UNWIND: return (cairo_font_face_t*) &_cairo_font_face_nil; }
static cairo_status_t _cairo_sub_font_lookup_glyph (cairo_sub_font_t *sub_font, unsigned long scaled_font_glyph_index, cairo_scaled_font_subsets_glyph_t *subset_glyph) { cairo_sub_font_glyph_t key, *sub_font_glyph; _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index); if (_cairo_hash_table_lookup (sub_font->sub_font_glyphs, &key.base, (cairo_hash_entry_t **) &sub_font_glyph)) { subset_glyph->font_id = sub_font->font_id; subset_glyph->subset_id = sub_font_glyph->subset_id; subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index; subset_glyph->is_scaled = sub_font->is_scaled; subset_glyph->is_composite = sub_font->is_composite; subset_glyph->x_advance = sub_font_glyph->x_advance; return CAIRO_STATUS_SUCCESS; } return CAIRO_STATUS_NULL_POINTER; }
static cairo_bool_t _cairo_sub_font_lookup_glyph (cairo_sub_font_t *sub_font, unsigned long scaled_font_glyph_index, cairo_scaled_font_subsets_glyph_t *subset_glyph) { cairo_sub_font_glyph_t key, *sub_font_glyph; _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index); if (_cairo_hash_table_lookup (sub_font->sub_font_glyphs, &key.base, (cairo_hash_entry_t **) &sub_font_glyph)) { subset_glyph->font_id = sub_font->font_id; subset_glyph->subset_id = sub_font_glyph->subset_id; subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index; subset_glyph->is_scaled = sub_font->is_scaled; subset_glyph->is_composite = sub_font->is_composite; subset_glyph->x_advance = sub_font_glyph->x_advance; return TRUE; } return FALSE; }
static cairo_status_t _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font, unsigned long scaled_font_glyph_index, const char *utf8, int utf8_len, cairo_scaled_font_subsets_glyph_t *subset_glyph) { cairo_sub_font_glyph_t key, *sub_font_glyph; cairo_status_t status; _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index); sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs, &key.base); if (sub_font_glyph == NULL) { cairo_scaled_glyph_t *scaled_glyph; if (sub_font->num_glyphs_in_current_subset == sub_font->max_glyphs_per_subset) { cairo_scaled_font_subsets_glyph_t tmp_subset_glyph; sub_font->current_subset++; sub_font->num_glyphs_in_current_subset = 0; /* Reserve first glyph in subset for the .notdef glyph * except for Type 3 fonts */ if (! _cairo_font_face_is_user (sub_font->scaled_font->font_face)) { status = _cairo_sub_font_map_glyph (sub_font, 0, NULL, -1, &tmp_subset_glyph); if (unlikely (status)) return status; } } _cairo_scaled_font_freeze_cache (sub_font->scaled_font); status = _cairo_scaled_glyph_lookup (sub_font->scaled_font, scaled_font_glyph_index, CAIRO_SCALED_GLYPH_INFO_METRICS, &scaled_glyph); assert (status != CAIRO_INT_STATUS_UNSUPPORTED); if (unlikely (status)) { _cairo_scaled_font_thaw_cache (sub_font->scaled_font); return status; } sub_font_glyph = _cairo_sub_font_glyph_create (scaled_font_glyph_index, sub_font->current_subset, sub_font->num_glyphs_in_current_subset, scaled_glyph->metrics.x_advance, scaled_glyph->metrics.y_advance); _cairo_scaled_font_thaw_cache (sub_font->scaled_font); if (unlikely (sub_font_glyph == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = _cairo_sub_font_glyph_lookup_unicode (sub_font_glyph, sub_font->scaled_font, scaled_font_glyph_index); if (unlikely (status)) { _cairo_sub_font_glyph_destroy (sub_font_glyph); return status; } status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base); if (unlikely (status)) { _cairo_sub_font_glyph_destroy (sub_font_glyph); return status; } sub_font->num_glyphs_in_current_subset++; if (sub_font->is_scaled) { if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_scaled_subset_used) sub_font->parent->max_glyphs_per_scaled_subset_used = sub_font->num_glyphs_in_current_subset; } else { if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_unscaled_subset_used) sub_font->parent->max_glyphs_per_unscaled_subset_used = sub_font->num_glyphs_in_current_subset; } } subset_glyph->font_id = sub_font->font_id; subset_glyph->subset_id = sub_font_glyph->subset_id; subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index; subset_glyph->is_scaled = sub_font->is_scaled; subset_glyph->is_composite = sub_font->is_composite; subset_glyph->x_advance = sub_font_glyph->x_advance; subset_glyph->y_advance = sub_font_glyph->y_advance; status = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph, utf8, utf8_len, &subset_glyph->utf8_is_mapped); subset_glyph->unicode = sub_font_glyph->unicode; return status; }
static cairo_status_t _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font, unsigned long scaled_font_glyph_index, const char *text_utf8, int text_utf8_len, cairo_scaled_font_subsets_glyph_t *subset_glyph) { cairo_sub_font_glyph_t key, *sub_font_glyph; cairo_status_t status; _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index); sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs, &key.base); if (sub_font_glyph == NULL) { uint32_t font_unicode; char *font_utf8; int font_utf8_len; cairo_bool_t is_latin; int latin_character; status = _cairo_sub_font_glyph_lookup_unicode (sub_font->scaled_font, scaled_font_glyph_index, &font_unicode, &font_utf8, &font_utf8_len); if (unlikely(status)) return status; /* If the supplied utf8 is a valid single character, use it * instead of the font lookup */ if (text_utf8 != NULL && text_utf8_len > 0) { uint32_t *ucs4; int ucs4_len; status = _cairo_utf8_to_ucs4 (text_utf8, text_utf8_len, &ucs4, &ucs4_len); if (status == CAIRO_STATUS_SUCCESS) { if (ucs4_len == 1) { font_unicode = ucs4[0]; free (font_utf8); font_utf8 = malloc (text_utf8_len + 1); if (font_utf8 == NULL) { free (ucs4); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } memcpy (font_utf8, text_utf8, text_utf8_len); font_utf8[text_utf8_len] = 0; font_utf8_len = text_utf8_len; } free (ucs4); } } /* If glyph is in the winansi encoding and font is not a user * font, put glyph in the latin subset. If glyph is .notdef * the latin subset is preferred but only if the latin subset * already contains at least one glyph. We don't want to * create a separate subset just for the .notdef glyph. */ is_latin = FALSE; latin_character = -1; if (sub_font->use_latin_subset && (! _cairo_font_face_is_user (sub_font->scaled_font->font_face))) { latin_character = _cairo_unicode_to_winansi (font_unicode); if (latin_character > 0 || (latin_character == 0 && sub_font->num_glyphs_in_latin_subset > 0)) { if (!sub_font->latin_char_map[latin_character]) { sub_font->latin_char_map[latin_character] = TRUE; is_latin = TRUE; } } } status = _cairo_sub_font_add_glyph (sub_font, scaled_font_glyph_index, is_latin, latin_character, font_unicode, font_utf8, font_utf8_len, &sub_font_glyph); if (unlikely(status)) return status; } subset_glyph->font_id = sub_font->font_id; subset_glyph->subset_id = sub_font_glyph->subset_id; if (sub_font_glyph->is_latin) subset_glyph->subset_glyph_index = sub_font_glyph->latin_character; else subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index; subset_glyph->is_scaled = sub_font->is_scaled; subset_glyph->is_composite = sub_font->is_composite; subset_glyph->is_latin = sub_font_glyph->is_latin; subset_glyph->x_advance = sub_font_glyph->x_advance; subset_glyph->y_advance = sub_font_glyph->y_advance; status = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph, text_utf8, text_utf8_len, &subset_glyph->utf8_is_mapped); subset_glyph->unicode = sub_font_glyph->unicode; return status; }
cairo_int_status_t _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset) { unsigned int i; cairo_hash_table_t *names; cairo_string_entry_t key, *entry; char buf[30]; char *utf8; uint16_t *utf16; int utf16_len; cairo_status_t status = CAIRO_STATUS_SUCCESS; names = _cairo_hash_table_create (_cairo_string_equal); if (unlikely (names == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); subset->glyph_names = calloc (subset->num_glyphs, sizeof (char *)); if (unlikely (subset->glyph_names == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP_HASH; } i = 0; if (! subset->is_scaled) { subset->glyph_names[0] = strdup (".notdef"); if (unlikely (subset->glyph_names[0] == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP_HASH; } status = create_string_entry (subset->glyph_names[0], &entry); if (unlikely (status)) goto CLEANUP_HASH; status = _cairo_hash_table_insert (names, &entry->base); if (unlikely (status)) { free (entry); goto CLEANUP_HASH; } i++; } for (; i < subset->num_glyphs; i++) { utf8 = subset->utf8[i]; utf16 = NULL; utf16_len = 0; if (utf8 && *utf8) { status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len); if (unlikely (status)) goto CLEANUP_HASH; } if (utf16_len == 1) { int ch = _cairo_unicode_to_winansi (utf16[0]); if (ch > 0 && _cairo_winansi_to_glyphname (ch)) strncpy (buf, _cairo_winansi_to_glyphname (ch), sizeof (buf)); else snprintf (buf, sizeof (buf), "uni%04X", (int) utf16[0]); _cairo_string_init_key (&key, buf); entry = _cairo_hash_table_lookup (names, &key.base); if (entry != NULL) snprintf (buf, sizeof (buf), "g%d", i); } else { snprintf (buf, sizeof (buf), "g%d", i); } free (utf16); subset->glyph_names[i] = strdup (buf); if (unlikely (subset->glyph_names[i] == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP_HASH; } status = create_string_entry (subset->glyph_names[i], &entry); if (unlikely (status)) goto CLEANUP_HASH; status = _cairo_hash_table_insert (names, &entry->base); if (unlikely (status)) { free (entry); goto CLEANUP_HASH; } } CLEANUP_HASH: _cairo_hash_table_foreach (names, _pluck_entry, names); _cairo_hash_table_destroy (names); if (likely (status == CAIRO_STATUS_SUCCESS)) return CAIRO_STATUS_SUCCESS; if (subset->glyph_names != NULL) { for (i = 0; i < subset->num_glyphs; i++) { free (subset->glyph_names[i]); } free (subset->glyph_names); subset->glyph_names = NULL; } return status; }
cairo_private cairo_status_t _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets, cairo_scaled_font_t *scaled_font, unsigned long scaled_font_glyph_index, cairo_scaled_font_subsets_glyph_t *subset_glyph) { cairo_sub_font_t key, *sub_font; cairo_scaled_glyph_t *scaled_glyph; cairo_font_face_t *font_face; cairo_matrix_t identity; cairo_font_options_t font_options; cairo_scaled_font_t *unscaled_font; cairo_status_t status; int max_glyphs; cairo_bool_t type1_font; /* Lookup glyph in unscaled subsets */ if (subsets->type != CAIRO_SUBSETS_SCALED) { key.is_scaled = FALSE; _cairo_sub_font_init_key (&key, scaled_font); if (_cairo_hash_table_lookup (subsets->unscaled_sub_fonts, &key.base, (cairo_hash_entry_t **) &sub_font)) { status = _cairo_sub_font_lookup_glyph (sub_font, scaled_font_glyph_index, subset_glyph); if (status == CAIRO_STATUS_SUCCESS) return CAIRO_STATUS_SUCCESS; } } /* Lookup glyph in scaled subsets */ key.is_scaled = TRUE; _cairo_sub_font_init_key (&key, scaled_font); if (_cairo_hash_table_lookup (subsets->scaled_sub_fonts, &key.base, (cairo_hash_entry_t **) &sub_font)) { status = _cairo_sub_font_lookup_glyph (sub_font, scaled_font_glyph_index, subset_glyph); if (status == CAIRO_STATUS_SUCCESS) return CAIRO_STATUS_SUCCESS; } /* Glyph not found. Determine whether the glyph is outline or * bitmap and add to the appropriate subset */ status = _cairo_scaled_glyph_lookup (scaled_font, scaled_font_glyph_index, CAIRO_SCALED_GLYPH_INFO_PATH, &scaled_glyph); if (status && status != CAIRO_INT_STATUS_UNSUPPORTED) return status; if (status == 0 && subsets->type != CAIRO_SUBSETS_SCALED) { /* Path available. Add to unscaled subset. */ key.is_scaled = FALSE; _cairo_sub_font_init_key (&key, scaled_font); if (! _cairo_hash_table_lookup (subsets->unscaled_sub_fonts, &key.base, (cairo_hash_entry_t **) &sub_font)) { font_face = cairo_scaled_font_get_font_face (scaled_font); cairo_matrix_init_identity (&identity); _cairo_font_options_init_default (&font_options); cairo_font_options_set_hint_style (&font_options, CAIRO_HINT_STYLE_NONE); cairo_font_options_set_hint_metrics (&font_options, CAIRO_HINT_METRICS_OFF); unscaled_font = cairo_scaled_font_create (font_face, &identity, &identity, &font_options); if (unscaled_font->status) return unscaled_font->status; subset_glyph->is_scaled = FALSE; type1_font = FALSE; #if CAIRO_HAS_FT_FONT type1_font = _cairo_type1_scaled_font_is_type1 (unscaled_font); #endif if (subsets->type == CAIRO_SUBSETS_COMPOSITE && !type1_font) { max_glyphs = MAX_GLYPHS_PER_COMPOSITE_FONT; subset_glyph->is_composite = TRUE; } else { max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT; subset_glyph->is_composite = FALSE; } sub_font = _cairo_sub_font_create (subsets, unscaled_font, subsets->num_sub_fonts++, max_glyphs, subset_glyph->is_scaled, subset_glyph->is_composite); if (sub_font == NULL) { cairo_scaled_font_destroy (unscaled_font); return CAIRO_STATUS_NO_MEMORY; } status = _cairo_hash_table_insert (subsets->unscaled_sub_fonts, &sub_font->base); if (status) { _cairo_sub_font_destroy (sub_font); return status; } } } else { /* No path available. Add to scaled subset. */ key.is_scaled = TRUE; _cairo_sub_font_init_key (&key, scaled_font); if (! _cairo_hash_table_lookup (subsets->scaled_sub_fonts, &key.base, (cairo_hash_entry_t **) &sub_font)) { subset_glyph->is_scaled = TRUE; subset_glyph->is_composite = FALSE; if (subsets->type == CAIRO_SUBSETS_SCALED) max_glyphs = INT_MAX; else max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT; sub_font = _cairo_sub_font_create (subsets, cairo_scaled_font_reference (scaled_font), subsets->num_sub_fonts++, max_glyphs, subset_glyph->is_scaled, subset_glyph->is_composite); if (sub_font == NULL) { cairo_scaled_font_destroy (scaled_font); return CAIRO_STATUS_NO_MEMORY; } status = _cairo_hash_table_insert (subsets->scaled_sub_fonts, &sub_font->base); if (status) { _cairo_sub_font_destroy (sub_font); return status; } } } return _cairo_sub_font_map_glyph (sub_font, scaled_font_glyph_index, subset_glyph); }
static cairo_status_t _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font, unsigned long scaled_font_glyph_index, cairo_scaled_font_subsets_glyph_t *subset_glyph) { cairo_sub_font_glyph_t key, *sub_font_glyph; cairo_status_t status; cairo_scaled_glyph_t *scaled_glyph; _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index); if (! _cairo_hash_table_lookup (sub_font->sub_font_glyphs, &key.base, (cairo_hash_entry_t **) &sub_font_glyph)) { if (sub_font->num_glyphs_in_current_subset == sub_font->max_glyphs_per_subset) { sub_font->current_subset++; sub_font->num_glyphs_in_current_subset = 0; if (sub_font->parent->type != CAIRO_SUBSETS_SCALED) { /* Reserve first glyph in subset for the .notdef glyph */ sub_font->num_glyphs_in_current_subset++; } } status = _cairo_scaled_glyph_lookup (sub_font->scaled_font, scaled_font_glyph_index, CAIRO_SCALED_GLYPH_INFO_METRICS, &scaled_glyph); if (status) return status; sub_font_glyph = _cairo_sub_font_glyph_create (scaled_font_glyph_index, sub_font->current_subset, sub_font->num_glyphs_in_current_subset++, scaled_glyph->metrics.x_advance); if (sub_font_glyph == NULL) return CAIRO_STATUS_NO_MEMORY; if (sub_font->is_scaled) { if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_scaled_subset_used) sub_font->parent->max_glyphs_per_scaled_subset_used = sub_font->num_glyphs_in_current_subset; } else { if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_unscaled_subset_used) sub_font->parent->max_glyphs_per_unscaled_subset_used = sub_font->num_glyphs_in_current_subset; } status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base); if (status) { _cairo_sub_font_glyph_destroy (sub_font_glyph); return status; } } subset_glyph->font_id = sub_font->font_id; subset_glyph->subset_id = sub_font_glyph->subset_id; subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index; subset_glyph->is_scaled = sub_font->is_scaled; subset_glyph->is_composite = sub_font->is_composite; subset_glyph->x_advance = sub_font_glyph->x_advance; return CAIRO_STATUS_SUCCESS; }
/** * cairo_toy_font_face_create: * @family: a font family name, encoded in UTF-8 * @slant: the slant for the font * @weight: the weight for the font * * Creates a font face from a triplet of family, slant, and weight. * These font faces are used in implementation of the the #cairo_t "toy" * font API. * * If @family is the zero-length string "", the platform-specific default * family is assumed. The default family then can be queried using * cairo_toy_font_face_get_family(). * * The cairo_select_font_face() function uses this to create font faces. * See that function for limitations and other details of toy font faces. * * Return value: a newly created #cairo_font_face_t. Free with * cairo_font_face_destroy() when you are done using it. * * Since: 1.8 **/ cairo_font_face_t * cairo_toy_font_face_create (const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight) { cairo_status_t status; cairo_toy_font_face_t key, *font_face; cairo_hash_table_t *hash_table; if (family == NULL) return (cairo_font_face_t*) &_cairo_font_face_null_pointer; /* Make sure we've got valid UTF-8 for the family */ status = _cairo_utf8_to_ucs4 (family, -1, NULL, NULL); if (unlikely (status)) { if (status == CAIRO_STATUS_INVALID_STRING) return (cairo_font_face_t*) &_cairo_font_face_invalid_string; return (cairo_font_face_t*) &_cairo_font_face_nil; } switch (slant) { case CAIRO_FONT_SLANT_NORMAL: case CAIRO_FONT_SLANT_ITALIC: case CAIRO_FONT_SLANT_OBLIQUE: break; default: return (cairo_font_face_t*) &_cairo_font_face_invalid_slant; } switch (weight) { case CAIRO_FONT_WEIGHT_NORMAL: case CAIRO_FONT_WEIGHT_BOLD: break; default: return (cairo_font_face_t*) &_cairo_font_face_invalid_weight; } if (*family == '\0') family = CAIRO_FONT_FAMILY_DEFAULT; hash_table = _cairo_toy_font_face_hash_table_lock (); if (unlikely (hash_table == NULL)) goto UNWIND; _cairo_toy_font_face_init_key (&key, family, slant, weight); /* Return existing font_face if it exists in the hash table. */ font_face = _cairo_hash_table_lookup (hash_table, &key.base.hash_entry); if (font_face != NULL) { if (font_face->base.status == CAIRO_STATUS_SUCCESS) { cairo_font_face_reference (&font_face->base); _cairo_toy_font_face_hash_table_unlock (); return &font_face->base; } /* remove the bad font from the hash table */ _cairo_hash_table_remove (hash_table, &font_face->base.hash_entry); } /* Otherwise create it and insert into hash table. */ font_face = _cairo_malloc (sizeof (cairo_toy_font_face_t)); if (unlikely (font_face == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto UNWIND_HASH_TABLE_LOCK; } status = _cairo_toy_font_face_init (font_face, family, slant, weight); if (unlikely (status)) goto UNWIND_FONT_FACE_MALLOC; assert (font_face->base.hash_entry.hash == key.base.hash_entry.hash); status = _cairo_hash_table_insert (hash_table, &font_face->base.hash_entry); if (unlikely (status)) goto UNWIND_FONT_FACE_INIT; _cairo_toy_font_face_hash_table_unlock (); return &font_face->base; UNWIND_FONT_FACE_INIT: _cairo_toy_font_face_fini (font_face); UNWIND_FONT_FACE_MALLOC: free (font_face); UNWIND_HASH_TABLE_LOCK: _cairo_toy_font_face_hash_table_unlock (); UNWIND: return (cairo_font_face_t*) &_cairo_font_face_nil; }
/** * cairo_toy_font_face_create: * @family: a font family name, encoded in UTF-8 * @slant: the slant for the font * @weight: the weight for the font * * Creates a font face from a triplet of family, slant, and weight. * These font faces are used in implementation of the the #cairo_t "toy" * font API. * * If @family is the zero-length string "", the platform-specific default * family is assumed. The default family then can be queried using * cairo_toy_font_face_get_family(). * * The cairo_select_font_face() function uses this to create font faces. * See that function for limitations of toy font faces. * * Return value: a newly created #cairo_font_face_t. Free with * cairo_font_face_destroy() when you are done using it. * * Since: 1.8 **/ cairo_font_face_t * cairo_toy_font_face_create (const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight) { cairo_status_t status; cairo_toy_font_face_t key, *font_face; cairo_hash_table_t *hash_table; if (family == NULL) return (cairo_font_face_t*) &_cairo_font_face_null_pointer; /* Make sure we've got valid UTF-8 for the family */ status = _cairo_utf8_to_ucs4 (family, -1, NULL, NULL); if (status == CAIRO_STATUS_INVALID_STRING) return (cairo_font_face_t*) &_cairo_font_face_invalid_string; else if (status) return (cairo_font_face_t*) &_cairo_font_face_nil; switch (slant) { case CAIRO_FONT_SLANT_NORMAL: case CAIRO_FONT_SLANT_ITALIC: case CAIRO_FONT_SLANT_OBLIQUE: break; default: return (cairo_font_face_t*) &_cairo_font_face_invalid_slant; } switch (weight) { case CAIRO_FONT_WEIGHT_NORMAL: case CAIRO_FONT_WEIGHT_BOLD: break; default: return (cairo_font_face_t*) &_cairo_font_face_invalid_weight; } if (*family == '\0') family = CAIRO_FONT_FAMILY_DEFAULT; hash_table = _cairo_toy_font_face_hash_table_lock (); if (hash_table == NULL) goto UNWIND; _cairo_toy_font_face_init_key (&key, family, slant, weight); /* Return existing font_face if it exists in the hash table. */ if (_cairo_hash_table_lookup (hash_table, &key.base.hash_entry, (cairo_hash_entry_t **) &font_face)) { if (! font_face->base.status) { /* We increment the reference count here manually to avoid double-locking. */ _cairo_reference_count_inc (&font_face->base.ref_count); _cairo_toy_font_face_hash_table_unlock (); return &font_face->base; } /* remove the bad font from the hash table */ _cairo_hash_table_remove (hash_table, &key.base.hash_entry); font_face->base.hash_entry.hash = 0; } /* Otherwise create it and insert into hash table. */ //+EAWebKitChange //11/10/2011 font_face = cairo_malloc (sizeof (cairo_toy_font_face_t)); //-EAWebKitChange if (font_face == NULL) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto UNWIND_HASH_TABLE_LOCK; } status = _cairo_toy_font_face_init (font_face, family, slant, weight); if (status) goto UNWIND_FONT_FACE_MALLOC; status = _cairo_hash_table_insert (hash_table, &font_face->base.hash_entry); if (status) goto UNWIND_FONT_FACE_INIT; _cairo_toy_font_face_hash_table_unlock (); return &font_face->base; UNWIND_FONT_FACE_INIT: _cairo_toy_font_face_fini (font_face); UNWIND_FONT_FACE_MALLOC: //+EAWebKitChange //11/10/2011 cairo_free (font_face); //-EAWebKitChange UNWIND_HASH_TABLE_LOCK: _cairo_toy_font_face_hash_table_unlock (); UNWIND: return (cairo_font_face_t*) &_cairo_font_face_nil; }
cairo_int_status_t _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset) { const cairo_scaled_font_backend_t *backend; unsigned int i; cairo_status_t status; cairo_hash_table_t *names; cairo_string_entry_t key, *entry; char buf[30]; if (subset->to_unicode == NULL) return CAIRO_INT_STATUS_UNSUPPORTED; status = _cairo_truetype_create_glyph_to_unicode_map (subset); if (status) { if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; backend = subset->scaled_font->backend; if (backend->map_glyphs_to_unicode == NULL) return CAIRO_INT_STATUS_UNSUPPORTED; status = backend->map_glyphs_to_unicode (subset->scaled_font, subset); if (status) return status; } names = _cairo_hash_table_create (_cairo_string_equal); if (names == NULL) return _cairo_error (CAIRO_STATUS_NO_MEMORY); subset->glyph_names = calloc (subset->num_glyphs, sizeof (char *)); if (subset->glyph_names == NULL) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP_HASH; } subset->glyph_names[0] = strdup (".notdef"); if (subset->glyph_names[0] == NULL) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP_HASH; } status = create_string_entry (subset->glyph_names[0], &entry); if (status) goto CLEANUP_HASH; status = _cairo_hash_table_insert (names, &entry->base); if (status) { free (entry); goto CLEANUP_HASH; } for (i = 1; i < subset->num_glyphs; i++) { if (subset->to_unicode[i] <= 0xffff) { snprintf (buf, sizeof(buf), "uni%04X", (unsigned int)(subset->to_unicode[i])); _cairo_string_init_key (&key, buf); if (_cairo_hash_table_lookup (names, &key.base, (cairo_hash_entry_t **) &entry)) { snprintf (buf, sizeof(buf), "g%d", i); } } else { snprintf (buf, sizeof(buf), "g%d", i); } subset->glyph_names[i] = strdup (buf); if (subset->glyph_names[i] == NULL) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP_HASH; } status = create_string_entry (subset->glyph_names[i], &entry); if (status) goto CLEANUP_HASH; status = _cairo_hash_table_insert (names, &entry->base); if (status) { free (entry); goto CLEANUP_HASH; } } CLEANUP_HASH: while (1) { entry = _cairo_hash_table_random_entry (names, NULL); if (entry == NULL) break; _cairo_hash_table_remove (names, (cairo_hash_entry_t *) entry); free (entry); } _cairo_hash_table_destroy (names); if (status == CAIRO_STATUS_SUCCESS) return CAIRO_STATUS_SUCCESS; if (subset->glyph_names != NULL) { for (i = 0; i < subset->num_glyphs; i++) { if (subset->glyph_names[i] != NULL) free (subset->glyph_names[i]); } free (subset->glyph_names); subset->glyph_names = NULL; } return status; }